import a submodule with its name from a module - python

I have a function called prepared_db in submodule db.db_1:
from spam import db
submodule_name = "db_1"
func_name = "prepare_db"
func = ...
how can I get the function by the submodule name and function name in the context above?
UPDATE:
To respond #histrio 's answer, I can verify his code works for os module. But it does not work in this case. To create the example:
$ mkdir -p spam/db
$ cat > spam/db/db_1.py
def prepare_db():
print('prepare_db func')
$ touch spam/db/__init__.py
$ PYTHONPATH=$PYTHONPATH:spam
now, you can do the import normally:
>>> from spam.db.db_1 import prepare_db
>>> prepare_db()
prepare_db func
but if you do this dynamically, I get this error:
>>> getattr(getattr(db, submodule_name), func_name)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-9-1b6aa1216551> in <module>()
----> 1 getattr(getattr(db, submodule_name), func_name)
AttributeError: module 'spam.db.db_1' has no attribute 'prepared_db'

It's simple. You can consider module as object.
import os
submodule_name = "path"
func_name = "exists"
submodule = getattr(os, submodule_name)
function = getattr(submodule, func_name)
function('/home') # True
or [just for fun, don't do that]
fn = reduce(getattr, ('sub1', 'sub2', 'sub3', 'fn'), module)
UPDATE
import importlib
submodule = importlib.import_module('.'+submodule_name, module.__name__)
function = getattr(submodule, func_name)

I think I figured it out, you need to add the function to the __all__ variable in the __init__.py file, so that would be something along the lines of:
from .db_1 import prepare_db
__all__ = ['prepare_db']
After that, it should work just fine.

Related

Is it possible to make a scope that is only for the script?

The basic idea of this is to have a variable that can only be used in the same script it is defined/declared scope.
So even if you import the script to another file you still can't access that variable.
Basically a local scope but for the script file.
Sorry if i'm bad at explaining.
Because normaly you can just do this:
Script a (the script with the variable)
scriptvar = 21
def somefunction():
return "banana"
Script b (the script that should not be able to access the variable)
import script_a
print(script_a.somefunction())
print(script_a.scriptvar)
Script b should return
>> banana
>> AttributeError: module 'script_a' has no attribute 'scriptvar'
You can't do this but there is a convention that if you add a underscore to the name you indicate that it is a internal variable.
I think, that there is no elegant way to get this.
There is a __all__ directive to specify what will be imported via from module_name import * but it will not work with
import module_name
module_name.scriptvar
There is a workaround: you can initialise all the necessary objects inside function and export only useful ones. Simple example
# lib.py
import sys
__all__ = ['x', 'y']
def __init(module):
def x():
return 2
z = 2
def y():
return z
module.x = x
module.y = y
del module.__init
__init(sys.modules[__name__])
# script.py
import lib
print(lib.x())
try:
lib.__init()
except AttributeError:
print('As expected')
from lib import *
print(x())
print(y())
try:
print(z)
except NameError:
print('As expected')
Running python3 script.py gives
2
As expected
2
2
As expected

ImportError: cannot import name - Python

I am trying to import some variables from a different python file resides in the same directory from a another python file.
I have two files in the same directory as below:
constantvariables.py
test.py
This is how constantvariables.py looks like
class CONST(object):
FOO = 1234
NAMESPACE = "default"
DEPLOYMENT_NAME = "deployment-test"
DOCKER_IMAGE_NAME = "banukajananathjayarathna/bitesizetroubleshooter:v1"
SERVICE_CLUSTER = "deployment-test-clusterip"
SERVICE_NODEPORT = "deployment-test-nodeport"
INGRESS_NAME = "deployment-test-ingress"
def __setattr__(self, *_):
pass
CONST = CONST()
and this is how my test.py looks like:
import os
from . import constantvariables
print(constantsvariables.NAMESPACE)
But I get this error:
Traceback (most recent call last):
File "test.py", line 7, in
from . import constantsvariables
ImportError: cannot import name 'constantsvariables'
can someone please help me?
Python version I am using python 2.7.5
Make constant file like that constant.py and put inside config folder for proper management.
FOO = 1234
NAMESPACE = "default"
DEPLOYMENT_NAME = "deployment-test"
DOCKER_IMAGE_NAME = "banukajananathjayarathna/bitesizetroubleshooter:v1"
SERVICE_CLUSTER = "deployment-test-clusterip"
SERVICE_NODEPORT = "deployment-test-nodeport"
INGRESS_NAME = "deployment-test-ingress"
Inside your base directory create main.py file and call the constant inside that.
import os
from config.constants import NAMESPACE, FOO
print(NAMESPACE)
If you want to keep your constant file as it is, you can write this:
import os
from constantvariables import CONST
print(CONST.NAMESPACE)

Creating importable Python 3 package / module

I am having trouble creating an importable Python package/library/module or whatever the right nomenclature is. I am using Python 3.7
The file structure I am using is:
Python37//Lib//mypackage
mypackage
__init__.py
mypackage_.py
The code in __init__.py is:
from mypackage.mypackage_ import MyClass
The code in mypackage_.py is:
class MyClass:
def __init__(self, myarg = None):
self.myvar = myarg
And from my desktop I try running the following code:
import mypackage
x = MyClass(None)
But get the following error:
Traceback (most recent call last):
File "C:\Users\***\Desktop\importtest.py", line 3, in <module>
x = MyClass(None)
NameError: name 'MyClass' is not defined
You haven't imported the name MyClass into your current namespace. You've imported mypackage. To access anything within mypackage, you need to prefix the name with mypackage.<Name>
import mypackage
x = mypackage.MyClass(None)
As #rdas says, you need to prefix the name with mypackage.<Name>.
I don't recommend doing this, but you can wildcard import in order to make x = MyClass(None) work:
from mypackage import *
Now, everything from mypackage is imported and usable in the current namespace. However, you have to be careful with wildcard imports because they can create definition conflictions (if multiple modules have the same name for different things).

Mocking logging of a module imported with a relative import

Due to the structure of our project and the way we run its tests, our library modules are imported with a relative import by test modules, for example:
from .. import foo_bar
Now, I want to check that a function in the foo_bar module issues a warning for certain parameters. I have tried this:
from unittest.mock import patch
#patch('foo_bar.logging')
def test_distance(mock_logging):
foo_bar.baz(None)
assert mock_logging.warn.called
and I got this:
target = 'foo_bar'
def _importer(target):
components = target.split('.')
import_path = components.pop(0)
> thing = __import__(import_path)
E ImportError: No module named 'foo_bar'
/tmp/envs/foo/lib/unittest/mock.py:1058: ImportError
When I tried to change the patch line like this:
#patch('..foo_bar.logging')
I got this error:
target = '..foo_bar'
def _importer(target):
components = target.split('.')
import_path = components.pop(0)
> thing = __import__(import_path)
E ValueError: Empty module name
/tmp/envs/foo/lib/unittest/mock.py:1058: ValueError
Any idea how to use the patch function from unittest.mock in these circumstances?
You can use the imported module's __name__ attribute to achieve relative import mocking.
#patch(foo_bar.__name__ + '.logging')
def test_distance(mock_logging):
...

Python Module issues

Im pretty new to python, and have been having a rough time learning it. I have a main file
import Tests
from Tests import CashAMDSale
CashAMDSale.AMDSale()
and CashAMDSale
import pyodbc
import DataFunctions
import automa
from DataFunctions import *
from automa.api import *
def AMDSale():
AMDInstance = DataFunctions.GetValidAMD()
And here is GetValidAMD
import pyodbc
def ValidAMD(GetValidAMD):
(short method talking to a database)
My error comes up on the line that has AMDInstance = DataFunctions.GetValidAMD()
I get the error AttributeError: 'module' object has no attribute 'GetValidAMD'
I have looked and looked for an answer, and nothing has worked. Any ideas? Thanks!
DataFunctions is a folder, which means it is a package and must contain an __init__.py file for python to recognise it as such.
when you import * from a package, you do not automatically import all it's modules. This is documented in the docs
so for your code to work, you either need to explicitly import the modules you need:
import DataFunctions.GetValidAMD
or you need to add the following to the __init__.py of DataFunctions:
__all__ = ["GetValidAMD"]
then you can import * from the package and everything listen in __all__ will be imported
When you create the file foo.py, you create a python module. When you do import foo, Python evaluates that file and places any variables, functions and classes it defines into a module object, which it assigns to the name foo.
# foo.py
x = 1
def foo():
print 'foo'
 
>>> import foo
>>> type(foo)
<type 'module'>
>>> foo.x
1
>>> foo.foo()
foo
When you create the directory bar with an __init__.py file, you create a python package. When you do import bar, Python evaluates the __init__.py file and places any variables, functions and classes it defines into a module object, which it assigns to the name bar.
# bar/__init__.py
y = 2
def bar():
print 'bar'
 
>>> import bar
>>> type(bar)
<type 'module'>
>>> bar.y
2
>>> bar.bar()
bar
When you create python modules inside a python package (that is, files ending with .py inside directory containing __init__.py), you must import these modules via this package:
>>> # place foo.py in bar/
>>> import foo
Traceback (most recent call last):
...
ImportError: No module named foo
>>> import bar.foo
>>> bar.foo.x
1
>>> bar.foo.foo()
foo
Now, assuming your project structure is:
main.py
DataFunctions/
__init__.py
CashAMDSale.py
def AMDSale(): ...
GetValidAMD.py
def ValidAMD(GetValidAMD): ...
your main script can import DataFunctions.CashAMDSale and use DataFunctions.CashAMDSale.AMDSale(), and import DataFunctions.GetValidAMD and use DataFunctions.GetValidAMD.ValidAMD().
Check out this.
It's the same problem. You are importing DataFunctions which is a module. I expct there to be a class called DataFunctions in that module which needs to be imported with
from DataFunctions import DataFunctions
...
AMDInstance = DataFunctions.GetValidAMD()

Categories