In MicroPython I created two modules 'mod_a' and 'mod_b'.
I am trying to grab functionality from one to the other and the other way around.
|mod_a
| | foo.py
| | __init__.py
|mod b
| | baa.py
| | __init__.py
foo.py
# necessary to grab module mod_b
import sys
sys.path.append('.')
from mod_b import Baa
class Foo:
b = Baa()
b.printer()
def drinker(self):
print('Drinking')
baa.py
import sys
# not working
# from mod_a import Foo
class Baa:
def printer(self):
print('Printer')
print('b.Baa', sys.path) => ['.' ...]
# ==> how to get this working
# a = Foo()
# a.drinker()
So far I tried
import sys
import os
if '/' not in sys.path:
sys.path.insert(0, os.getcwd())
sys.path.insert(1, '.')
sys.path.insert(2, '/mod_b')
sys.path.insert(2, '/mod_a')
sys.path.insert(2, '.mod_b')
sys.path.insert(2, '.mod_a')
and
sys.modules.get('.mod_b')
Please note that the following code only solves the import problem.
The code still has a circular import problem.
ImportError: cannot import name 'Baa' from partially initialized
module 'mod_b.baa' (most likely due to a circular import)
(C:\Users\Guest\test\.\mod_b\baa.py)
When initializing class Foo, it needs to call Baa.printer() which calls a = Foo() need the uninitialized class Foo, you need to fix that later.
foo.py
import sys
sys.path.insert(0,'.')
from mod_b.baa import Baa
class Foo:
b = Baa()
b.printer()
def drinker(self):
print('Drinking')
baa.py
import sys
sys.path.insert(0,'.')
from mod_a.foo import Foo
class Baa:
def printer(self):
print('Printer')
a = Foo()
a.drinker()
Circular imports are not supported in MicroPython up to v1.18.
MicroPython is largely based on Python 3.4 and differences to Python 3.5 are documented including circular imports.
Related
How do I make import pkg fail in moduleA.py? I can patch pkg to fail if something's imported from it, but not otherwise:
# test.py
import os
import moduleA
from unittest.mock import patch
from importlib import reload
#patch.dict('sys.modules', pkg=os)
def test_mock():
reload(moduleA)
# moduleA.py
import pkg # make this fail
from pkg import sum # this does fail
Live example
This is a bit more complicated. You have to make sure that reloading fails - this can be done by adding a class that implements find_spec. Second, you have to remove an already loaded package from sys.modules - otherwise this will be used on reload:
import sys
from importlib import reload
import pytest
import moduleA
class ImportRaiser:
def find_spec(self, fullname, path, target=None):
if fullname == 'pkg':
# we get here if the module is not loaded and not in sys.modules
raise ImportError()
sys.meta_path.insert(0, ImportRaiser())
def test_import_error():
if 'pkg' in sys.modules:
del sys.modules['pkg']
with pytest.raises(ImportError):
reload(moduleA)
Why the 1st case succeed. But the 2nd case failed AssertionError: Expected 'Jenkins' to have been called.
util.py
from jenkinsapi.jenkins import Jenkins
import os
class Util:
#staticmethod
def rm(filename):
os.remove(filename)
#staticmethod
def get_jenkins_instance():
Jenkins(
'host',
username='username',
password='password',
ssl_verify=False,
lazy=True)
test_util.py
import pytest
from util import Util
def test_util_remove(mocker):
m = mocker.patch('os.remove')
Util.rm('file')
m.assert_called()
def test_util_get_instance(mocker):
m = mocker.patch('jenkinsapi.jenkins.Jenkins')
Util.get_jenkins_instance()
m.assert_called()
Two files are in the same root folder.
Not very clear what's the differences between Python's import and from ... import ....
But if you use from ... import ..., the mock looks as following:
util.py
from jenkinsapi.jenkins import Jenkins # <-- difference A
class Util:
#staticmethod
def get_jenkins_instance():
Jenkins(
'host',
username='username',
password='password',
ssl_verify=False,
lazy=True)
test_util.py
import pytest
from util import Util
def test_util_get_instance(mocker):
m = mocker.patch('util.Jenkins') # <-- difference B
Util.get_jenkins_instance()
m.assert_called()
If you use import directly, the mock looks as following:
util.py
import jenkinsapi.jenkins # <-- difference A
class Util:
#staticmethod
def get_jenkins_instance():
jenkinsapi.jenkins.Jenkins(
'host',
username='username',
password='password',
ssl_verify=False,
lazy=True)
test_util.py
import pytest
from util import Util
def test_util_get_instance(mocker):
m = mocker.patch('jenkinsapi.jenkins.Jenkins') # <-- difference B
Util.get_jenkins_instance()
m.assert_called()
========== Edit (Aug 5, 2022) ==========
Here's the reason why patched like this.
a.py
-> Defines SomeClass
b.py
-> from a import SomeClass
-> some_function instantiates SomeClass
Now we want to test some_function but we want to mock out SomeClass using patch(). The problem is that when we import module b, which we will have to do then it imports SomeClass from module a. If we use patch() to mock out a.SomeClass then it will have no effect on our test; module b already has a reference to the real SomeClass and it looks like our patching had no effect.
The key is to patch out SomeClass where it is used (or where it is looked up ). In this case some_function will actually look up SomeClass in module b, where we have imported it.
I made a module that makes a linear regression model and draws a graph.
So the module needs to import some packages such as sklearn and matplotlib.
And I want to import this module to another python file and use it.
I think either of the two python files needs to import the above packages..
which of them needs to import?
In below case, my_module.py should import LinearRegression? or my_module2.py should?
ex)
my_module.py
---------------------------
**from sklearn.linear_model import LinearRegression**?
class myclass:
def a (self):
lr = LinearRegression()
my_module2.py
------------------------------
**from sklearn.linear_model import LinearRegression**?
from my_module import myclass
i = myclass()
i.a()
First you import it in my_module.py, then import * from my_module.py to my_module2.py.
my_module.py
---------------------------
from sklearn.linear_model import LinearRegression
class myclass:
def a (self):
lr = LinearRegression()
my_module2.py
------------------------------
from my_module import *
i = myclass()
i.a()
I have a program that is laid out like the following:
test\test.py
test\modules\base.py
test\modules\blah.py
I need to load modules by name. Each module implements a class with the same methods, so I load them into a dictionary so that I can reference them as needed. I'm getting the follow error trying to do a relative import.
File "modules/blah.py", line 1, in <module>
from .base import BaseModule
ImportError: attempted relative import with no known parent package
Is there a way to use relative imports from code imported using importlib?
I'm using Python 3. The following is a simple example showing this error...
test\test.py:
#!/usr/bin/env python
import importlib
class Test():
def __init__(self):
spec = importlib.util.spec_from_file_location("blah", "modules/blah.py")
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
def main():
t = Test()
if __name__ == '__main__':
main()
test\modules\base.py:
class BaseModule():
modulename = "base"
def __init__(self,name):
print("Initializing module %s" % (self.modulename))
test\modules\blah.py:
from .base import BaseModule
class BlahModule(BaseModule):
modulename = "blah"
Adding the following code should help:
import os
import sys
module_path = "modules/blah.py"
module_dir = os.path.dirname(module_path)
if module_dir not in sys.path:
sys.path.append(module_dir)
# do actual import of module here
I'm working on a GUI app. Let's say that I have a file main.py which is in the root directory and I want to import widgets like this:
from widgets import FancyWindow, ColorPicker
# ...
And my app is structured like so:
| main.py
+ widgets/
| __init__.py
| fancy_window.py
| color_picker.py
...
IIRC, I would have to import classes from the other modules like so:
from widgets.color_picker import ColorPicker
from widgets.fancy_window import FancyWindow
So my question is if there is something I can do in widgets/__init__.py to make it so that I can do imports in the way I want to?
You actually have it there already, just make your __init__.py have those two lines:
from widgets.color_picker import ColorPicker
from widgets.fancy_window import FancyWindow
Anything that you import (and any other symbols you define) in __init__.py will then be available.
E.g. if you put:
apple = 5
in __init__.py you could also do: from widgets import apple. No magic :)
In __init__.py you can import the modules, then export them:
from fancy_window import FancyWindow
from color_picker import ColorPicker
__all__ = [FancyWindow, ColorPicker]
Now, you can do the following:
from widgets import * # Only imports FancyWindow and ColorPicker
from widgets import FancyWindow
from widgets import ColorPicker
import widgets
color_picker = widgets.ColorPicker()
The best way would be to use __init__.py to perform setups needed for the package.
# __init__.py
from fancy_window import FancyWindow
from color_picker import ColorPicker
Then in main.py you can perform imports directly.
# main.py
from widgets import FancyWindow, ColorPicker
A more convenient way to package everything in __init__.py
# __init__.py
from fancy_window import *
from color_picker import *
yes, by adding the public variables of the other modules to __all__ in __init__.py
see https://docs.python.org/3/reference/simple_stmts.html#import