Given an object produced during importing the code, produce the set of imports that are needed to execute that object creation code.
Case 1:
some_obj = module.submodule.Class(42)
get_imports for_object(some_obj)
>>> "import module.submodule"
Case 2 (Sometimes the root module does not import submodules automatically (e.g. Airflow operators)):
some_obj = submodule.Class(42)
get_imports for_object(some_obj)
>>> "from module import submodule"
Case 3 (stretch goal):
some_obj = submodule.Class(sub2.Class2(42))
get_imports for_object(some_obj)
>>> ["from module import submodule", "from module2 import sub2"]
The goal is to produce import lines such that prepending them to object instantiation code will make the instantiation work.
This'll do:
def get_object_imports(obj, sub_obj_class_name=None):
sub_obj_modules = []
if sub_obj_class_name is not None:
for _, attribute_value in obj.__dict__.items():
value_str = str(getattr(attribute_value,'__class__',''))
if ('.' + sub_obj_class_name) in value_str:
sub_obj_modules.append(attribute_value.__module__)
if sub_obj_modules != []:
sub_module_imports = [('import ' + sub_obj_module) for sub_obj_module
in sub_obj_modules]
return ['import ' + obj.__module__] + sub_module_imports
else:
return 'import ' + obj.__module__
Cases (1) & (2) are equivalent, in that running either imports the same module. Note that with above, objects with same class names but different module sources will be included.
Demo:
from module import class1
from other_module import submodule
obj1 = class1()
obj2 = obj1(submodule.class2())
print(get_object_imports(obj2, 'class2'))
# ['import module', 'import other_module.submodule']
Related
If I have the following directory structure:
handy/
- __init__.py
- utils.py
- dir1
- __init__.py
- script.py
I can populate DATA in help() by writing non-keywords into the __init__.py file, for example:
# __init__.py
hello = "xyz"
other = "z"
variables = 1
Now when I do help(handy), it shows:
DATA
hello = 'xyz'
other = 'z'
variables = 1
Are there any other ways to populate the help DATA from outside of the top-level __init__.py file, or is that the only way?
I'm not sure what you have in mind, but since handy/__init__.py is an executable script, you could do something like this:
__init__.py:
from .utils import *
hello = "xyz"
other = "z"
variables = 1
utils.py:
UTILS_CONSTANT = 42
def func():
pass
Which would result in:
>>> import handy
>>> help(handy)
Help on package handy:
NAME
handy
PACKAGE CONTENTS
utils
DATA
UTILS_CONSTANT = 42
hello = 'xyz'
other = 'z'
variables = 1
FILE
c:\stack overflow\handy\__init__.py
>>>
to what help(handy) displays.
There is a module in helpers directory called helper_a.py.
It has all classes and functions defined here.
Now I want to call a function from here into another module (not in helpers directory) but one step (cd ..) behind. (init.py) is in helpers directory.
Code and error is as below :
from helpers.helper_a import *
import pandas as pd
query_train_data = "select * from train;"
df_train_dataset = pd.read_sql(query_train_data, con=engDps1000)
query_test_data = "select * from test;"
df_test_dataset = pd.read_sql(query_test_data, con=engDps1000)
df_train_data = df_train_dataset
df_test_data = df_test_dataset
data_prep_steps() # This function is defined in helpers_a
Error:
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-12-3c88b46f341a> in <module>
----> 1 data_prep_steps()
~\Desktop\Notebooks\helpers\helper_a.py in data_prep_steps()
---> 89 # STEP 1 : CONVERT REQUIRED COLS TO CATEGORIES
90 for df_name in [df_train_data, df_test_data]:
91 data_prep_class = data_prep(df_name)
NameError: name 'df_train_data' is not defined
Question is that the variable df_train data is defined in the current module and i want to use it in the function defined in helpers_a by calling it also in the current module, but why is it not recognizing this variable??
Note : Also tried assigning global variable status but it still doesnt solve the issue
There is a solution to create non existing attributes,methods or functions in other modules. It comes from unit testing.
from unittest.mock import patch, PropertyMock
from helpers.helper_a import *
import pandas as pd
query_train_data = "select * from train;"
df_train_dataset = pd.read_sql(query_train_data, con=engDps1000)
query_test_data = "select * from test;"
df_test_dataset = pd.read_sql(query_test_data, con=engDps1000)
df_train_data = df_train_dataset
df_test_data = df_test_dataset
with patch('helpers.helper_a.df_test_data',create=True,new_callable=PropertyMock) as df_test_data_mock: #Create tells to create attribute if it does not exist
with patch('helpers.helper_a.df_train_data', create=True, new_callable=PropertyMock) as df_train_data_mock: # PropertyMock is used to mock properties
df_test_data_mock.return_value = df_test_data
df_train_data_mock.return_value = df_train_data
data_prep_steps() # This function is defined in helpers_a
Although I agree with comments that passing those values would be way simpler. Also due to python dynamic nature you can just simply set those attributes on the module itself. This method is way simpler but you need to remember to clean up after your done which previous method does for you with context mananger.
import helpers.helper_a
import pandas as pd
query_train_data = "select * from train;"
df_train_dataset = pd.read_sql(query_train_data, con=engDps1000)
query_test_data = "select * from test;"
df_test_dataset = pd.read_sql(query_test_data, con=engDps1000)
helpers.helper_a.df_train_data = df_train_dataset
helpers.helper_a.df_test_data = df_test_dataset
helpers.helper_a.data_prep_steps() # This function is defined in helpers_a
I am trying to patch the fun_1 function from the worker_functions dictionary and I seem to be struggling:
cli.py:
import sys
from worker_functions import (
fun_1,
fun_2,
fun_3,
)
FUNCTION_MAP = {
'run_1': fun_1,
'run_2': fun_2,
'run_3': fun_3,
}
def main():
command = sys.argv[1]
tag = sys.argv[2]
action = FUNCTION_MAP[command]
action(tag)
I've tried mocking cli.fun_1 and cli.main.action and cli.action but this is leading to failure.
test_cli.py:
from mock import patch
from cli import main
def make_test_args(tup):
sample_args = ['cli.py']
sample_args.extend(tup)
return sample_args
def test_fun_1_command():
test_args = make_test_args(['run_1', 'fake_tag'])
with patch('sys.argv', test_args),\
patch('cli.fun_1') as mock_action:
main()
mock_action.assert_called_once()
Do I seem to be missing something?
You'll need to patch the references in the FUNCTION_MAP dictionary itself. Use the patch.dict() callable to do so:
from unittest.mock import patch, MagicMock
mock_action = MagicMock()
with patch('sys.argv', test_args),\
patch.dict('cli.FUNCTION_MAP', {'run_1': mock_action}):
# ...
That's because the FUNCTION_MAP dictionary is the location that the function reference is looked up.
I have a file named
a.py
file = "/home/test/abc.txt"
I am working on creating a unittest for another file which takes value of this file variable from a.py
How can I mock this variable name to any dummy file for example?
file = "/tmp/a.txt"
Use mock.patch:
import mock
#mock.patch('a.file', '/tmp/a.txt')
def test_a():
assert thing_that_uses_a_file == '/tmp/a.txt'
#tbm 's answer is work for me, on python 2.7
config.py
SERVICE_REQUIRED = [
("lrc:/etc/rc2_d/S47pppd", "legacy_run"),
("lrc:/etc/rc2_d/S89PRESERVE", "legacy_run"),
("lrc:/etc/rc2_d/S99sysinfo", "legacy_run"),
("lrc:/etc/rc2_d/S99tcpwindow", "legacy_run"),
("lrc:/etc/rc3_d/S99cpupool", "legacy_run"),
("lrc:/etc/rc3_d/S99logparse", "legacy_run"),
("lrc:/etc/rc3_d/S99nicmon", "legacy_run"),
("lrc:/etc/rc3_d/S99nwmond", "legacy_run")
]
file_a.py
from config import SERVICE_REQUIRED
def demo_func():
for name, state in SERVICE_REQUIRED:
print name, state
...
test_file_a.py
...
class TestFileA(unittest.TestCase):
#mock.patch('file_a.SERVICE_REQUIRED', [
('svc:/system/console-login:vt2', 'online'),
('svc:/system/system-log:rsyslog', 'online'),
('svc:/network/socket-config:default', 'disabled'),
('dump', 'legacy_run'),
('firewall', 'disabled'),
("/'; echo hello;'", 'online')
])
def test_demo_func(self):
print SERVICE_REQUIRED
In your specific case, why not just import a and then a.file = "/tmp/a.txt" ?
Which version of Python are you on? Python 3.x has unittest.mock which is backported to 2.x on pypi.
Anyway, if you are trying to create a context specific mock:
>>> from mock import Mock
>>>
>>> # applies to module imports but doing it as a class here
... class A(object):
... file = 'xyz'
...
>>> some_a = Mock(file='abc')
>>> some_a.file
'abc'
>>>
>>> actual_a = A()
>>> actual_a.file
'xyz'
>>>
>>>
>>> def some_test():
... A = Mock(file='abc')
... assert A.file == 'abc'
... assert A.file != 'xyz'
...
>>> some_test()
>>> # no assertion error
Are you trying to mock it at import time? Based on another SO answer:
>>> import sys
>>> sys.modules['A'] = Mock(file='abc')
>>> import A
>>>
>>> A.file
'abc'
>>> mocked_a = A
>>> mocked_a.file
'abc'
>>>
I have two Scripts. Script 1 is titled schemeDetails.The second script is a test script called temporaryFile that creates a schemeSetup object using the schemeSetup class which is within schemeDetails. Everything is hunky dory up to the point where I try to acess the method insertScheme which is within the schemeSetup Class.
I have imported the schemeDetails script using the following:
import schemeDetails
reload(schemeDetails)
from schemeDetails import *
I can create the schemeDetails Object and access its attributes
d = schemeDetails.schemeSetup() -- fine
print(d.scheme) -- fine
d.insertScheme() -- throws error
but trying to call the insertScheme function throws an error
I don't know why this is happening as the import statement looks above board to me. Any advice appreciated
from sikuli import *
import os
class schemeSetup(object):
#Uses default values
def __init__(
self,
scheme = "GM",
cardNumber = "1234567A",
month = "December",
year = "2015",
setSchemeAsDefault = True):
#Provide default values for parameters
self.scheme = scheme
self.cardNumber = cardNumber
self.month = month
self.year = year
self.setSchemeAsDefault = setSchemeAsDefault
#schemeDetails is not a sub
# class of patient. It is simply defined within the patient class
# - there is a huge difference.
#====================================================#
#schemeDetails Function
def insertScheme(self):
print("insertScheme Works")
#r = Regions()
#r.description("Patient Maintenance", "schemeDetails")
#myRegion = r.createRegion()
#myRegion.highlight(1)
#click(myRegion.find(insertSchemeButton))
#click(myRegion.find(blankSchemeEntry))
#type(self.scheme + Key.ENTER + Key.ENTER)
#type(self.cardNumber + Key.ENTER)
#type(self.month + Key.ENTER)
#type(self.year + Key.ENTER)
#type(" ")
#unticks HT link, HT linking should be in a separate function
#====================================================#
#schemeDetails Function
def editScheme(self):
print("editScheme Works")
#====================================================#
def deleteScheme(self):
pass
#====================================================#
It may be of importance that calling either of the bottom functions does not produce an error. If I put print("Hello") under editScheme, and call that method using s.editScheme the program compiles but I get no output. If I run print(s.editScheme) it returns None
Well it seems to be fixed now after changing the import format to this
import schemeDetails
from schemeDetails import schemeSetup
s = schemeDetails.schemeSetup()