Package python codes which uses __import__ function - python

My directory structure is:
./
├── foo
│   ├── bar.py
│   ├── foo.py
│   └── __init__.py
└── main.py
with:
bar.py:
def get_data():
return 'ha'
foo.py:
class foo:
def __init__(self):
self.lib = __import__('bar', fromlist=['bar'])
self.data = self.lib.get_data()
def print_data(self):
print(self.data)
if __name__=='__main__':
f = foo()
f.print_data()
__init__.py:
from foo import foo
and main.py:
from foo import foo
a = foo()
a.print_data()
Running python foo.py I get ha correctly, but running python main.py I get the following message:
Traceback (most recent call last):
File "main.py", line 3, in <module>
a = foo()
File ".../foo/foo.py", line 3, in __init__
self.lib = __import__('bar')
ImportError: No module named bar
My requirements are 1) making foo to work like a package, 2) using __import__ in foo.py's __init__ function instead of import in the first line of foo.py.
I changed line 3 of foo.py to self.lib = __import__('foo.bar', fromlist=['bar']), and then got the correct answer. But that is not I want, since running python foo.py will lead to a failure and that is not a package solution when the whole directory ./ become another package. It seems an import path problem that I cannot figure out.

Changing foo.py to that makes it work correctly:
import importlib
class foo:
def __init__(self):
self.lib = importlib.import_module('foo.bar')
self.data = self.lib.get_data()
def print_data(self):
print(self.data)
if __name__=='__main__':
f = foo()
f.print_data()

Related

How do I specify inheritence behavior on initialization of an object in Python?

I'm trying to write a class with a method that behaves differently based on data given on the initialization of the object. I want to pass this object code to run stored in a different file. The behavior should be as follows
foo = Myclass(config="return_a.py")
bar = Myclass(config="return_b.py")
foo.baz() # returns a
bar.baz() # returns b
# where return_a.py and return_b.py are files in the directory
The closest I've come to fixing it so far is using exec and having my configured python write to a file which I then read from. I don't know how I'd do this in memory
You can use importlib to import the files dynamically.
Let's say your project has the structure:
.
├── main.py
├── return_a.py
└── return_b.py
you can put in main.py your code:
import importlib
class Myclass:
def __init__(self, config) -> None:
config = importlib.import_module(
config)
self.baz = config.baz
foo = Myclass(config="return_a")
bar = Myclass(config="return_b")
foo.baz()
bar.baz()
This is assuming you have the function baz your return_a and return_b files. For example:
#return_a.py
def baz():
print("I am A")
#return_b.py
def baz():
print("I am B")
Now if you execute main.py you will get:
I am A
I am B

Import in a module fails because __name__ is __main__

Here is my project structure:
Project
main.py
myPackage/
subfolder1/
__init__.py
script11.py
script12.py
subfolder2/
__init__.py
script2.py
__init__.py
in main.pyI import script2.py the following way :
from myPackage.subfolder2 import script2 as script2
then, I call a function from script2.py in main.py with :
bar = script2.foo()
and in script2 I need to import a function from script1 :
from ..subfolder1.script11 import my_function
and it breaks with the error :
attempted relative import with no known parent package
I have inspected the __name__ variable and indeed it has the value __main__. How can I manage that properly ?
All you should have to do is change your import in main.py to from myPackage.subfolder2 import script2. I set up a directory and some files in this way, using that import, and the script runs as expected:
main.py
myPackage/
subfolder1/
script11.py
subfolder2/
script2.py
script11.py
def bar():
return 10
script2.py
from ..subfolder1.script11 import bar
def foo():
x = bar()
print('foo is', x)
main.py
from myPackage.subfolder2 import script2 as s2
s2.foo()
Running:
>>> py .\main.py
foo is 10
Some notes:
I'm assuming Python 3, since Python 2 was deprecated beginning of this year
In Python 3, the __init__.py files aren't necessary to make a package, but having them doesn't hurt anything. You can leave them out if you want.
The as script2 part in from subfolder2 import script2 as script2 is redundant. It will already be imported as script2.

Override function in a module with complex file tree

