2

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

linker85
  • 1,601
  • 5
  • 26
  • 44
  • Did you try to use: from lambda.lambda_function import *? – Giordano Mar 23 '21 at 17:13
  • Try `from lambda import lambda_function` – Raghava Dhanya Mar 23 '21 at 17:13
  • 1
    in which file are you trying to `import lambda_function`? you should be using the [relative import](https://stackoverflow.com/questions/14132789/relative-imports-for-the-billionth-time) format here – Aaron Mar 23 '21 at 17:15
  • yeah I tried but since lambda is a keyword in python, it doesnt like it, and I dont know if aws lambda would complain if I rename that lambda folder – linker85 Mar 23 '21 at 17:17
  • is `root` basically your "site-packages" and `lambda` is a package provided for you or one you're trying to write? I would strongly recommend re-naming the package something other than `lambda` if you can. otherwise you'll have to use [`importlib.import_module`](https://docs.python.org/3/library/importlib.html#importlib.import_module) rather than `import` – Aaron Mar 23 '21 at 17:31
  • the lambda folder was automatically created by aws when I created the project then I downloaded the source code from aws – linker85 Mar 23 '21 at 17:36
  • @linker85 is `root` supposed to be the top level package? there's no `__init__.py` file so I was just assuming it was just some folder on the import search path like "site-packages". your indentation does not make the file structure crystal clear to me... – Aaron Mar 23 '21 at 18:05
  • Sorry, I corrected the indentation – linker85 Mar 23 '21 at 18:47
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/230281/discussion-between-aaron-and-linker85). – Aaron Mar 23 '21 at 19:10

2 Answers2

2

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

Alexey Inkin
  • 1,853
  • 1
  • 12
  • 32
  • 2
    probably better to link to the latest documentation rather than the ancient 2.5... https://docs.python.org/3/reference/import.html#package-relative-imports the newer example is much more complete and readable too (it isn't real clear what `A.B.C` is) – Aaron Mar 23 '21 at 17:21
  • I updated my question with what you showed me, I can import from one level above but not from 2 levels above and even then when I import from one level above it complains on run time – linker85 Mar 23 '21 at 17:33
  • I have added: Two or more leading dots indicate a relative import to the parent(s) of the current package, one level per dot after the first. – Alexey Inkin Mar 23 '21 at 17:44
  • updated as you mentioned, everything works on compile time, but on run time it crashes as mentioned at the top of the post – linker85 Mar 23 '21 at 18:03
2

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!
Aaron
  • 10,133
  • 1
  • 24
  • 40
  • the option "regular import with module name colliding with a reserved word" worked for me, the 2nd crashes as explained at my post – linker85 Mar 23 '21 at 18:12
  • also I am running the behave frame work and in that case when I do A = import_module("lambda.A") I get ModuleNotFoundError: No module named 'lambda' but if I run directly the python file it works – linker85 Mar 23 '21 at 18:24
  • @linker85 that sounds like a module search path issue... putting these examples into my "site-packages" folder was no accident. the folder containing the `lambda` package must be on the list of folders where python will search for modules or `lambda` must be in the same folder as the script you're executing. I guarantee if you copy my example verbatim, it will work, but otherwise you must expand on how your system works to illuminate how your situation is different. – Aaron Mar 23 '21 at 18:27
  • Is the `features` folder inside the `lambda` folder or something else I'm not getting? – Aaron Mar 23 '21 at 18:34
  • in my defense it was previously at the same indent level as lambda.... – Aaron Mar 23 '21 at 18:48
  • I updated my post it seems that only when I run the library behave its unable to find the lambda module, if I run directly C.py it works – linker85 Mar 23 '21 at 18:57