I'm a little confused about how importing works. Assume:
package/
__init__.py
file1.py
In __init__.py:
from file1 import AClass
__version__ = '1.0'
In file1.py:
Class AClass(object):
def bar():
# I want to use __version__here, but don't want to pass
# it through the constructor. Is there any way?
pass
If I use from . import __version__ in file1.py it just says ImportError: cannot import name __version__.
You've got a circular dependency because both files try to import each other. Move __version__ to a separate module, say package/version.py, then import that in both others with
from .version import __version__
Try:
__version__ = '1.0'
from file1 import AClass
You need to assign the constants before you import the module so that it'll be in place when you try to import it.
EDIT: larsmans suggestion to avoid the circular dependency is a good idea.
Related
I have a config var in the main class that I use a lot and I also pass it to some other instances that pass it to other classes, and so on.
I need a solution that can be used globally, without the need of passing an instance of the config file, and that I can modify as needed (not const).
something that only requires import anywhere and that the data will be the same and up to date.
In Java, I know that I can Autowired and I know that behind the scenes I'll use the exact same instance.
What solution does Python have?
example
util.py
config = None
setConfig(self, config):
self.config = config
getConfig(self):
return self.config
file1.py
....
import util
util.setConfig(4)
file2.py
import util
util.getConfig()
file3.py
import util
util.setConfig(8)
file4.py
import util
util.getConfig()
main.py
file1()
file2() # ==4
file3()
file4() # ==8
file2() # ==8
Thanks
Is it possible to mock a module in python using unittest.mock? I have a module named config, while running tests I want to mock it by another module test_config. how can I do that ? Thanks.
config.py:
CONF_VAR1 = "VAR1"
CONF_VAR2 = "VAR2"
test_config.py:
CONF_VAR1 = "test_VAR1"
CONF_VAR2 = "test_VAR2"
All other modules read config variables from the config module. While running tests I want them to read config variables from test_config module instead.
If you're always accessing the variables in config.py like this:
import config
...
config.VAR1
You can replace the config module imported by whatever module you're actually trying to test. So, if you're testing a module called foo, and it imports and uses config, you can say:
from mock import patch
import foo
import config_test
....
with patch('foo.config', new=config_test):
foo.whatever()
But this isn't actually replacing the module globally, it's only replacing it within the foo module's namespace. So you would need to patch it everywhere it's imported. It also wouldn't work if foo does this instead of import config:
from config import VAR1
You can also mess with sys.modules to do this:
import config_test
import sys
sys.modules["config"] = config_test
# import modules that uses "import config" here, and they'll actually get config_test
But generally it's not a good idea to mess with sys.modules, and I don't think this case is any different. I would favor all of the other suggestions made over it.
foo.py:
import config
VAR1 = config.CONF_VAR1
def bar():
return VAR1
test.py:
import unittest
import unittest.mock as mock
import test_config
class Test(unittest.TestCase):
def test_one(self):
with mock.patch.dict('sys.modules', config=test_config):
import foo
self.assertEqual(foo.bar(), 'test_VAR1')
As you can see, the patch works even for code executed during import foo.
If you want to mock an entire module just mock the import where the module is used.
myfile.py
import urllib
test_myfile.py
import mock
import unittest
class MyTest(unittest.TestCase):
#mock.patch('myfile.urllib')
def test_thing(self, urllib):
urllib.whatever.return_value = 4
Consider this following setup
configuration.py:
import os
class Config(object):
CONF_VAR1 = "VAR1"
CONF_VAR2 = "VAR2"
class TestConfig(object):
CONF_VAR1 = "test_VAR1"
CONF_VAR2 = "test_VAR2"
if os.getenv("TEST"):
config = TestConfig
else:
config = Config
now everywhere else in your code you can use:
from configuration import config
print config.CONF_VAR1, config.CONF_VAR2
And when you want to mock your coniguration file just set the environment variable "TEST".
Extra credit:
If you have lots of configuration variables that are shared between your testing and non-testing code, then you can derive TestConfig from Config and simply overwrite the variables that need changing:
class Config(object):
CONF_VAR1 = "VAR1"
CONF_VAR2 = "VAR2"
CONF_VAR3 = "VAR3"
class TestConfig(Config):
CONF_VAR2 = "test_VAR2"
# CONF_VAR1, CONF_VAR3 remain unchanged
If your application ("app.py" say) looks like
import config
print config.var1, config.var2
And gives the output:
$ python app.py
VAR1 VAR2
You can use mock.patch to patch the individual config variables:
from mock import patch
with patch('config.var1', 'test_VAR1'):
import app
This results in:
$ python mockimport.py
test_VAR1 VAR2
Though I'm not sure if this is possible at the module level.
I'm a newbie in using Python.
What I need is simple: import a module dynamically.
Here is my little test:
#module
class Test:
def func(self, id, name):
print("Your ID: " + str(id) + ". Your name: " + name)
return
I put this class in a file named my_module.py and the path of the file is: c:\doc\my_module.py.
Now I create a new python project to import the file above.
Here is what I do:
import sys
module = sys.path.append(r'c:\doc\my_module.py')
myClass = module.__class__
print(myClass)
However, I got this result:
<class 'NoneType'>
Why can't I get Test?
Is it because the way to import a module is wrong or because I need to do some config to import a module?
You're doing it wrong. Here's how you should import your module with sys.path.append:
import sys # import sys
sys.path.append(r'c:\doc\') # add your module path to ``sys.path``
import my_module # now import your module using filename without .py extension
myClass = my_module.Test # this is how you use the ``Test`` class form your module
try this:
import sys
sys.path.append(r'c:\doc\') # make sure python find your module
import my_module # import your module
t = my_module.Test() # Initialize the Test class
t.func(1, 'test') # call the method
The way to import a module is through the import command. You can specify the path with sys as a directory. You also need to instantiate the class within the module (through the my_module.Test()). See the following:
import sys
sys.path.append(r'c:\doc\\')
import my_module
myObj = my_module.Test()
myClass = myObj.__class__
print(myClass)
I tried to break up one large file into three smaller files for organization purposes and now nothing works. I'm sure the problem is with my import statements. Main.py imports Members.py and Members imports from RouteTools. However, even after including
import routeTools
...routeTools.tool()
In Members.py, it doesn't work after
Main.py
import Members
...Members.stuff()
I even tried putting
import routeTools
at the top of Main.py as well. What am I doing wrong or is there a better way to organize one file into multiple modules? Thanks.
Edit: "nothing works" = NameError: global name 'tool' is not defined when running routeTools.tool() from Members.py after it has been imported into Main.py
Here is my code:
import routetools
class Member(object):
def __init__(self, fields, scouts, id):
...
self.routes = [routeTools.Route(s) for s in self.scouts ]
...
And this is called in Main.py:
import Members
import routeTools
...
member = Members.Member(self.fields, self.scouts, i)
routeTools contains:
class Route(object):
...
I have a directory structure like this
main.py
markdown-extensions/
__init__.py
doc_extension.py
Here is my doc_extension.py (it's intended to be a bare bones markdown post processor):
from markdown.postprocessors import Postprocessor
class DocsPostProcessor(Postprocessor):
def run(self, text):
return "<h1>hello world</h1>"
class DocsExtension:
def extendMarkdown(self,md):
postProcessor = DocsPostProcessor()
postProcessor.md = md
md.postprocessors.add(postProcessor)
How do I go about importing it into my main.py? I've tried variations on the following to no avail:
import markdown-extensions.doc_extension
import markdown-extensions.*
import markdown-extensions.doc_extension
The - sign is not a valid character for a Python name (also known as identifier), whether it is a module or not. See here.
from markdown-extensions.doc_extension import *
but rather be explicit, as * will import all global variables, methods and classes. So:
from markdown-extensions.doc_extension import DocsPostProcessor, DocsExtension
*edit
And yes besides that you can't have "-"s, I mistook it for a "_".