Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 41 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ $ pip install python-lambda-local
This will install the package with name `python-lambda-local` in the virtualenv.
Now you can use the command `python-lambda-local` to run your AWS Lambda function written in Python on your own machine.

## Usage
## Usage as a shell command

Run `python-lambda-local -h` to see the help.

```
usage: python-lambda-local [-h] [-l LIBRARY_PATH] [-f HANDLER_FUNCTION]
[-t TIMEOUT] [-a ARN_STRING] [-v VERSION_NAME]
[--version]
[-e ENVIRONMENT_VARIABLES] [--version]
FILE EVENT

Run AWS Lambda function written in Python on local machine.
Expand Down Expand Up @@ -118,16 +118,50 @@ python-lambda-local -l lib/ -f handler -t 5 test.py event.json
The output will be like:

```
[root - INFO - 2017-04-19 12:39:05,512] Event: {u'answer': 42}
[root - INFO - 2017-04-19 12:39:05,512] START RequestId: b918f9ae-0ca1-44af-9937-dd5f9eeedcc1
[root - INFO - 2018-11-20 17:10:53,352] Event: {'answer': 42}
[root - INFO - 2018-11-20 17:10:53,352] START RequestId: 3c8e6db4-886a-43da-a1c7-5e6f715de531 Version:
0
49
196
441
784
1225
[root - INFO - 2017-04-19 12:39:05,515] END RequestId: b918f9ae-0ca1-44af-9937-dd5f9eeedcc1
[root - INFO - 2017-04-19 12:39:05,515] RESULT:
[root - INFO - 2018-11-20 17:10:53,359] END RequestId: 3c8e6db4-886a-43da-a1c7-5e6f715de531
[root - INFO - 2018-11-20 17:10:53,360] REPORT RequestId: 3c8e6db4-886a-43da-a1c7-5e6f715de531 Duration: 2.17 ms
[root - INFO - 2018-11-20 17:10:53,360] RESULT:
None
[root - INFO - 2017-04-19 12:39:05,515] REPORT RequestId: b918f9ae-0ca1-44af-9937-dd5f9eeedcc1 Duration: 2.27 ms
```

## Usage as a library

### API signature

``` python
call(func, event, context, environment_variables={})
```

Call a handler function `func` with given `event`, `context` and custom `environment_variables`.

### Sample

1. Make sure the 3rd party libraries used in the AWS Lambda function can be imported.

``` bash
pip install rx
```

2. To call the lambda function above with your python code:

``` python
from lambda_local.main import call
from lambda_local.context import Context

import test

event = {
"answer": 42
}
context = Context(5)