I have a module module containing 2 functions a and b splited into 2 different files m1.py and m2.py.
The module's file tree:
module/
__init__.py
m1.py
m2.py
__init__.py contains:
from .m1 import a
from .m2 import b
m1.py contains:
def a():
print('a')
m2.py contains:
from . import a
def b():
a()
Now, I want to override the function a in a main.py file, such that the function b uses the new function a. I tried the following:
import module
module.a = lambda: print('c')
module.b()
But it doesn't work, module.b() still print a.
I found a solution, that consists in not importing with from . import a but with import module.
m2.py becomes:
import module
def b():
module.a()

monkeypatch a function that needs to be imported in conftest

I'm trying to use pytest.monkeypatch to patch a function I've defined in another file. I then need to patch a function from another that relies on this first monkeypatch. Here's a simple example
# class_def.py
class C:
def __init__(self):
# Normally, there is something that makes self.p
# that will use a file that will exist on production
raise FileNotFoundError
def factory():
print('in factory')
return C()
----
# function_def.py
from .class_def import factory
foo = factory()
def bar():
return 0
----
# conftest.py
from unittest.mock import MagicMock
import pytest
import playground.class_def
#pytest.fixture(autouse=True)
def patch_c(monkeypatch):
fake_c = MagicMock()
def factory():
print('in monkey factory')
return fake_c
monkeypatch.setattr('playground.class_def.factory', factory)
from .function_def import bar
# Then I would patch bar
And running pytest . will fail with FileNotFoundError. I believe this happens because I am calling foo = factory() at the top level of function_def.py. I expected this not to happen because I am patching factory before doing this import, but that doesn't seem to be happening. Is there a way to ensure this monkeypatch.setattr will go into effect before from .function_def import bar in conftest.py?
Also, the file structure looks like
playground
|--- __init__.py
|--- conftest.py
|--- class_def.py
|--- function_def
You have direct access to the attribute you want to change. You don't need monkeypatch at all.
Here's my tree :
$ tree .
.
├── a.py
├── b.py
├── __init__.py
└── test_a.py
0 directories, 4 files
a.py
class A:
def __init__(self):
raise Exception
def factory():
return A()
b.py
import a
print(a.factory())
test_a.py
import a
def test_a():
def fake_factory():
return 'A'
a.factory = fake_factory
import b
And it works:
$ pytest
=============================================================================================== test session starts ===============================================================================================
platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0
rootdir: /home/ahorgnies/test/monkeypatch, inifile:
plugins: remotedata-0.2.1, openfiles-0.3.0, doctestplus-0.1.3, arraydiff-0.2
collected 1 item
test_a.py . [100%]
============================================================================================ 1 passed in 0.01 seconds =============================================================================================

Python3 relative imports

I'm tired of reading one-off use cases of relative imports so I figured I'd as a question to get an example of how to do a relative import from a directory above and bellow, for both importing module functions and class objects.
directory structure:
.
├── lib
│   ├── __init__.py
│   └── bar.py
└── src
├── main.py
└── srclib
├── __init__.py
└── foo.py
bar.py
def BarFunc():
print("src Bar function")
class BarClass():
def __inti__(self):
print("src Bar Class")
def test(self):
print("BarClass working")
foo.py
def FooFunction():
print("srclib Foo function")
class FooClass():
def __init__(self):
print("srclib Foo Class")
def test(self):
print("FooClass working")
Question: What is the syntax in python 3 to import for these use cases?
main.py
# What is the syntax to import in python 3?
# I want to be able to call FooFunc()
foo.FooFunc()
# I want to be able to create a FooClass() object
foo_class = foo.FooClass()
foo_class.test()
# I want to be able to call FooFunc()
bar.BarFunc()
# I want to be able to create a BarClass() object
bar_class = bar.BarClass()
bar_class.test()
It all depends on where you start your python interpreter from. In your case, I would suggest you to start the interpreter from your project's root directory while making the following changes:
In file src/srclib/__init__.py add:
from . import foo
The reason for doing this is to explicitly state in your __init__.py file what to import from your module.
In your main.py file, add the following:
from lib import bar
from src.srclib import foo
Hope this helps!

Categories

Resources