how to import a parent file in python?

Viewed 107

Hello so I have this aws lambda project in python(3.9) with the next structure:

*root -|
      *lambda -|
           _init_.py
           A.py
           *features -|
              _init_.py
              alexa.feature
              B.py
              *steps -|
                 _init_.py
                 alexa_steps.py
                 C.py

So following the suggestions I have: In C.py

from importlib import import_module
A = import_module("lambda.A")


def testC():
    return A.testA()

If I run C.py it works fine but in alexa_steps.py I got:

from importlib import import_module

@given('the user has opened the skill')
def step_impl(context):
    A = import_module("lambda.A")b
    A.testA()

In terminal I get into the lambda folder and execute: behave The test fails and I get:

USMCDANCN2Z76AB:mathquiz xzxqdy$ cd lambda
USMCDANCN2Z76AB:lambda xzxqdy$ behave
Exception ModuleNotFoundError: No module named 'lambda'
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.9/bin/behave", line 8, in <module>
    sys.exit(main())
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/behave/__main__.py", line 183, in main
    return run_behave(config)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/behave/__main__.py", line 127, in run_behave
    failed = runner.run()
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/behave/runner.py", line 804, in run
    return self.run_with_paths()
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/behave/runner.py", line 809, in run_with_paths
    self.load_step_definitions()
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/behave/runner.py", line 796, in load_step_definitions
    load_step_modules(step_paths)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/behave/runner_util.py", line 412, in load_step_modules
    exec_file(os.path.join(path, name), step_module_globals)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/behave/runner_util.py", line 386, in exec_file
    exec(code, globals_, locals_)
  File "features/steps/C.py", line 2, in <module>
    A = import_module("lambda.A")
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 972, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 984, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'lambda'

Thanks in advance for your help

2 Answers

Here is the latest doc on relative imports: https://docs.python.org/3/reference/import.html#package-relative-imports

Relative imports use leading dots. A single leading dot indicates a relative import, starting with the current package. Two or more leading dots indicate a relative import to the parent(s) of the current package, one level per dot after the first. For example, given the following package layout:

    package/
        __init__.py
        subpackage1/
            __init__.py
            moduleX.py
            moduleY.py
        subpackage2/
            __init__.py
            moduleZ.py
        moduleA.py

In either subpackage1/moduleX.py or subpackage1/__init__.py, the following are valid relative imports:

    from .moduleY import spam
    from .moduleY import spam as ham
    from . import moduleY
    from ..subpackage1 import moduleY
    from ..subpackage2.moduleZ import eggs
    from ..moduleA import foo

They first appeared in 2.5: https://docs.python.org/2/whatsnew/2.5.html#pep-328-absolute-and-relative-imports

If you must keep the package called lambda it obviously conflicts with the python keyword for anonymous functions, so you must use importlib.import_module and pass the package name as a string so python cannot confuse it with a keyword.

I put a package called "lambda" and a package called "features" in my "site-packages" folder with the following structure:

site-packages
    lambda
        __init__.py #empty file
        A.py #file contents: def testA(): print("A!")

    features
        __init__.py #empty file
        B.py #file contents: def testB(): print("B!")
        steps
            __init__.py #empty file
            C.py

C.py contains the following:

#regular import with module name colliding with a reserved word
from importlib import import_module
A = import_module("lambda.A")
A.testA()

#relative import up a level is covered in https://docs.python.org/3/reference/import.html#package-relative-imports
from ..B import testB
testB()

Now when I call from features.steps import C from a console, it prints out:

>>> from features.steps import C
A!
B!
Related