call(test.handler, event, context)
```
181 changes: 111 additions & 70 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,43 +18,45 @@ Within virtualenv, run the following command.

.. code:: bash

$ pip install python-lambda-local
$ pip install python-lambda-local

This will install the package with name ``python-lambda-local`` in the
virtualenv. Now you can use the command ``python-lambda-local`` to run
your AWS Lambda function written in Python on your own machine.

Usage
-----
Usage as a shell command
------------------------

Run ``python-lambda-local -h`` to see the help.

::

usage: python-lambda-local [-h] [-l LIBRARY_PATH] [-f HANDLER_FUNCTION]
[-t TIMEOUT] [-a ARN_STRING] [-v VERSION_NAME]
[--version]
FILE EVENT

Run AWS Lambda function written in Python on local machine.

positional arguments:
FILE lambda function file name
EVENT event data file name

optional arguments:
-h, --help show this help message and exit
-l LIBRARY_PATH, --library LIBRARY_PATH
path of 3rd party libraries
-f HANDLER_FUNCTION, --function HANDLER_FUNCTION
lambda function handler name, default: "handler"
-t TIMEOUT, --timeout TIMEOUT
seconds until lambda function timeout, default: 3
-a ARN_STRING, --arn-string ARN_STRING
ARN string for lambda function
-v VERSION_NAME, --version-name VERSION_NAME
lambda function version name
--version print the version of python-lambda-local and exit
usage: python-lambda-local [-h] [-l LIBRARY_PATH] [-f HANDLER_FUNCTION]
[-t TIMEOUT] [-a ARN_STRING] [-v VERSION_NAME]
[-e ENVIRONMENT_VARIABLES] [--version]
FILE EVENT

Run AWS Lambda function written in Python on local machine.

positional arguments:
FILE lambda function file name
EVENT event data file name

optional arguments:
-h, --help show this help message and exit
-l LIBRARY_PATH, --library LIBRARY_PATH
path of 3rd party libraries
-f HANDLER_FUNCTION, --function HANDLER_FUNCTION
lambda function handler name, default: "handler"
-t TIMEOUT, --timeout TIMEOUT
seconds until lambda function timeout, default: 3
-a ARN_STRING, --arn-string ARN_STRING
ARN string for lambda function
-v VERSION_NAME, --version-name VERSION_NAME
lambda function version name
-e ENVIRONMENT_VARIABLES, --environment-variables ENVIRONMENT_VARIABLES
path to flat json file with environment variables
--version print the version of python-lambda-local and exit

Prepare development directory
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -66,25 +68,25 @@ Suppose your project directory is like this:

::

├── event.json
├── lib
│   ├── rx
│   │   ├── abstractobserver.py
│   │   ├── ... (package content of rx)
...
│   │   └── testscheduler.py
│   └── Rx-1.2.3.dist-info
│   ├── DESCRIPTION.rst
│   ├── METADATA
│   ├── metadata.json
│   ├── pbr.json
│   ├── RECORD
│   ├── top_level.txt
│   ├── WHEEL
│   └── zip-safe
└── test.py

The handler's code is in ``test.py`` and the function name of the
├── event.json
├── lib
│   ├── rx
│   │   ├── abstractobserver.py
│   │   ├── ... (package content of rx)
...
│   │   └── testscheduler.py
│   └── Rx-1.2.3.dist-info
│   ├── DESCRIPTION.rst
│   ├── METADATA
│   ├── metadata.json
│   ├── pbr.json
│   ├── RECORD
│   ├── top_level.txt
│   ├── WHEEL
│   └── zip-safe
└── test.py

The handlers code is in ``test.py`` and the function name of the
handler is ``handler``. The source depends on 3rd party library ``rx``
and it is installed in the directory ``lib``. The test event in json
format is in ``event.json`` file.
Expand All @@ -94,25 +96,25 @@ Content of ``test.py``:

.. code:: python

from __future__ import print_function
from rx import Observable
from __future__ import print_function
from rx import Observable


def handler(event, context):
xs = Observable.from_(range(event['answer']))
ys = xs.to_blocking()
zs = (x*x for x in ys if x % 7 == 0)
for x in zs:
print(x)
def handler(event, context):
xs = Observable.from_(range(event['answer']))
ys = xs.to_blocking()
zs = (x*x for x in ys if x % 7 == 0)
for x in zs:
print(x)

Content of ``event.json``:
^^^^^^^^^^^^^^^^^^^^^^^^^^

.. code:: json

{
"answer": 42
}
{
"answer": 42
}

Run the lambda function
^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -122,24 +124,63 @@ the following command

::

python-lambda-local -l lib/ -f handler -t 5 test.py event.json
python-lambda-local -l lib/ -f handler -t 5 test.py event.json

The output will be like:

::

[root - INFO - 2017-04-19 12:39:05,512] Event: {u'answer': 42}
[root - INFO - 2017-04-19 12:39:05,512] START RequestId: b918f9ae-0ca1-44af-9937-dd5f9eeedcc1
0
49
196
441
784
1225
[root - INFO - 2017-04-19 12:39:05,515] END RequestId: b918f9ae-0ca1-44af-9937-dd5f9eeedcc1
[root - INFO - 2017-04-19 12:39:05,515] RESULT:
None
[root - INFO - 2017-04-19 12:39:05,515] REPORT RequestId: b918f9ae-0ca1-44af-9937-dd5f9eeedcc1 Duration: 2.27 ms
[root - INFO - 2018-11-20 17:10:53,352] Event: {'answer': 42}
[root - INFO - 2018-11-20 17:10:53,352] START RequestId: 3c8e6db4-886a-43da-a1c7-5e6f715de531 Version:
0
49
196
441
784
1225
[root - INFO - 2018-11-20 17:10:53,359] END RequestId: 3c8e6db4-886a-43da-a1c7-5e6f715de531
[root - INFO - 2018-11-20 17:10:53,360] REPORT RequestId: 3c8e6db4-886a-43da-a1c7-5e6f715de531 Duration: 2.17 ms
[root - INFO - 2018-11-20 17:10:53,360] RESULT:
None

Usage as a library
------------------

API signature
~~~~~~~~~~~~~

.. code:: python

call(func, event, context, environment_variables={})

Call a handler function ``func`` with given ``event``, ``context`` and
custom ``environment_variables``.

Sample
~~~~~~

1. Make sure the 3rd party libraries used in the AWS Lambda function can
be imported.

.. code:: bash

pip install rx

2. To call the lambda function above with your python code:

.. code:: python

from lambda_local.main import call
from lambda_local.context import Context

import test

event = {
"answer": 42
}
context = Context(5)

call(test.handler, event, context)

.. |Join the chat at https://gitter.im/HDE/python-lambda-local| image:: https://badges.gitter.im/Join%20Chat.svg
:target: https://gitter.im/HDE/python-lambda-local?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
Expand Down
10 changes: 1 addition & 9 deletions lambda_local/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,16 @@

from __future__ import print_function
import argparse
import sys
from multiprocessing import Process
import pkg_resources

from .main import run


__version__ = pkg_resources.require("python-lambda-local")[0].version


def main():
args = parse_args()

p = Process(target=run, args=(args,))
p.start()
p.join()

sys.exit(p.exitcode)
run(args)


def parse_args():
Expand Down
47 changes: 31 additions & 16 deletions lambda_local/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,47 @@
Copyright 2015-2018 HDE, Inc.
Licensed under MIT.
'''
from __future__ import print_function

from datetime import datetime
from datetime import timedelta
import uuid


class Context(object):
def __init__(self, timeout, arn_string, version_name):
self.function_name = "undefined"
self.function_version = version_name
self.invoked_function_arn = arn_string
self.memory_limit_in_mb = 0
self.aws_request_id = "undefined"
self.log_group_name = "undefined"
self.log_stream_name = "undefined"
self.identity = None
self.client_context = None
self.timeout = timeout
self.duration = timedelta(seconds=timeout)
def __init__(self, timeout_in_seconds,
aws_request_id=uuid.uuid4(),
function_name="undefined",
function_version="$LATEST",
log_group_name="undefined",
log_stream_name="undefined",
invoked_function_arn="undefined",
memory_limit_in_mb='0',
client_context=None,
identity=None):
self.function_name = function_name
self.function_version = function_version
self.invoked_function_arn = invoked_function_arn
self.memory_limit_in_mb = memory_limit_in_mb
self.aws_request_id = aws_request_id
self.log_group_name = log_group_name
self.log_stream_name = log_stream_name
self.identity = identity
self.client_context = client_context

self._timeout_in_seconds = timeout_in_seconds
self._duration = timedelta(seconds=timeout_in_seconds)

def get_remaining_time_in_millis(self):
if self.timelimit is None:
if self._timelimit is None:
raise Exception("Context not activated.")
return millis_interval(datetime.now(), self.timelimit)
return millis_interval(datetime.now(), self._timelimit)

def log(self, msg):
print(msg)

def activate(self):
self.timelimit = datetime.now() + self.duration
def _activate(self):
self._timelimit = datetime.now() + self._duration
return self


Expand Down
Loading