Relative imports do not work from imported modules - python

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

Related

Mock import failure

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)

Python Module and Class - AttributeError: module has no attribute

I'm new to python and I'm trying to create a module and class.
If I try to import mystuff and then use cfcpiano = mystuff.Piano(), I get an error:
AttributeError: module 'mystuff' has no attribute 'Piano'
If I try from mystuff import Piano I get:
ImportError: cannot import name 'Piano'
Can someone explain what is going on? How do I use a module and class in Python
mystuff.py
def printhello():
print ("hello")
def timesfour(input):
print (input * 4)
class Piano:
def __init__(self):
self.type = raw_input("What type of piano? ")
def printdetails(self):
print (self.type, "piano, " + self.age)
Test.py
import mystuff
from mystuff import Piano
cfcpiano = mystuff.Piano()
cfcpiano.printdetails()
If you want to create a python module named mystuff
Create a folder with name mystuff
Create an __init__.py file
#__init__.py
from mystuff import Piano #import the class from file mystuff
from mystuff import timesfour,printhello #Import the methods
Copy your class mystuff.py to the folder mystuff
Create file test.py outside the folder(module) mystuff.
#test.py
from mystuff import Piano
cfcpiano = Piano()
cfcpiano.printdetails()

Define an object as 'root' of module

I have a module module.py
class SomeClass():
def __init__(self):
self.var='123'
def printit(self):
print self.var
And now I'm trying to import this module into script.py and call the method printit from the class SomeClass
import module
module.SomeClass().printit()
I also can do it by another way:
from module import SomeClass
SomeClass().printit()
And another one:
from module import SomeClass as module
module().printit()
It's nice but i want to get something like this:
import module
module().printit()
or even
import module
SomeClass().printit()
Generally I want to make a module that will export SomeClass by default. Is it possible to make something like this by changing module.py?

Is there a way to get the name of the 'parent' module from an imported module?

I'm curious if it's possible to access the name of the parent module that some other module is imported into.
For instance, if I have a module (moduleA) and a parent is module, foo.py, into which it will be imported into, is it possible for moduleA to know where foo is located ?
ModuleA
def print_parent_module():
os.path.asbpath(#somehow access filename of parent module)
foo.py
import moduleA
print moduleA.print_parent_module()
>>> "foo.py"
I ran into a similar issue. You could make use of __name__:
parent_name = '.'.join(__name__.split('.')[:-1])
Or if you try to access the module directly (not the OP's question but related), see my answer in Is there a way to access parent modules in Python
No. Imported modules do not hold any form of state which stores data related to how they are imported.
I think the better question is, why would you even want to do it this way? You're aware that if foo.py is indeed your __main__ then you can easily get the name foo.py out of it (by using sys.argv)? And if foo.py is an imported module instead, then you obviously already know the name of foo.py and its location, etc. at the time that you import it.
Here is something I came with to store a parent's method name and variables to be recalled later in the class with a decorator.
import inspect
from functools import wraps
def set_reuse_vars(method):
#wraps(method)
def _impl(self, *method_args, **method_kwargs):
func_current = inspect.currentframe()
self.recall_func = dict()
self.recall_func['method_kwargs'] = func_current.f_locals['method_kwargs']
self.recall_func['method_name'] = func_current.f_locals['method'].__name__
return method(self, *method_args, **method_kwargs)
return _impl
class APIData(object):
def __init__(self):
self.client = None
self.response = None
self.recall_func = None
def get_next_page(self):
# Takes a pageToken to return the next result
get_func = getattr(self, self.recall_func['method_name'])
self.recall_func['method_kwargs']['pageToken'] = self.response['nextPageToken']
return get_func(**self.recall_func['method_kwargs'])
#set_reuse_vars
def search_list_by_keyword(self, **kwargs):
self.response = self.client.search().list(
**kwargs
).execute()
return self.response
script to run it.
api_data = APIData()
results = api_data.search_list_by_keyword(
part='snippet',
maxResults=25,
order='date')
print(results)
resultsTwo = api_data.get_next_page()
print(resultsTwo)
Figured it out!
A little import statement inside of the function can give access to the module name.
moduleA
def print_module_name():
import sys
return sys.argv[0]
Then, inside the "parent" module
# foo.py
import os
import moduleA
if __name__ == '__main__':
print os.path.split(moduleA.print_module_name())[-1]
Gives:
>>> 'foo.py'

Class is not defined despite being imported

I seem to have run into a really confusing error. Despite importing the .py file containing my class, Python is insistent that the class doesn't actually exist.
Class definition in testmodule.py:
class Greeter:
def __init__(self, arg1=None):
self.text = arg1
def say_hi(self):
return self.text
main.py:
#!/usr/bin/python
import testmodule
sayinghi = Greeter("hello world!")
print(sayinghi.say_hi())
I have a theory that the import is not working as it should. How do I do this correctly?
Use the fully-qualified name:
sayinghi = testmodule.Greeter("hello world!")
There is an alternative form of import that would bring Greeter into your namespace:
from testmodule import Greeter
import testmodule
# change to
from testmodule import Greeter
or
import testmodule
sayinghi = Greeter("hello world!")
# change to
import testmodule
sayinghi = testmodule.Greeter("hello world!")
You imported the module/package, but you need to reference the class inside it.
You could also do this instead
from testmodule import *
but then beware of namespace pollution

Categories

Resources