Skip to content

Commit f4ceaa2

Browse files
committed
Transform serverless-wsgi into serverless-python-requirements!
Removes all but an even simpler version of automatic requirement packing and adds a utility function to add deps to sys.path
1 parent c462bdf commit f4ceaa2

File tree

7 files changed

+42
-435
lines changed

7 files changed

+42
-435
lines changed

README.md

Lines changed: 14 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -1,171 +1,33 @@
1-
# Serverless WSGI
1+
# Serverless Python Requirements
22

33
[![serverless](http://public.serverless.com/badges/v3.svg)](http://www.serverless.com)
44

5-
A Serverless v1.0 plugin to build your deploy Python WSGI applications using Serverless. Compatible
6-
WSGI application frameworks include Flask, Django and Pyramid - for a complete list, see:
7-
[http://wsgi.readthedocs.io/en/latest/frameworks.html](http://wsgi.readthedocs.io/en/latest/frameworks.html).
8-
9-
### Features
10-
11-
* Transparently converts API Gateway requests to and from standard WSGI requests
12-
* Supports anything you'd expect from WSGI such as redirects, cookies, file uploads etc.
13-
* Automatically downloads Python packages that you specify in `requirements.txt` and deploys them along with your application
14-
* Convenient `wsgi serve` command for serving your application locally during development
5+
A Serverless v1.0 plugin to automatically bundle dependencies from
6+
`requirements.txt`.
157

168

179
## Install
1810

1911
```
20-
npm install --save serverless-wsgi
12+
npm install --save serverless-python-requirements
2113
```
2214

23-
Add the plugin to your `serverless.yml` file and set the WSGI application:
15+
Add the plugin to your `serverless.yml`:
2416

2517
```yaml
2618
plugins:
27-
- serverless-wsgi
28-
```
29-
30-
31-
## Flask configuration example
32-
33-
This example assumes that you have intialized your application as `app` inside `api.py`.
34-
35-
```
36-
project
37-
├── api.py
38-
├── requirements.txt
39-
└── serverless.yml
19+
- serverless-python-requirements
4020
```
4121
42-
### api.py
4322
44-
A regular Flask application.
23+
## Adding the dependencies to `sys.path`
4524

25+
`serverless-python-requirements` adds a module called `requirements` to your
26+
puck. To easily make the bundled dependencies available, simply import it. Eg.
27+
add this to the top of any file using dependencies specified in your
28+
`requirements.txt`:
4629
```python
47-
from flask import Flask
48-
app = Flask(__name__)
49-
50-
51-
@app.route("/cats")
52-
def cats():
53-
return "Cats"
54-
55-
56-
@app.route("/dogs/<id>")
57-
def dog(id):
58-
return "Dog"
59-
```
60-
61-
### serverless.yml
62-
63-
Load the plugin and set the `custom.wsgi.app` configuration in `serverless.yml` to the
64-
module path of your Flask application.
65-
66-
All functions that will use WSGI need to have `wsgi.handler` set as the Lambda handler and
67-
use the `lambda-proxy` integration for API Gateway.
68-
69-
```yaml
70-
service: example
71-
72-
provider:
73-
name: aws
74-
runtime: python2.7
75-
76-
plugins:
77-
- serverless-wsgi
78-
79-
functions:
80-
api:
81-
handler: wsgi.handler
82-
events:
83-
- http:
84-
path: cats
85-
method: get
86-
integration: lambda-proxy
87-
- http:
88-
path: dogs/{id}
89-
method: get
90-
integration: lambda-proxy
91-
92-
custom:
93-
wsgi:
94-
app: api.app
95-
```
96-
97-
### requirements.txt
98-
99-
Add Flask to the application bundle.
100-
101-
```
102-
Flask==0.11.1
103-
```
104-
105-
106-
## Deployment
107-
108-
Simply run the serverless deploy command as usual:
109-
110-
```
111-
$ sls deploy
112-
Serverless: Packaging Python WSGI handler...
113-
Serverless: Packaging required Python packages...
114-
Serverless: Packaging service...
115-
Serverless: Removing old service versions...
116-
Serverless: Uploading CloudFormation file to S3...
117-
Serverless: Uploading service .zip file to S3...
118-
Serverless: Updating Stack...
119-
Serverless: Checking Stack update progress...
120-
..........
121-
Serverless: Stack update finished...
122-
```
123-
124-
125-
## Other frameworks
126-
127-
Set `custom.wsgi.app` in `serverless.yml` according to your WSGI callable:
128-
129-
* For Pyramid, use [make_wsgi_app](http://docs.pylonsproject.org/projects/pyramid/en/latest/api/config.html#pyramid.config.Configurator.make_wsgi_app) to intialize the callable
130-
* Django is configured for WSGI by default, set the callable to `<project_name>.wsgi.application`. See [https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/](https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/) for more information.
131-
132-
133-
## Usage
134-
135-
### Automatic requirement packaging
136-
137-
You'll need to include any packages that your application uses in the bundle
138-
that's deployed to AWS Lambda. This plugin helps you out by doing this automatically,
139-
as long as you specify your required packages in a `requirements.txt` file in the root
140-
of your Serverless service path:
141-
142-
```
143-
Flask==0.11.1
144-
requests==2.11.1
145-
```
146-
147-
For more information, see [https://pip.readthedocs.io/en/1.1/requirements.html](https://pip.readthedocs.io/en/1.1/requirements.html).
148-
149-
### Local server
150-
151-
For convenience, a `sls wsgi serve` command is provided to run your WSGI application
152-
locally. This command requires the `werkzeug` Python package to be installed,
153-
and acts as a simple wrapper for starting werkzeug's built-in HTTP server.
154-
155-
By default, the server will start on port 5000.
156-
157-
```
158-
$ sls wsgi serve
159-
* Running on http://localhost:5000/ (Press CTRL+C to quit)
160-
* Restarting with stat
161-
* Debugger is active!
162-
```
163-
164-
Configure the port using the `-p` parameter:
165-
166-
```
167-
$ sls wsgi serve -p 8000
168-
* Running on http://localhost:8000/ (Press CTRL+C to quit)
169-
* Restarting with stat
170-
* Debugger is active!
30+
import requirements
31+
# Now you can use deps you specified in requirements.txt!
32+
import requests
17133
```

index.js

Lines changed: 14 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,13 @@ const child_process = require('child_process');
99

1010
BbPromise.promisifyAll(fse);
1111

12-
class ServerlessWSGI {
13-
validate() {
14-
if (this.serverless.service.custom && this.serverless.service.custom.wsgi && this.serverless.service.custom.wsgi.app) {
15-
this.wsgiApp = this.serverless.service.custom.wsgi.app;
16-
} else {
17-
throw new this.serverless.classes.Error(
18-
'Missing WSGI app, please specify custom.wsgi.app. For instance, if you have a Flask application "app" in "api.py", set the Serverless custom.wsgi.app configuration option to: api.app');
19-
}
20-
};
12+
class ServerlessPythonRequirements {
13+
packVendorHelper() {
14+
this.serverless.cli.log('Packaging Python requirements helper...');
2115

22-
packWsgiHandler() {
23-
this.serverless.cli.log('Packaging Python WSGI handler...');
24-
25-
return BbPromise.all([
26-
fse.copyAsync(
27-
path.resolve(__dirname, 'wsgi.py'),
28-
path.join(this.serverless.config.servicePath, 'wsgi.py')),
29-
fse.writeFileAsync(
30-
path.join(this.serverless.config.servicePath, '.wsgi_app'),
31-
this.wsgiApp)
32-
]);
16+
return fse.copyAsync(
17+
path.resolve(__dirname, 'requirements.py'),
18+
path.join(this.serverless.config.servicePath, 'requirements.py'));
3319
};
3420

3521
packRequirements() {
@@ -42,11 +28,12 @@ class ServerlessWSGI {
4228
this.serverless.cli.log('Packaging required Python packages...');
4329

4430
return new BbPromise((resolve, reject) => {
45-
const res = child_process.spawnSync('python', [
46-
path.resolve(__dirname, 'requirements.py'),
47-
path.resolve(__dirname, 'requirements.txt'),
31+
const res = child_process.spawnSync('pip', [
32+
'install',
33+
'-t',
34+
path.join(this.serverless.config.servicePath, '.requirements'),
35+
'-r',
4836
requirementsFile,
49-
path.join(this.serverless.config.servicePath, '.requirements')
5037
]);
5138
if (res.error) {
5239
return reject(res.error);
@@ -59,7 +46,7 @@ class ServerlessWSGI {
5946
};
6047

6148
cleanup() {
62-
const artifacts = ['wsgi.py', '.wsgi_app', '.requirements'];
49+
const artifacts = ['requirements.py', '.requirements'];
6350

6451
return BbPromise.all(_.map(artifacts, (artifact) =>
6552
fse.removeAsync(path.join(this.serverless.config.servicePath, artifact))));;
@@ -83,39 +70,15 @@ class ServerlessWSGI {
8370
this.serverless = serverless;
8471
this.options = options;
8572

86-
this.commands = {
87-
wsgi: {
88-
commands: {
89-
serve: {
90-
usage: 'Serve the WSGI application locally.',
91-
lifecycleEvents: [
92-
'serve',
93-
],
94-
options: {
95-
port: {
96-
usage: 'The local server port, defaults to 5000.',
97-
shortcut: 'p',
98-
},
99-
},
100-
},
101-
},
102-
},
103-
};
104-
10573
this.hooks = {
10674
'before:deploy:createDeploymentArtifacts': () => BbPromise.bind(this)
107-
.then(this.validate)
108-
.then(this.packWsgiHandler)
75+
.then(this.packVendorHelper)
10976
.then(this.packRequirements),
11077

11178
'after:deploy:createDeploymentArtifacts': () => BbPromise.bind(this)
11279
.then(this.cleanup),
113-
114-
'wsgi:serve:serve': () => BbPromise.bind(this)
115-
.then(this.validate)
116-
.then(this.serve)
11780
};
11881
}
11982
}
12083

121-
module.exports = ServerlessWSGI;
84+
module.exports = ServerlessPythonRequirements;

package.json

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
{
2-
"name": "serverless-wsgi",
2+
"name": "serverless-python-requirements",
33
"version": "1.0.0",
44
"engines": {
55
"node": ">=4.0"
66
},
7-
"description": "Serverless WSGI Plugin",
8-
"author": "logan.dk",
7+
"description": "Serverless Python Requirements Plugin",
8+
"author": "United Income <[email protected]>",
99
"license": "MIT",
1010
"repository": {
1111
"type": "git",
12-
"url": "https://github.com/logandk/serverless-wsgi"
12+
"url": "https://github.com/UnitedIncome/serverless-python-requirements"
1313
},
1414
"keywords": [
1515
"serverless",
16-
"wsgi",
17-
"flask",
16+
"python",
17+
"requirements",
18+
"pip",
1819
"serverless framework plugin",
1920
"serverless applications",
2021
"serverless plugins",
@@ -30,11 +31,8 @@
3031
"index.js",
3132
"LICENSE",
3233
"package.json",
33-
"README.md",
3434
"requirements.py",
35-
"requirements.txt",
36-
"serve.py",
37-
"wsgi.py"
35+
"README.md"
3836
],
3937
"main": "index.js",
4038
"bin": {},

0 commit comments

Comments
 (0)