I want to test a function which import another module.
So i want to mock module.
So my test function :
def test_validate_transaction():
dataset_id = "idx"
transaction_id = "idy"
transaction = {
"transaction_rid" : transaction_id,
"is_successful" : True
}
with mock.patch('table_management.get_last_transaction_id', return_value=transaction) :
assert validate_transaction(dataset_rid,transaction_rid) == False
and my function that i want to test is
import json
import os
from table_management import get_last_transaction_id
def validate_transaction(dataset_id,transaction_id):
try:
transaction = get_last_transaction_id(dataset_rid)
return True if transaction['transaction_id'] != transaction_rid or transaction['is_successful']==False else False
except Exception as e:
print("An exception occurred " + str(e))
return {}
But by doing this, i receive the error :
..\..\..\env\lib\site-packages\mock\mock.py:1378: in __enter__
self.target = self.getter() ..\..\..\env\lib\site-packages\mock\mock.py:1548: in <lambda>
getter = lambda: _importer(target)
target = 'table_management'
def _importer(target):
components = target.split('.')
import_path = components.pop(0)
thing = __import__(import_path)
E ImportError: No module named table_management
..\..\..\env\lib\site-packages\mock\mock.py:1231: ImportError
do you have any idea what is missing ?
I'm not sure that you actually don't have some other issues related to import but you are trying to mock a wrong object. You need to mock get_last_transaction_id imported in the module where validate_transaction is. You didn't mention its name so let's assume it's called xyz:
from full_path.to.xyz import validate_transaction
def test_validate_transaction():
dataset_id = "idx"
transaction_id = "idy"
transaction = {
"transaction_rid" : transaction_id,
"is_successful" : True
}
with mock.patch('xyz.get_last_transaction_id', return_value=transaction):
assert validate_transaction(dataset_rid,transaction_rid) == False
Related
file.py
import datetime
ENV_NUMBER_DAYS_RESERVED = 3
def check_date(entity):
entity_created_date = entity.get('createdDatetime').date()
utc_date = datetime.datetime.utcnow().date()
print((utc_date - entity_created_date).days) #<MagicMock name='datetime.datetime.utcnow().date().__sub__().days' id='4899349456'>
print(type((utc_date - entity_created_date).days))#<class 'unittest.mock.MagicMock'>
return True if (utc_date - entity_created_date).days > int(ENV_NUMBER_DAYS_RESERVED) else False
test.py
import file
#patch('file.datetime')
def test_check_date_False(self, date_now):
entity = MagicMock()
entity.get.return_value = datetime.datetime(2022,1,1)
date_now.datetime.utcnow.date.return_value = datetime.datetime(2022,1,1)
self.assertFalse(check_date(entity=entity))
I get an Error:
TypeError: '>' not supported between instances of 'MagicMock' and 'int'
Is there anyway to test this function?
Probably the problem is with this part of the last line:
(utc_date - namespace_created_date).days
I could reproduce and fix.
Here is a working unittest file (assuming file.py is accessible):
import unittest
from unittest.mock import patch, MagicMock
import datetime
import file
class TestFile(unittest.TestCase):
#patch('file.datetime')
def test_check_date_False(self, date_now):
entity = MagicMock()
entity.get.return_value = datetime.datetime(2022,1,1)
date_now.datetime.utcnow.return_value = datetime.datetime(2022,1,1)
self.assertFalse(file.check_date(None, entity=entity))
unittest.main(verbosity=2)
If I use date_now.datetime.utcnow.date.return_value = datetime.datetime(2022,1,1) I have the same error as you have, but removing .date is enough to have the test to pass.
I have a Scenario where i want to check file exist at path or not
But if file not exist at path catch the error and log it to file using logging module and then script should break (exit). further code of lines should not be executed which is next function addtion_value if first function falls
Note : my script file contains lots of function one after the other in same file
Below is my code , i was able to code but with error
import path
import logging
logging.basicConfig(filename='log.txt',level=logging.INFO,format='%(asctime)',filemode='w')
def checkfileexist(Pth,Fle):
var=Path(Pth+'/'+Fle)
try :
if var.is_file():
logging.INFO('File found')
return (var)
exception Nofile as er:
logging.error('Not Found file')
else:
sys.exit()
def additionvalue(a,b):
return (a+b)
Is it possible to make use of import os module and create code ?
I have modified your script and it's working
import os
import logging
import sys
logging.basicConfig(filename='log.txt',level=logging.INFO,format='%(asctime)s- %(message)s',filemode='a')
def checkfileexist(Pth,Fle):
var=Pth+'/'+Fle
try :
if (var is None):
logging.error('Path is empty')
raise Exception("empty path")
if os.path.exists(var):
logging.error('File found')
return (var)
else:
raise Exception("File Not found")
except Exception as e:
logging.error('Not Found file')
sys.exit()
def additionvalue(a,b):
return (a+b)
you were not logging the message %(asctime)s- %(message)s as well as instead of 'w' you should use 'a' (append)
You can do it without raising any error:
def checkfileexist(Pth,Fle):
var = Path(Pth+'/'+Fle)
if var.is_file():
logging.info('File found')
return var
else:
logging.error('Not Found file')
But if you insist, you can do something like this:
def checkfileexist(Pth,Fle):
var = Path(Pth+'/'+Fle)
try:
if not var.is_file():
raise FileNotFoundError()
except FileNotFoundError as er:
logging.error('Not Found file')
else:
logging.info('File found')
return var
need to check both the parameter is passed to the function checkfilexist()
When you define a function with required parameters (as the function above), Python will already raise an error if you don't pass all its parameters:
checkfileexist()
# Raises TypeError: checkfileexist() missing 2 required positional arguments: 'Pth' and 'Fle'
checkfileexist('/c/d/',)
# Raises TypeError: checkfileexist() missing 1 required positional argument: 'Fle'
For the third case (raise an error if any argument is empty), you can do something like this:
def checkfileexist(Pth,Fle):
# Same as `if len(Pth) == 0:`
if not Pth:
raise TypeError("parameter Pth must not be empty")
# Same as `if len(Fle) == 0:`
if not Fle:
raise TypeError("parameter Fle must not be empty")
# ...
After all above answers and tried on my editor and prepared this below script
Correct me if any thing wrong in below code
Thanks for helping me with your approach: #lakshika-parihar #enzo & #Joaquim Procopio
But this worked for me
import os
import logging
import sys
logging.basicConfig(filename='C:\\Users\\admin\\Desktop\\JUL\\log.txt', level=logging.INFO,
format='%(asctime)s : %(message)s', filemode='w')
def checkfileexist(file_path, file_name):
try:
var_pth = str(file_path)
var_fle = str(file_name)
var_full = var_pth + var_fle
if var_pth is None or var_pth == '':
logging.error("Path parameter is empty")
raise TypeError('Path parameter is empty')
else:
pass
logging.info(f'Path : {var_pth}')
if var_fle is not None and var_fle != '':
pass
logging.info(f'Full : {var_fle}')
else:
logging.error("File parameter is empty")
raise TypeError('File parameter is empty')
if os.path.exists(var_full):
logging.error(f'File : {var_fle} is found at path : {var_pth} ')
logging.info(f'File : {var_full}')
return var_full
except:
logging.error(f"ERRO : {erron} ")
sys.exit()
try:
# Calling function
# checkfileexist('C:\\Users\\admin\\Desktop\\JUL\\', 'ABX')
# checkfileexist('', 'ABX') #Output : 2021-07-28 22:45:48,307 : Path parameter is empty
# checkfileexist('', '') #Output : 2021-07-28 22:46:53,758 : Path parameter is empty
checkfileexist() #2021-07-29 11:12:46,207 : ERROR : checkfileexist() missing 2 required positional arguments: 'file_path' and 'file_name'
except Exception as er:
logging.error(f"ERROR : {er} ")
sys.exit()
I'd like to mock an OverflowError because I'd like to test the value of a variable is after that exception is raised. However, I do not know how to replicate an OverflowError with the libraries I am using. Libraries I am using in this specific test is pysolar.solar specifically the get_altitude, get_azimuth and radiation methods
After mindlessly trying out different numbers to try to simulate an OverflowError I decided to try out Mocking the function and introducing a side effect.
Code I am testing sunposition.py
import numpy as np
import pandas as pd
from pysolar.solar import get_altitude, get_azimuth, radiation as radiation_module
def sun_position(lat: float, lon: float, time: pd.Timestamp = None) -> List[float]:
if time is None:
time = pd.Timestamp.now(tz='UTC')
dt = time.to_pydatetime()
altitude = get_altitude(lat, lon, dt)
azimuth = get_azimuth(lat, lon, dt)
try:
radiation = radiation_module.get_radiation_direct(dt, altitude)
except OverflowError:
radiation = np.nan
return pd.Series([altitude, azimuth, radiation], index=['Alt', 'Azi', 'Rad'])
**What I started to do with patch **
"""Test sunposition module"""
import unittest
import numpy as np
import pandas as pd
from unittest.mock import MagicMock, patch, Mock
from bigfolder.sun import sunposition
class TestSunposition(unittest.TestCase):
"""Test functions in sunposition."""
def test_sun_position_overflow_error(self):
error_lat = 23
error_lon = 12
error_time = pd.Timestamp('2007-02-18 15:13:05', tz="UTC")
mock_args = {'side_effect': OverflowError}
with patch('bigfolder.sun.sunposition.sun_position', **mock_args):
# run the test
self.assertRaises(OverflowError, sunposition.sun_position(lat=error_lat, lon=error_lon, time=error_time))
if __name__ == '__main__':
unittest.main()
I was expecting it to give me and OverFlow error... and it did, however my assertion failed anyways with an OverflowError My guess is that I patched at the wrong place? I don't really understand why the test failed regardless when the error was still an OverFlow Error
This is what was printed out
_mock_self = <MagicMock name='sun_position' id='102333856'>, args = ()
kwargs = {'lat': 23, 'lon': 12, 'time': Timestamp('2007-02-18 15:13:05+0000', tz='UTC')}
self = <MagicMock name='sun_position' id='102333856'>, _new_name = ''
_new_parent = None
_call = call(lat=23, lon=12, time=Timestamp('2007-02-18 15:13:05+0000', tz='UTC'))
seen = set(), skip_next_dot = False, do_method_calls = False
name = 'sun_position'
def _mock_call(_mock_self, *args, **kwargs):
self = _mock_self
self.called = True
self.call_count += 1
_new_name = self._mock_new_name
_new_parent = self._mock_new_parent
_call = _Call((args, kwargs), two=True)
self.call_args = _call
self.call_args_list.append(_call)
self.mock_calls.append(_Call(('', args, kwargs)))
seen = set()
skip_next_dot = _new_name == '()'
do_method_calls = self._mock_parent is not None
name = self._mock_name
while _new_parent is not None:
this_mock_call = _Call((_new_name, args, kwargs))
if _new_parent._mock_new_name:
dot = '.'
if skip_next_dot:
dot = ''
skip_next_dot = False
if _new_parent._mock_new_name == '()':
skip_next_dot = True
_new_name = _new_parent._mock_new_name + dot + _new_name
if do_method_calls:
if _new_name == name:
this_method_call = this_mock_call
else:
this_method_call = _Call((name, args, kwargs))
_new_parent.method_calls.append(this_method_call)
do_method_calls = _new_parent._mock_parent is not None
if do_method_calls:
name = _new_parent._mock_name + '.' + name
_new_parent.mock_calls.append(this_mock_call)
_new_parent = _new_parent._mock_new_parent
# use ids here so as not to call __hash__ on the mocks
_new_parent_id = id(_new_parent)
if _new_parent_id in seen:
break
seen.add(_new_parent_id)
ret_val = DEFAULT
effect = self.side_effect
if effect is not None:
if _is_exception(effect):
> raise effect
E OverflowError
So then I thought I must have patched in the wrong place and introduced the side effect earlier than I should have? So I instead patched the method int the try block. This was my following code.
def test_sun_position_overflow_error(self):
error_lat = 23
error_lon = 12
error_time = pd.Timestamp('2007-02-18 15:13:05', tz="UTC")
mock_args = {'side_effect': OverflowError}
with patch('bigfolder.sun.sunposition.sun_position.radiation_module.get_radiation_direct', **mock_args):
# run the test
self.assertRaises(OverflowError, sunposition.sun_position(lat=error_lat, lon=error_lon, time=error_time))
And now my error is " ModuleNotFoundError: No module named 'bigfolder.sun.sunposition.sun_position'; 'bigfolder.sun.sunposition' is not a package"
I then just changed the path to 'sun_position.radiation_module.get_radiation_direct' but there's no module found.
So my questions are: How to replicate an OverflowError so that then I can check the value of a variable I set once that Exception is raised. Why is the first OverflowError I introduce still not pass my assertion?
Thanks
UPDATE TEST passes
After following #Gang 's suggestion, the OverFlowError was reproduced. I realized that in order to test the block for the exception, specifically that radiation was then np.nan I had to patch the method that I wanted to have the OverFlowError and not the whole method of sun_position. When I tried doing that I imported it incorrectly, as I thought the external library was part of the code. So I changed bigfolder.sun.sunposition.sun_position.radiation_module.get_radiation_direct to pysolar.solar.radiation.get_radiation_direct which is the external library that has the get_radiation_direct method I wanted to mock.
def test_sun_position_overflow_error(self):
lat = 23
lon = 12
time = pd.Timestamp('2007-02-18 15:13:05', tz="UTC")
# get_radiation_direct will now produce an OverFlowError(regardless of coordinates)
mock_args = {'side_effect': OverflowError}
# mock get_radiation_direct and produce OverFlowError
with patch('pysolar.solar.radiation.get_radiation_direct', **mock_args):
# Check radiation column is nan value
assert math.isnan(sunposition.sun_position(lat=lat, lon=lon, time=time)[2])
Why is the first OverflowError I introduce still not pass my assertion?
Almost there. The right way to assertRaises:
def test_sun_position_overflow_error(self):
# This has to be here first and without func call
with self.assertRaises(OverflowError):
# patch the function to have an exception no matter what
mock_args = {'side_effect': OverflowError}
with patch('bigfolder.sun.sunposition.sun_position', **mock_args):
# call this func to trigger an exception
sunposition.sun_position(lat=error_lat, lon=error_lon, time=error_time)
After review the document, it is how to call a func inside assertRaises
assertRaises(exception, callable, *args, **kwds)
fun(*args, **kwds) raises exc
This usage is wrong:
self.assertRaises(OverflowError, sunposition.sun_position(lat=error_lat, lon=error_lon, time=error_time))
It should be a func name with kwargs:
self.assertRaises(OverflowError, sunposition.sun_position, lat=error_lat, lon=error_lon, time=error_time)
If I run the below code in pycharm, I get this error:
--error--
C:\Python33\python.exe B:/Python/untitled3/working_test.py
'vim.VirtualMachine:vm-65063'
Traceback (most recent call last):
File "B:/Python/untitled3/working_test.py", line 47, in <module>
main()
File "B:/Python/untitled3/working_test.py", line 37, in main
filterspec = vim.TaskFilterSpec(vim.TaskFilterSpec.ByEntity(entity=source_machine))
TypeError: __init__() takes 1 positional argument but 2 were given
Process finished with exit code 1
--error--
I've tried using self, creating a class etc, but I just can't get my head around what I'm doing wrong. Any help is appreciated. I'm basically, trying to get task information on an entity (virtual machine) within vsphere.
Thanks!
import ssl
from pyVim import connect
from pyVmomi import vmodl, vim
def main():
try:
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
context.verify_mode = ssl.CERT_NONE
si = connect.SmartConnect(host='vcenter name',
user='user name',
pwd='password',
port=443,
sslContext=context)
if not si:
print("Could not connect to the specified host using specified "
"username and password")
return -1
content = si.RetrieveContent()
def getobject(vimtype, name):
obj = None
container = content.viewManager.CreateContainerView(content.rootFolder, vimtype, True)
for c in container.view:
if c.name == name:
obj = c
break
return obj
source_machine = getobject([vim.VirtualMachine], 'virtual machine name')
print(source_machine)
taskManager = content.taskManager
filterspec = vim.TaskFilterSpec(vim.TaskFilterSpec.ByEntity(entity=source_machine))
collector = taskManager.CreateCollectorForTasks(filterspec)
except vmodl.MethodFault as e:
print("Caught vmodl fault : {}".format(e.msg))
return -1
return 0
if __name__ == "__main__":
main()
thank you for the help.
i've adjusted this portion of the code and it's returned back without errors, but looking into now, why it only seems to be returning the query task itself instead of the tasks pertaining to the vm. I think it may have something to do with the tasks being at a vcenter level, but working throug it now.
source_machine = getobject([vim.VirtualMachine], 'virtual machine name)
taskManager = content.taskManager
filterspec = vim.TaskFilterSpec()
filterspec.entity = vim.TaskFilterSpec.ByEntity(entity=source_machine,recursion='all')
collector = taskManager.CreateCollectorForTasks(filterspec)
print(collector)
output returned:
C:\Python33\python.exe B:/Python/untitled3/working_test.py
'vim.TaskHistoryCollector:session[52b617f0-0f65-705c-7462-814d8b648fdd]52081175-cb98-a09f-f9f6-f6787f68d3b7'
Process finished with exit code 0
vim.TaskFilterSpec() accepts no positional arguments. A minimal reproduction of the exception can be had with:
>>> vim.TaskFilterSpec(vim.TaskFilterSpec.ByEntity(entity=vim.ManagedEntity('1')))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __init__() takes 1 positional argument but 2 were given
The class constructor vim.TaskFilterSpec() wants to be invoked with a entity named parameter. In your example code above, this would mean altering line 37 to read:
filterspec = vim.TaskFilterSpec(entity=vim.TaskFilterSpec.ByEntity(entity=source_machine))
When invoked with a placebo ManagedEntity, this results in a filter-spec similar to:
>>> source_machine=vim.ManagedEntity('1')
>>> filterspec = vim.TaskFilterSpec(entity=vim.TaskFilterSpec.ByEntity(entity=source_machine))
>>> filterspec
(vim.TaskFilterSpec) {
dynamicType = <unset>,
dynamicProperty = (vmodl.DynamicProperty) [],
entity = (vim.TaskFilterSpec.ByEntity) {
dynamicType = <unset>,
dynamicProperty = (vmodl.DynamicProperty) [],
entity = 'vim.ManagedEntity:1',
recursion = <unset>
},
time = <unset>,
userName = <unset>,
activationId = (str) [],
state = (vim.TaskInfo.State) [],
alarm = <unset>,
scheduledTask = <unset>,
eventChainId = (int) [],
tag = (str) [],
parentTaskKey = (str) [],
rootTaskKey = (str) []
}
I am trying to set up some code using Pyro to process python code functions on a remote host and get results back. After starting the name server, i would execute this code on the remote host (actually still on localhost):
import Pyro4
class Server(object):
def evaluate(self, func, args):
return func(*args)
def main():
server = Server()
Pyro4.Daemon.serveSimple(
{
server: "server"
},
ns=True)
if __name__ == '__main__':
main()
On the client side i have this code, which is an example of the behaviour i am trying to set up.
import Pyro4
remoteServer = Pyro4.Proxy('PYRONAME:server')
def square(x):
return x**2
print remoteServer.evaluate(square, 4)
However, this code results in the following exception:
/usr/lib/python2.7/site-packages/Pyro4/core.py:155: UserWarning: HMAC_KEY not set,
protocol data may not be secure
warnings.warn("HMAC_KEY not set, protocol data may not be secure")
Traceback (most recent call last):
File "/home/davide/Projects/rempy/example-api-pyro.py", line 7, in <module>
print remoteServer.evaluate(square, 4)
File "/usr/lib/python2.7/site-packages/Pyro4/core.py", line 149, in __call__
return self.__send(self.__name, args, kwargs)
File "/usr/lib/python2.7/site-packages/Pyro4/core.py", line 289, in _pyroInvoke
raise data
AttributeError: 'module' object has no attribute 'square'
It seems to me that the function object is pickled correctly and is sent to the Server instance on the remote host, but there is some problem in the namespace.
How can i solve this problem?
Thanks
I think i know your problem:
the module the function is defiined in is called
'__main__'
it exists in all running versions of python.
pickle does not transfer the source code but a reference
__main__.square
so you have two possibilities:
source square out and make the main module as short as possible such as:
# main.py
def square(x):
return x**2
import Pyro4
def main():
remoteServer = Pyro4.Proxy('PYRONAME:server')
print remoteServer.evaluate(square, 4)
and:
# __main__.py
import main
main.main()
Then the server can import exactly the same module from the file.
or create a module with my code:
class ThisShallNeverBeCalledError(Exception):
pass
class _R(object):
def __init__(self, f, *args):
self.ret = (f, args)
def __reduce__(self):
return self.ret
def __call__(self, *args):
raise ThisShallNeverBeCalledError()
#classmethod
def fromReduce(cls, value):
ret = cls(None)
ret.ret = value
return ret
def dump_and_load(obj):
'''pickle and unpickle the object once'''
s = pickle.dumps(obj)
return pickle.loads(s)
# this string creates an object of an anonymous type that can
# be called to create an R object or that can be reduced by pickle
# and creates another anonymous type when unpickled
# you may not inherit from this MetaR object because it is not a class
PICKLABLE_R_STRING= "type('MetaR', (object,), " \
" {'__call__' : lambda self, f, *args: "\
" type('PICKLABLE_R', "\
" (object,), "\
" {'__reduce__' : lambda self: (f, args), "\
" '__module__' : 'pickleHelp_', "\
" '__name__' : 'PICKLABLE_R', "\
" '__call__' : lambda self: None})(), "\
" '__reduce__' : lambda self: "\
" self(eval, meta_string, "\
" {'meta_string' : meta_string}).__reduce__(), "\
" '__module__' : 'pickleHelp_', "\
" '__name__' : 'R'})()".replace(' ', '')
PICKLABLE_R = _R(eval, PICKLABLE_R_STRING, \
{'meta_string' : PICKLABLE_R_STRING})
R = dump_and_load(PICKLABLE_R)
del PICKLABLE_R, PICKLABLE_R_STRING
PICKLABLE___builtins__ = R(vars, R(__import__, '__builtin__'))
PICKLABLE_FunctionType = R(type, R(eval, 'lambda:None'))
##R.__module__ = __name__
##R.__name__ = 'PICKLABLE_R'
def packCode(code, globals = {}, add_builtins = True, use_same_globals = False, \
check_syntax = True, return_value_variable_name = 'obj',
__name__ = __name__ + '.packCode()'):
'''return an object that executes code in globals when unpickled
use_same_globals
if use_same_globals is True all codes sent through
one pickle connection share the same globals
by default the dont
return_value_variable_name
if a variable with the name in return_value_variable_name exists
in globals after the code execution
it is returned as result of the pickling operation
if not None is returned
__name__
'''
if check_syntax:
compile(code, '', 'exec')
# copying locals is important
# locals is transferred through pickle for all code identical
# copying it prevents different code from beeing executed in same globals
if not use_same_globals:
globals = globals.copy()
if add_builtins:
globals['__builtins__'] = PICKLABLE___builtins__
globals.setdefault('obj', None)
# get the compilation code
# do not marshal or unmarshal code objects because the platforms may vary
code = R(compile, code, __name__, 'exec')
# the final object that can reduce, dump and load itself
obj = R(R(getattr, tuple, '__getitem__'), (
R(R(PICKLABLE_FunctionType, code, globals)),
R(R(getattr, type(globals), 'get'), globals, \
returnValueVariableName, None)
), -1)
return obj
and then send this to the other side:
packCode('''
def square(...):
...
''', return_value_variable_name = 'square')
and the function will come out on the other side, no module code is needed to transefer this python function to the other server side.
If something does not work out please tell me.