Python submodule in the same file as module - python

If I currently have a file that is importing:
from foo import f0
from foo.bar import f1
I can create a file foo.py with a function f0 in it to satisfy the first import.
Is there any way to satisfy the second import from within that same file foo.py?

I just wanted to do that same thing. I only found this question, without an actual answer. So, here's what I came up with as a solution:
import sys
def add_submodule(submod):
name = submod.__name__
sys.modules[__name__ + "." + name] = submod(name)
from types import ModuleType
class submod1(ModuleType):
class foo:
pass
class submod2(ModuleType):
class bar:
pass
add_submodule(submod1)
add_submodule(submod2)
In essence, you subclass types.ModuleType to define a module. You then add it manually to sys.modules below the namespace of the current module, as given by __name__.
This is a minimal solution. If one would want to move add_submodule() to a separate stand-alone module for re-usability, it would have to be expanded a bit:
One could not simply use __name__ as this would be the namespace where add_submodule() was defined in. This should work instead:
In the separate module:
def add_submodule(submod, parentname):
name = submod.__name__
sys.modules[parentname + "." + name] = submod(name)
In the actual module:
add_submodule(submod1, __name__)
add_submodule(submod2, __name__)
I fear there's no nicer way of getting the parent's name into the function, though.
Both cases can now be used like so:
In [1]: import submodtest.submod1 as sm1
In [2]: import submodtest.submod2 as sm2
In [3]: sm1. [TAB]
sm1.foo sm1.mro
In [3]: sm2. [TAB]
sm2.bar sm2.mro
EDIT: Pushed the above full example to my Github.

Create a directory called foo
Within this directory, have a file called __init__.py
This effectively creates a module called foo
In this file, store the functions you want bundled with foo
Create a subdirectory of foo, called bar.
Within this directory, have a file called __init__.py
This effectively creates a sub module foo.bar
In this file, store the functions you want bundled with foo.bar

No, you should create a directory named foo as a package.
Click here to read official documentation about The import system

Related

how to get the directory of the file contain a specified function in python

I have 3 file main.py, a.py, b.py and a function func() belongs to either a.py or b.py but I don't know exactly which. The code in the main.py:
from a import *
from b import *
func()
I want to get the directory of the file containing the func(), here is a.py or b.py. So how can I do?
Thanks in advance.
You can use the following code snippet to get file paths of modules containing the desired functions:
file_path = func.__code__.co_filename
dir_path = os.path.dirname(file_path) # since you wanted directory
where func is the function you imported from one of the modules.
Note: This will work for all function objects that are instances of the python function class. For eg, this won't work for functions in numpy, because they are instances of the numpy.ufunc class.
This is why they tell you not to do import *. As a rule of thumb, import only the names you need from any given import, to avoid confusion of this nature.
What you can do is check, in reverse order, which module contains the function you're concerned about. Later imports should overwrite earlier ones with the same name.
if hasattr(b, 'func') and b.func is func:
print(b.__file__)
elif hasattr(a, 'func') and a.func is func:
print(a.__file__)
else:
print("func came from somewhere else")
You can just look, by listing all the functions in a module with:
print(dir(module))
Eg. print(dir(math)) will list all the functions in the math module

How to initialize whole Python module and import all classes without needing to reference module name for every call?

Suppose I have a module named 'module1', which has many classes. I want to use all of their classes in my main controller main.py . I can import whole module with import module1, however, I assume that the class names in 'module1' are unique and I do not want to reference module1 every time I call its function such as module1.class1().
How can I import the whole contents of a module without explicitly having to state class/function names and still being able to refer to them without stating the module name.
Such as:
# module1.py.
class Class1():
pass
class Class2():
pass
# __main__.py
import module1
# The following will not work.
object1 = Class1()
object2 = Class2()
You can use the * import pattern
from module1 import *
This lets you use everything inside that module without referencing it.
from module1 import *
instance = Class1()
However, this is generally discouraged. For reasons why, some additional reading:
Why is "import *" bad?
https://www.geeksforgeeks.org/why-import-star-in-python-is-a-bad-idea/

