Cannot call a method from the same file - python

I have the following code:
def a():
response = rannum(14)
print("Number: " + response)
def rannums(x):
random(x)
it is saying that the object is not callable and I am having a hard time figuring out how to get this to work

rannums calls random, which isn't defined anywhere. a calls rannum, which isn't defined anywhere. Neither a nor rannums are called from anywhere.

Following your comment (" I am basically trying to make a method that will return back a random number with the length of the argument (x)"):
This is copy and paste from ipython interactive shell – you have to retype, if you want to use it
In [1]: from random import choices; from string import digits
In [2]: def get_random_number_with_length(length):
...: return int(''.join(choices(digits, k=length)))
...:
In [3]: get_random_number_with_length(13)
Out[3]: 8677100367579
or maybe better:
In [1]: from random import randint
In [2]: def get_random_number_with_length(length):
...: return randint(10**(length-1), (10**length) -1)
...:
In [3]: get_random_number_with_length(3)
Out[3]: 806
and your error is that you are calling the module random and not the function random.random(x), or do from random import random.

Related

Mock function use two times/same name

I have a function to test that calls the same function twice, but this function returns two different data. I need to create a mock for the first variable and then for the second, I have a solution but it doesn't work in some cases. I want to be able to mock the api_result_first variable and the api_result_second variable which uses api_call().
Do you have an idea?
My code :
import pandas as pd
import time
import random
def api_call():
time.sleep(2)
return random.randint(0,9)
def slow_function():
api_result_first = api_call()
api_result_second = api_call()
result = api_result_first + api_result_second
return result
My Pystest :
from a import *
import pytest
# https://changhsinlee.com/pytest-mock/
def test_aa(mocker):
mocker.patch("a.api_call", return_value="ok")
value = slow_function()
assert isinstance(value, int)
Use side_effects to provide a sequence of return values to use.
def test_aa(mocker):
mocker.patch("a.api_call", side_effects=[3, 5])
value = slow_function()
assert value == 8

How to get "name" from module when using "import module as name"

I can't seem to find where the actual name that a module has been bound to is stored. For example:
import re as my_re
print my_re.__name__ # Output is "re," not "my_re"
I would like to be able to get the name that I imported the module as rather than the actual name of the module.
My use case is that I have a function that takes a function object as an argument and needs to be able to determine what name it is bound to. Here is a more thorough example:
import module as my_module
def my_func(in_func):
print in_func.__bound-name__ # Or something to this effect
my_func(my_module.function1) # Should print "my_module.function1"
I would pass the module name as string and then use globals() to fetch the module for use within the function. Suppose you pass 'np' to the function, then globals()['np'] will return the function.
In [22]: import numpy as np
In [23]: def demo(A):
...: a = globals()[A]
...: print(a.array([i for i in range(10)]))
...:
In [24]: demo('np')
[0 1 2 3 4 5 6 7 8 9]
There is no way to do exactly what you want because string my_re is not stored anywhere, it is only a name of a variable. PEP221 which proposed the syntax for import ... as statement explains that the following lines are equal:
import re as my_re
and
import re
my_re = re
del re

How to handle a huge collection of functions in Python 2.7

