serverless / serverless-python-requirements

⚡️🐍📦 Serverless plugin to bundle Python packages
MIT License
1.11k stars 290 forks source link

invoke local issue when "module" is defined #520

Open lepirlouit opened 4 years ago

lepirlouit commented 4 years ago

I'm unable to invoke my function locally when I use the module functionality:

severless.yml

package:
  individually: true

functions:
  my_function:
     handler: my_function.lambda_handler
     module: src/my_function_folder

invoke local : serverless invoke local -f my_function

got error : ModuleNotFoundError: No module named 'my_function'

lepirlouit commented 4 years ago

warkaround : this can be fixed in the serverless/lib/plugins/aws/invokeLocal/invoke.py file by adding


line 72: import os
line 73: sys.path.append(os.path.join('.', "src", "my_function_folder"))```
jorgeandresvasquez commented 4 years ago

Having the same issue, have you been able to find any other solutions?

lepirlouit commented 4 years ago

temporary try my workaround https://github.com/UnitedIncome/serverless-python-requirements/issues/520#issuecomment-638047127

sndrsnk commented 4 years ago

I'm also affected by this issue. Removing the module: parameter works but then the plugin can't see my requirements.txt file as it's nested, so there's always going to be a discrepancy between the handler path determined locally and remotely. Thanks for the temporary workaround @lepirlouit!

sndrsnk commented 4 years ago

I've found another temporary workaround using environment variables in serverless.yml:

functions:
  LambdaTestFunction:
    handler: ${env:HANDLER_PATH_PREFIX, ""}handler.handler
    module: src/test_lambda
  ...
  ...
package:
  individually: true

When I invoke locally, I use the following command:

HANDLER_PATH_PREFIX=src/test_lambda/ LOCAL=true ./node_modules/serverless/bin/serverless.js invoke local -f LambdaTest -p ./tests/resources/base_event.yml

I've tested local and remote invocations and I can confirm it's working as expected.

jamesoflol commented 4 years ago

Thanks @sndrsnk. This works. But I then have a problem with importing modules from alongside handler.py. I find that they either work in local or lambda, depending on my syntax. As a workaround, I have to do this:

if "IS_LOCAL" in os.environ:
    from test_lambda import my_other_module
else:
    import my_other_module

Note that IS_LOCAL is automatically set by serverless framework - you don't need to make it yourself.

Python isn't my fave language, so I'm probably doing something dumb. Or is this required? (I tried doing from . import my_other_module but it only worked locally and not in lambda.)

sndrsnk commented 4 years ago

@jamesoflol You're welcome, and thanks for raising the issue regarding relative imports. I tested it on my end and can confirm that I'm experiencing the same issue. I did some research and found a really nice workaround here.

Simply add the following block of code to your package's __init__.py file:

import os
import sys

sys.path.append(os.path.dirname(os.path.realpath(__file__)))
└── test_lambda
    ├── __init__.py <=== add the code to this one
    ├── handler.py
    ├── requirements.txt
    └── some_module
        ├── __init__.py
        └── example.py

Hope it helps!

thomaschen commented 3 years ago

@sndrsnk Thanks for sharing!

Here' another workaround by setting the PYTHONPATH environment variable to the module field in serverless.yml when you invoke local. In this case, you don't need to add local-only logic to the serverless.yml, and the good thing is the relative imports would still work as-is.

PYTHONPATH=YOUR_MODULE serverless invoke local --function YOUR_FUNCTION
tw1t611 commented 2 years ago

The provided workaround works great for functions without an import of an external package. However it does not include the packages installed in venv. Is there any solution to this?