Global variable sharing across different modules behave differently - python

In config.py, I have:
config = 0
#config = []
def init_config():
global config
config = 1
#config.append("1")
print("init", config)
In main.py, I have:
from config import init_config
from config import config
def main():
init_config()
print("main", config)
if __name__ == '__main__':
main()
And both the config.py and the main.py in the same directory. After running python main.py, I got:
init 1
main 0
But if I use the comment lines in the config.py instead, I got:
init ['1']
main ['1']
So why does the difference happen? (Python 3.5.5)

Once imported from config.py, the variable config becomes a separate copy of config.config that lives in main.py's namespace. You should import config as a module and then access the variable config as an attribute to the module config instead:
import config
def main():
config.init_config()
print("main", config.config)
if __name__ == '__main__':
main()

Related

Flask can't import application from root directory to test

I have the following folder structure:
In the application.py file I am using a factory method create_app():
# application.py
def create_app():
flask_app = Flask(__name__)
return flask_app
app = create_app()
# --- Import Routes ---
from src.routes import *
if __name__ == "__main__":
app.run()
In the test folder I have the following code
# /tests/test.py
from application import create_app
def test_root_route():
flask_app = create_app()
with flask_app.test_client() as test_client:
response = test_client.get('/')
assert response.status_code == 200
Now I get the following error when running the test:
from application import create_app
ModuleNotFoundError: No module named 'application'
Why can't I import the method from the application.py file?
Unfortunately I can't change the folder structure as the application.py needs to be in root so it can be run by our server.
Please share folder structure properly , looking at it currently seems like while running tests.py , the application.py file is in the directory above the current one .
Also you can try to make a test.py where apllication.py is located. Then import the tests you've written in test directory.
try using from .application import with and __init__.py file in the root file
Python has a lot of problems with sibling imports

Initialize module only once on imports from multiple files

I have multiple python scripts, like this:
utils.py
module1.py
module2.py
module3.py
main.py
...
In utils.py:
import some_lib
role_id = "some_key_1"
secret_id = "some_key_2"
def initialize():
real_key = some_web_request(role_id, secret_id)
some_lib.init(real_key)
# define some other functions using some_lib
In module1.py, module2.py, module3.py:
import utils
# define some other functions using functions in utils.py
In main.py:
import module1
import module2
import module3
# do something
I want to run utils.initialize() only once for initializing some_lib. However, due to how import works in python, if I put initialize() on global area in utils.py then it will run on every import statement run.
I can implement this like this, in utils.py
import some_lib
initialized = False
def initialize():
# same as above
if not initialized:
initialize()
initialized = True
Is this a good practice? Is there better or elegant way to implement this?

Why do so many people put the app.run() in flask sites into a __name__ == "__main__" condition?

I know what if __name__ == "__main__" does and use it, but why do so many people and the documentation put the " app.run() " function of flask in this condition?
This is because there are certain situation where you have to access certain variables for example when you have a sqlalchemy database and If you want create tables. You have to do
from app import db
In such situation you app will run
Also when you move to production you don't need run and app is called from elsewhere if you add if __name__ == "__main__" part run will not be called unnecessarly.
This will ensure that when this module is imported, it won't run the code within
if __name__ == "__main__":
Your name == "main" when you run the .py directly.
ex:
foo.py
import bar
print("This is foo file)
now the inverse:
bar.py
import foo
def main():
print(This is bar file)
print(__name__)
if __name__ == "__main__":
main()
(running the bar.py file)
python bar.py
This is foo file
This is bar file
"__main__"
(running the foo.py file)
python foo.py
this is foo file
I know others will comment and provide a more thorough answer. But this is one way of looking at it.
Cheers.

Mocking __main__

I would like to ensure with tests that:
- the application cannot be imported
- the application can be started as a real application (i.e: python src.py)
I'm interested about that, why the following is not working:
src.py
class A:
def x(self):
print('this is x')
if __name__ == '__main__':
A().x()
test.py (snippet)
class Test(unittest.TestCase):
#mock.patch('src.A.x')
def test_main(self, mock_x):
import src
mock_x.assert_any_call()
This test fails... why?
Because the name of the module when imported is src, not __main__.
The easiest solution would be to move that code into a function:
def main():
A().x()
if __name__ == '__main__':
main()
and in your test, you would invoke src.main()
#mock.patch('src.A.x')
def test_main(self, mock_x):
import src
src.main()
mock_x.assert_any_call()
To test that a module is not importable you do not need to use mocks.
See assertRaises.
Just check if an error is thrown on import od module.
with self.assertRaises(...):
...

Importing values in config.py

I wanted to mix a config.py approach and ConfigParser to set some default values in config.py which could be overridden by the user in its root folder:
import ConfigParser
import os
CACHE_FOLDER = 'cache'
CSV_FOLDER = 'csv'
def main():
cp = ConfigParser.ConfigParser()
cp.readfp(open('defaults.cfg'))
cp.read(os.path.expanduser('~/.python-tools.cfg'))
CACHE_FOLDER = cp.get('folders', 'cache_folder')
CSV_FOLDER = cp.get('folders', 'csv_folder')
if __name__ == '__main__':
main()
When running this module I can see the value of CACHE_FOLDER being changed. However when in another module I do the following:
import config
def main()
print config.CACHE_FOLDER
This will print the original value of the variable ('cache').
Am I doing something wrong ?
The main function in the code you show only gets run when that module is run as a script (due to the if __name__ == '__main__' block). If you want that turn run any time the module is loaded, you should get rid of that restriction. If there's extra code that actually does something useful in the main function, in addition to setting up the configuration, you might want to split that part out from the setup code:
def setup():
# the configuration stuff from main in the question
def main():
# other stuff to be done when run as a script
setup() # called unconditionally, so it will run if you import this module
if __name__ == "__main__":
main() # this is called only when the module is run as a script

Categories

Resources