So I am working on this existing code base which has about 150 or so functions as time series
I wanted to store them in a class in order to prevent namespace pollution.
This is what exists
import some.module
def func1(start_date, end_date):
some code here
return time_series
def func2(start_date, end_date):
some code here
return time_series
.
.
.
def func150(start_date, end_date):
some code here
return time_series
Each one of these functions is a unique name without any pattern. I tired to put them in a class
def function_builder(some_data):
def f(start_date, end_date):
some_code_here()
return series
return f
class TimeSeries():
func1 = function_builder(some_data)
func2 = function_builder(some_other_data)
.
.
.
func150 = function_builder(some_other_other_data)
My hope was that this would lead to me simply being able to import the time series and use it like
from some.location import TimeSeries as ts
#Actual code use
data = ts.func1(start_date, end_date)
But this approach throws the following error
TypeError: unbound method f() must be called with TimeSeries instance as first argument (got date instead)
please advise on how I should proceed with a huge collection of functions. I am new to programming and I want to do this correctly.
You're probably better off creating a submodule rather than a class with multiple functions. However, if you really want to do it the way you described, you need to use static methods instead of methods:
class TimeSeries():
func1 = staticmethod(function_builder(some_data))
func2 = staticmethod(function_builder(some_other_data))
# ...
Alternately, because you already have function_builder,
def function_builder(some_data):
def f(start_date, end_date):
some_code_here()
return series
return staticmethod(f)
class TimeSeries():
func1 = function_builder(some_data)
func2 = function_builder(some_other_data)
# ...
The staticmethod function takes a function and returns a static method-y version of it. Thus, it can also be used as a function decorator.
You can (should?) programatically generate your time series functions if your inputs to function_builder can be generated algorithmically. You can use __setattr__ or update __dict__ to add your functions to a submodule (or object in this module, but that's less elegant, IMHO).
I think what you really should do is separate your functions out into separate modules if you are trying to prevent name-space pollution. However, you could just use a SimpleNamespace:
In [1]: def func1(a, b):
...: return a + b
...: def func2(a, b, c):
...: return a*b*c
...: def func3(x):
...: return 2**x
...:
In [2]: from types import SimpleNamespace
In [3]: group1 = SimpleNamespace(func1=func1, func2=func2, func3=func3)
And now you've conveniently organized your name-spaces:
In [7]: group1.func1(1,2)
Out[7]: 3
In [8]: group1.func2(1, 2, 3)
Out[8]: 6
In [9]: group1.func3(8)
Out[9]: 256
Although, they will still be under the module's namespace if you do a simple import yourmodule. Even though SimpleNamespace is essentially a class, equivalent to the following:
class SimpleNamespace:
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def __repr__(self):
keys = sorted(self.__dict__)
items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
return "{}({})".format(type(self).__name__, ", ".join(items))
def __eq__(self, other):
return self.__dict__ == other.__dict__

How to get a variable from an external function

How, if possible, would I be able to bring in a variable from an external function. Take this code
# HttpThing.py
import requests
def httpThing(someurl):
x = requests.get(someurl)
In another file I have
from httpThing.py import httpThing
httpThing(www.url.com)
print(x)
How would I be able to get the last print function to print the response to the query.
you return that value from the function like this:
# HttpThing.py
import requests
def httpThing(someurl):
x = requests.get(someurl)
return x
then use it like this:
from httpThing import httpThing
x = httpThing(www.url.com)
print(x)
NOTE: the variable that you return dosen't have to be same as the variable where you call that function for printing it. it could be named anything.

Asserting successive calls to a mock method

Mock has a helpful assert_called_with() method. However, as far as I understand this only checks the last call to a method.
If I have code that calls the mocked method 3 times successively, each time with different parameters, how can I assert these 3 calls with their specific parameters?
assert_has_calls is another approach to this problem.
From the docs:
assert_has_calls (calls, any_order=False)
assert the mock has been
called with the specified calls. The mock_calls list is checked for
the calls.
If any_order is False (the default) then the calls must be sequential.
There can be extra calls before or after the specified calls.
If any_order is True then the calls can be in any order, but they must
all appear in mock_calls.
Example:
>>> from unittest.mock import call, Mock
>>> mock = Mock(return_value=None)
>>> mock(1)
>>> mock(2)
>>> mock(3)
>>> mock(4)
>>> calls = [call(2), call(3)]
>>> mock.assert_has_calls(calls)
>>> calls = [call(4), call(2), call(3)]
>>> mock.assert_has_calls(calls, any_order=True)
Source: https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.assert_has_calls
Usually, I don't care about the order of the calls, only that they happened. In that case, I combine assert_any_call with an assertion about call_count.
>>> import mock
>>> m = mock.Mock()
>>> m(1)
<Mock name='mock()' id='37578160'>
>>> m(2)
<Mock name='mock()' id='37578160'>
>>> m(3)
<Mock name='mock()' id='37578160'>
>>> m.assert_any_call(1)
>>> m.assert_any_call(2)
>>> m.assert_any_call(3)
>>> assert 3 == m.call_count
>>> m.assert_any_call(4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "[python path]\lib\site-packages\mock.py", line 891, in assert_any_call
'%s call not found' % expected_string
AssertionError: mock(4) call not found
I find doing it this way to be easier to read and understand than a large list of calls passed into a single method.
If you do care about order or you expect multiple identical calls, assert_has_calls might be more appropriate.
Edit
Since I posted this answer, I've rethought my approach to testing in general. I think it's worth mentioning that if your test is getting this complicated, you may be testing inappropriately or have a design problem. Mocks are designed for testing inter-object communication in an object oriented design. If your design is not objected oriented (as in more procedural or functional), the mock may be totally inappropriate. You may also have too much going on inside the method, or you might be testing internal details that are best left unmocked. I developed the strategy mentioned in this method when my code was not very object oriented, and I believe I was also testing internal details that would have been best left unmocked.
You can use the Mock.call_args_list attribute to compare parameters to previous method calls. That in conjunction with Mock.call_count attribute should give you full control.
I always have to look this one up time and time again, so here is my answer.
Asserting multiple method calls on different objects of the same class
Suppose we have a heavy duty class (which we want to mock):
In [1]: class HeavyDuty(object):
...: def __init__(self):
...: import time
...: time.sleep(2) # <- Spends a lot of time here
...:
...: def do_work(self, arg1, arg2):
...: print("Called with %r and %r" % (arg1, arg2))
...:
here is some code that uses two instances of the HeavyDuty class:
In [2]: def heavy_work():
...: hd1 = HeavyDuty()
...: hd1.do_work(13, 17)
...: hd2 = HeavyDuty()
...: hd2.do_work(23, 29)
...:
Now, here is a test case for the heavy_work function:
In [3]: from unittest.mock import patch, call
...: def test_heavy_work():
...: expected_calls = [call.do_work(13, 17),call.do_work(23, 29)]
...:
...: with patch('__main__.HeavyDuty') as MockHeavyDuty:
...: heavy_work()
...: MockHeavyDuty.return_value.assert_has_calls(expected_calls)
...:
We are mocking the HeavyDuty class with MockHeavyDuty. To assert method calls coming from every HeavyDuty instance we have to refer to MockHeavyDuty.return_value.assert_has_calls, instead of MockHeavyDuty.assert_has_calls. In addition, in the list of expected_calls we have to specify which method name we are interested in asserting calls for. So our list is made of calls to call.do_work, as opposed to simply call.
Exercising the test case shows us it is successful:
In [4]: print(test_heavy_work())
None
If we modify the heavy_work function, the test fails and produces a helpful error message:
In [5]: def heavy_work():
...: hd1 = HeavyDuty()
...: hd1.do_work(113, 117) # <- call args are different
...: hd2 = HeavyDuty()
...: hd2.do_work(123, 129) # <- call args are different
...:
In [6]: print(test_heavy_work())
---------------------------------------------------------------------------
(traceback omitted for clarity)
AssertionError: Calls not found.
Expected: [call.do_work(13, 17), call.do_work(23, 29)]
Actual: [call.do_work(113, 117), call.do_work(123, 129)]
Asserting multiple calls to a function
To contrast with the above, here is an example that shows how to mock multiple calls to a function:
In [7]: def work_function(arg1, arg2):
...: print("Called with args %r and %r" % (arg1, arg2))
In [8]: from unittest.mock import patch, call
...: def test_work_function():
...: expected_calls = [call(13, 17), call(23, 29)]
...: with patch('__main__.work_function') as mock_work_function:
...: work_function(13, 17)
...: work_function(23, 29)
...: mock_work_function.assert_has_calls(expected_calls)
...:
In [9]: print(test_work_function())
None
There are two main differences. The first one is that when mocking a function we setup our expected calls using call, instead of using call.some_method. The second one is that we call assert_has_calls on mock_work_function, instead of on mock_work_function.return_value.

Categories

Resources