Python best module import practise - python

I have a python module mymodule.py:
def auth():
'''Authorize and generate a JSON file'''
return j
j = auth()
def get_value(key):
'''Takes the key and return value from JSON'''
value = j[key]
return value
I have a program where I use this module myprogram.py:
import mymodule
keys = [1,2,3,4,5]
def simple_program(keys):
# mymodule.auth() should I place it here?
for key in keys:
value = mymodule.get_value(key)
return value
So the goal is to call mymodule.auth() once, every time I run simple_program to refresh the JSON file. I don't know how to achieve this. Because myprogram.py is also a module and I call simple_program() from another .py file. So where do I place mymodule.auth()? Is it ok to place mymodule.auth() inside simple_program?

The instant you import mymodule the code below runs
j = auth()
which is why when you call mymodule.get_value() it works. This causes J to be a singleton in the global space. Everytime you import this, auth() will run again. This could be bad.
What you could do is this:
def auth():
'''Authorize and generate a JSON file'''
return j
j = None
def get_value(key):
global j
'''Takes the key and return value from JSON'''
if not j:
j = auth()
value = j[key]
return value
Now you just need to run get_value() and everything should work fine. No need to execute auth() again.

Your exact use case is a little vague (e.g. simple_program is not the main program but smth like a subroutine? and it is called several times from another py file?), but it seems to me like you should get familiar with classes. I would suggest to implement auth() as a class, e.g. like this:
class MyJson(object):
def __init__(self):
self._json = ... # do authorization and generation here and save the result as member
def get_value(self, key):
value = self._json[key]
return value
Now import and create an object of that class wherever you need it for the first time
from mymodule import MyJson
# ...
my_json = MyJson()
If you only need it to be initialized once, do that in your main program and pass the my_json object as parameter to simple_program (which should possibly also be a class). And then use it like
value = my_json.get_value(key)

Related

How to mock a Python method that is called more than once inside a loop using Pytest

Let's say I have a Python method:
def good_method(self) -> None:
txt = "Some text"
response = self.bad_method(txt)
resources = response["resources"]
print (resources)
while resources:
response = self.bad_method(txt)
resources = response["resources"]
print (resources)
Now let's say I want to write a unit test for it. The bad_method() returns a dictionary and it could get called over and over in the while loop. I have been trying to Mock the bad_method() so it returns a nested dictionary, so the while loop runs once. This is the code:
from unittest.mock import MagicMock
def test_good_method():
dic = {"resources": {"resources": "values"}}
def side_effect():
return dic
self.bad_method() = MagicMock(side_effect=side_effect())
self.good_method()
I expected to first get a {"resources": "values"} printed out, and then a values. But the only thing I get is a resources. What am I doing wrong? How can I achieve what I expect?
def test_good_method():
thing = MyClassContainingGoodAndBadMethod()
thing.bad_method = MagicMock(return_value={"a": "b"})
thing.good_method()
assert thing.bad_method.call_count == 10 # or however many times it is supposed to be called

Declaring a var usable by another function using a import in a secondary script

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)

Python function asserting value over pre declared value

I have a function (func.py). Structure of which look like this:
database = 'VENUS'
def first_function():
print("do some thing")
def second_function():
print("call third function)
third_function()
def third_function(db = database):
print("do some other thing")
I need to import this function and used the inner defined function. But, I want to use a different key for database. Basically, I want to overwrite database = 'VENUS' and use database = 'MARS' while second function call the third function. is there any way to do this?
Just provide the database name as argument
first_function("MARS")
second_function("MARS")
So the problem here, if I understood correctly, is that the default argument for func.third_function is defined at import time. It doesn't matter if you later modify the func.database variable, since the change will not reflect on the default argument of func.third_function.
One (admittedly hacky) solution is to inject a variable using a closure over the imported function. Example:
file.py:
x = 1
def print_x(xvalue = x)
print(xvalue)
Python console:
>>> import file
>>> file.print_x()
1
>>> file.x = 10
>>> file.print_x() # does not work (as you're probably aware)
1
>>> def inject_var(func_to_inject, var):
def f(*args, **kwargs):
return func_to_inject(var, *args, **kwargs)
return f
>>> file.print_x = inject_var(file.print_x, 10)
>>> file.print_x() # works
10
So using the inject_var as written above, you could probably do:
func.third_function = inject_var(func.third_function, "MARS")

Create dictionary dinamically and automatically assign the attributes from evaluations of functions

I'm working with a code that have this appearence:
module.py:
def attribute3():
return "something3"
def attribute2():
return "something2"
def attribute1():
return "something1"
main.py:
from module import attribute1, attribute2, attribute3
def main():
return {
"attribute1": attribute1(),
"attribute2": attribute2(),
"attribute3": attribute3()
}
print main()
And i would like to know if there is any better way to create the dictionary in the main function, without the necessaty of doing "attribute: function()". I'm feeling like i'm repeating my self.
I don't have access to the module.py code, so i can't change to a Class.
I'm using Python 2.5 because this is a legacy software.
Thanks.
You could use getattr and call the arbitrary functions returned.
import some_module
def create_dict(module, names):
resp = {}
for name in names: # Iterate over an arbitrary number of arguments
# Get the function with the name provided and call it,
# setting the response as the value for the name
resp[name] = getattr(module, name)()
return resp
print create_dict(some_module, ['attribute1', 'attribute2', 'attribute3'])
I didn't test this on Python 2.5 but I don't see any reason why it wouldn't work.

Passing values between modules in Python

I want to know how to pass values between modules in Python.
In generate_image.py I have:
def gerenate_image(fr,to,lat1,lon1,lat2,lon2):
output_image_name = spatial_matrix.plot_spatial_data(data_array,data_array.shape[0],data_array.shape[1],float(lon1)/10000,float(lon2)/10000,float(lat1)/10000,float(lat2)/10000,fr,to)
return()
In overlay.py, I want to use the "output_image_name",so I tried:
import generate_image
def overlay():
overlay = generate_image.output_image_name
....
but it didn't work. So how can I retrieve the value of output_image_name?Thanks.
Make your function return something.
def generate_image(fr,to,lat1,lon1,lat2,lon2):
return spatial_matrix.plot_spatial_data(data_array,data_array.shape[0],data_array.shape[1],float(lon1)/10000,float(lon2)/10000,float(lat1)/10000,float(lat2)/10000,fr,to)
Then in the other place import and call the function.
from yourmodule import generate_image
def overlay():
background = generate_image(*args) # Or what ever arguments you want.
In overlay.py:
def gerenate_image(fr,to,lat1,lon1,lat2,lon2):
return spatial_matrix.plot_spatial_data(...)
In generate_image.py:
import generate_image
def overlay():
overlay = generate_image.generate_image(...)

Categories