Import objects from a python module that has the same name as an __init__ import

The project is structured as follows:
dir/
__init__.py
foo.py
Foo.py has a function that uses a local assignment:
"""foo.py"""
BAR = 12345
def foo():
# do something with BAR
My goal is to import the object BAR to use in my own code. However, __init__.py contains an import of bar that masks any attempt to import from foo as a module:
"""__init__.py"""
from dir.foo import foo
So when I interact with the package, I'm only able to see dir.foo as a function definition instead of a module. How can I get access to dir.foo.BAR?
Lame hack:
import sys
foo_module = sys.modules["dir.foo"]
bar = foo_module.BAR
Better way might be to ask the author of dir not to shadow the submodule name within the top-level namespace, for example by avoiding naming a function the same way as the module in which it was defined.

Custom Py Module: Intra Module Importing

I am creating a custom Python module that I wanted to work similarly to something like numpy where most of the functionality can be accessed by calling np.function() or what have you. However, in creating my submodules and __init__.py file, I think that I've run into a circular import reference. Here's what I'm trying to do and the error I'm seeing, any tips to help me get this working the way I envisioned are greatly appreciated:
Let's call the module "foobar" and say I have a folder named "foobar" on the path and in this folder are three py files: "__init__.py", "foo.py", and "bar.py".
An example of submodule 1, "foo.py":
import bar
class Foo():
def __init__(self):
pass
def runfunc(self):
bar.func()
An example of submodule 2, "bar.py":
import foo
def func():
f=foo.F()
An example of __init__.py:
import numpy
from foo import *
from bar import *
__all__ = ['foo', 'bar']
So what I perceive to be my issue is that when foo is imported, it imports bar, which imports foo, which creates a loop (in my mind). I am also confused as to the use of __init__.py if, when it is called and imports other modules they cannot see each other when executing (i.e. I need to import bar into foo even though __init__.py did this).
When I run something from a script trying to import the entire module, I get the error in bar.py "ImportError: cannot import name foo". I am actually also having this issue elsewhere in the same module where I have a file with the base class "Base" and the extended class "Extended" where base.py needs to import extended.py so it can spawn instances of the expanded class and extended.py needs to import base.py so it can inherit the class.
Thanks for any help in advance!

How to import a class from a module from a package dynamically?

This is probably really simple, but I don't understand it. The following works:
foo.py
class Foo:
pass
bar.py
module = __import__('foo')
foo = module.__dict__['Foo']
Afterwards, foo is the class foo.Foo as expected.
Yet, if I put a.py into a package, it stops working:
qux/__init__.py
(empty file)
qux/foo.py
class Foo:
pass
bar.py
module = __import__('qux.foo')
foo = module.__dict__['Foo']
Running python bar.py gives me KeyError: 'Foo', but the module import is still successful.
What's going on, and how do I get it to work?
__import__ applied to nested module names returns the toplevel module/package - which is qux here. All modules are, however, inserted into sys.modules, so you can simply lookup qux.foo in there.
See the PyDoc on __import__() -it's all described there.
If you want to import a submodule, you can do something like this:
package = __import__('qux', fromlist=['foo'])
module = getattr(package, 'foo')
Note that with a fromlist the __import__ returns the most nested name in the first parameter, so you could substitute baz.bar.qux in the __import__ call to access the baz.bar.qux.foo module.
You need to use the fromlist parameter to reference a submodule:
temp = __import__('qux.foo', globals(), locals(), ['Foo'], -1)
foo = temp.Foo
You can directly access a module, nested or not, using importlib:
import importlib
module_name="qux.foo"
mod=importlib.import_module(module_name)
See http://docs.python.org/dev/library/importlib.html for more details.

Categories