I need to patch a function imported from the same file containing another function I want to test, but it's not working =/.
# funcs.py
def func_one():
return 1
def func_two():
return func_one() + 2
from .funcs import func_two
class TestFunc(TestCase):
def test_func_two(self):
with patch('func_one', 0):
result = func_two()
The result should be two but I got an error with the test:
TypeError: Need a valid target to patch. You supplied: 'func_one'
I need to import the absolute path of the function:
from .funcs import func_two
class TestFunc(TestCase):
def test_func_two(self):
#patch('funcs.func_one', MagicMock(return_value=0)):
result = func_two()
Where funcs.func_one is the entire module path + func name.
Related
Is there a way to make a function_a define a variable usable inside another function_b so that both are possible to import in a project ? Something like so:
Script_1
def func_a(str):
if str == 'Yes'
nb = 1
else:
nb=0
return nb
def func_b(int)
calc = (nb+int)**2
return calc
Script_2
from Script_1 import func_a, func_b
func_a('Yes')
func_b(5)
My attempt at declaring nb in Script_2 did not work as python tried to find it in Script_1. I hope this can give an idea of what I am trying to do. Also, the names of the variable are but a representation of type (strand int) I am looking for. Python is rather new to me and I am still learning. Thanks in advance.
The standard way to pass state from one function to another is for one function to return the value and for the other to take it as an argument.
# Script_1
def func_a(msg: str) -> int:
if msg == 'Yes':
return 1
else:
return 0
def func_b(na: int, nb: int) -> int:
return (na + nb)**2
# Script_2
# from Script_1 import func_a, func_b
nb = func_a('Yes')
print(func_b(5, nb))
By adding nb as an argument to func_b, we can take the return value from func_a and pass it to func_b. (Doing weird stuff with injecting data into the global namespace is technically possible, but it makes your code extraordinarily difficult to debug.)
Thanks to Amadan's suggestion, I was able to do this:
class test(object):
def __init__(self,string):
self.string = string
if string == 'Yes':
self.factor = 1
else:
self.factor = 0
def func(self, num):
calc = (num+self.factor)**2
return calc
And can be used as such in another file once saved in test.py:
from test import test
test('Yes').func(3)
test('No').func(3)
I have this file with unit tests:
#file tests.py
class TestResults(TestBase): ...
class TestRegisteredFunctions(TestBase):
"""Tests functions registered dynamically."""
def testNewFunction(self):
"""Server must register new functions."""
# Register new function
def square(num):
return num * num
self.server.register('square', square)
res = self.jsonrpc_req(1, 'square', [2])
self.assertEqual(res['result'], 4)
Most of the code is omitted because will not be relevant.
My problem is I need to grab that "square" function.
For example doing getattr(tests, 'square') in another module would correctly get me that square function. How can I achieve such result?
In a function I'm using uuid1 that I want to patch.
def myFunction():
my_value = uuid4.int
smth else..
I want to be able to mock my_value so it always returns the same number in my unit test, because I need it for further use.
I tried doing:
#patch('folder.myFunction.uuid4')
def test_myFunction(self, mock_value):
mock_value.return_value = 22222
But it throws an error saying myFunction does not have uuid4 as an attribute.
How do I mock its value?
The error you get is correct. Your function does not have a uuid4 attribute.
I'm reading between the lines assuming uuid4 is a method of the uuid module that normally generates a random uuid.
When testing you said you want it to always return the same value. To do that you can substitute a unittest.mock.Mock for uuid.uuid4.
In [36]: uuid_mock = Mock(return_value=uuid.UUID('77f1df52-4b43-11e9-910f-b8ca3a9b9f3e'))
In [37]: uuid_mock()
Out[37]: UUID('77f1df52-4b43-11e9-910f-b8ca3a9b9f3e')
Something like this for testing the following function (f)
import uuid, unittest
from unittest.mock import Mock, patch
def f():
z = uuid.uuid4()
return z.int
The target for the patch is the uuid method - uuid.uuid4. Specify a unittest.mock.Mock with a fixed return value for the new parameter of the patch. During the test, the Mock will be substituted for uuid.uuid4
class TestF(unittest.TestCase):
uuid_mock = Mock(return_value=uuid.UUID('77f1df52-4b43-11e9-910f-b8ca3a9b9f3e'))
good_uuid = uuid.UUID('77f1df52-4b43-11e9-910f-b8ca3a9b9f3e').int
bad_uuid = uuid.UUID('77f1df52-4b43-11e9-910f-b8ca3a9b5a31').int
#patch(target='uuid.uuid4', new=TestF.uuid_mock)
def test_myFunction_True(self):
self.assertEqual(f(), self.good_uuid)
#patch(target='uuid.uuid4', new=TestF.uuid_mock)
def test_myFunction_False(self):
self.assertNotEqual(f(), self.bad_uuid)
if __name__ == '__main__':
unittest.main()
Result:
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK
If you want to test a function that relies on f's return value and you want f to always return the same value during testing then make f the target for the patch.
def g():
return f() == uuid.UUID('77f1df52-4b43-11e9-910f-b8ca3a9b9f3e').int
class TestG(unittest.TestCase):
good_uuid_mock = Mock(return_value=uuid.UUID('77f1df52-4b43-11e9-910f-b8ca3a9b9f3e').int)
bad_uuid_mock = Mock(return_value=uuid.UUID('77f1df52-4b43-11e9-910f-b8ca3a9b5a31').int)
#patch(target='__main__.f', new=TestG.good_uuid_mock)
def test_myFunction_True(self):
self.assertTrue(g())
#patch(target='__main__.f', new=TestG.bad_uuid_mock)
def test_myFunction_False(self):
self.assertFalse(g())
It depends on your import. Let's say you have a module called module.py, and you have an import like this:
from uuid import uuid4
This means that in this module we now have a variable called uuid4. This is the thing to mock.
#patch('path.to.module.uuid4.int')
I do not want to import my module. I have to count the number of functions given the .py file path. What is the best way to do so?
One thing I thought about was to count the number of "def" in my code, but it does not seem like the best way to go about this. Is there any better way to count the number of functions?
To count the top level definition, use ast module like this:
import ast
with open(filename) as f:
tree = ast.parse(f.read())
sum(isinstance(exp, ast.FunctionDef) for exp in tree.body)
You can use ast.NodeVisitor:
import inspect
import importlib
import ast
class CountFunc(ast.NodeVisitor):
func_count = 0
def visit_FunctionDef(self, node):
self.func_count += 1
mod = "/path/to/some.py"
p = ast.parse(open(mod).read())
f = CountFunc()
f.visit(p)
print(f.func_count)
If you wanted to include lambdas you would need to add a visit_Lambda:
def visit_Lambda(self, node):
self.func_count += 1
That will find all defs including methods of any classes, we could add more restrictions to disallow that:
class CountFunc(ast.NodeVisitor):
func_count = 0
def visit_ClassDef(self, node):
return
def visit_FunctionDef(self, node):
self.func_count += 1
def visit_Lambda(self, node):
self.func_count += 1
You can tailor the code however you like, all the nodes and their attributes are described in the greentreesnakes docs
Padraic beats me to it, but here is my code, which works with Python 2 and Python 3.
from __future__ import print_function
import ast
class FunctionCounter(ast.NodeVisitor):
def __init__(self, filename):
self.function_count = 0
with open(filename) as f:
module = ast.parse(f.read())
self.visit(module)
def visit_FunctionDef(self, node):
print('function: {}'.format(node.name))
self.function_count += 1
# Uncomment this to disable counting methods, properties within a
# class
# def visit_ClassDef(self, node):
# pass
if __name__ == '__main__':
counter = FunctionCounter('simple.py')
print('Number of functions: {}'.format(counter.function_count))
Discussion
This code not only count the function at the module level, it also count functions (method and properties) nested within class definitions.
To disable counting functions in the class definitions, uncomment the 2 lines for visit_ClassDef
You can use
len(dir(module))
Hope it helps
you can use the pyclbr module to get results of the module, the only catch is that you need to use the name of the module as you would import it instead of the file path, this benefits from also recognizing from X import Y for python source based modules (not builtin ones like math)
from pyclbr import readmodule_ex, Function
#readmodule_ex is function 1
def test(): #2
pass
def other_func(): #3
pass
class Thing:
def method(self):
pass
result = readmodule_ex("test") #this would be it's own file if it is test.py
funcs = sum(isinstance(v,Function) for v in result.values())
print(funcs)
My answer is an edit to the answer of # Naveen Kumar because I can not edit his answer at the moment.
You can use
import module
len(dir(module))
i.e:
import math
print(len(dir(math)))
output:
63
I'm getting close to my final goal, which is to generate a nice graph between modules and other imported modules.
For example if x imports from y and z, and y imports from t and v I would like to have:
x -> y, z
y -> t, v
Now I already have my import hook defined as below, but running it on a simple file I don't get what I would expect:
python study_imports.py CollectImports simple.py
('study_imports.py', 'study_imports')
Where simple.py actually imports from study_imports.
The problem is that I want to see "simple.py" instead of "study_imports.py", is there a way to get the path of the file actually importing the other module?
class CollectImports(object):
"""
Import hook, adds each import request to the loaded set and dumps
them to file
"""
def __init__(self, output_file):
self.loaded = set()
self.output_file = output_file
def __str__(self):
return str(self.loaded)
def cleanup(self):
"""Dump the loaded set to file
"""
dumped_str = '\n'.join(x for x in self.loaded)
open(self.output_file, 'w').write(dumped_str)
def find_module(self, module_name, package=None):
#TODO: try to find the name of the package which is actually
#importing something else, and how it's doing it
#use a defualtdict with empty sets as the storage for this job
entry = (__file__, module_name)
self.loaded.add(str(entry))
Maybe with the inspect module.
Module a.py
import inspect
print inspect.stack()
Module b.py
import a
when running b.py, I got :
[
(<frame object at 0x28a9b70>, '/path/a.py', 5, '<module>', ['print inspect.stack()\n'], 0),
(<frame object at 0x28a9660>, 'b.py', 2, '<module>', ['import to_import\n'], 0)
]
Looks like the second frame contains what you need.
So I looked in snakefood a bit better and I ended up rewriting my code using the AST.
Snakefood still uses the compiler, which is deprecated and much slower than using the ast.
The result is great, for example this is a visitor:
from ast import parse, NodeVisitor
class ImportVisitor(NodeVisitor):
def __init__(self):
self.imported = set()
super(ImportVisitor, self).__init__()
def __str__(self):
return '\n'.join(x for x in self.imported)
def visit_Import(self, node):
for n in node.names:
self.imported.add(n.name)
#that we are using
def visit_ImportFrom(self, node):
self.imported.add(node.module)
Which can be usef for example as:
def gen_module_imports(mod):
try:
at = parse(open(mod).read())
except SyntaxError:
print("file %s has a syntax error, please fix it" % mod)
return []
else:
v = ImportVisitor()
v.visit(at)
return v.imported
The inspect trick seems to work fine :)
I get something like simple.py: set(['study_imports']) in the imports.log.
Class CollectImports(object):
"""
Import hook, adds each import request to the loaded set and dumps
them to file
"""
def __init__(self, output_file):
self.loaded = defaultdict(lambda: set())
self.output_file = output_file
def __str__(self):
return str(self.loaded)
def cleanup(self):
"""Dump the loaded set to file
"""
dumped_str = '\n'.join(('%s: %s' % (k, v)) for k, v in self.loaded.items())
open(self.output_file, 'w').write(dumped_str)
def find_module(self, module_name, package=None):
st = inspect.stack()
self.loaded[st[1][1]].add(module_name)