├── .gitignore ├── README.md ├── handler.py ├── package-lock.json ├── package.json ├── serverless.yml └── tests └── test_handler.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | 103 | # vim 104 | .*.sw* 105 | 106 | # node 107 | node_modules 108 | 109 | # serverless 110 | .serverless 111 | 112 | # IntelliJ 113 | .idea/ 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Serverless Python Starter [![Seed Status](https://api.seed.run/serverless-stack/serverless-python-starter/stages/dev/build_badge)](https://console.seed.run/serverless-stack/serverless-python-starter) 2 | 3 | A Python starter project for [Serverless Framework](https://serverless.com/framework/) with support for dependencies (using [virtualenv](https://pypi.python.org/pypi/virtualenv) & [serverless-python-requirements](https://github.com/UnitedIncome/serverless-python-requirements)) and tests (using [unittest](https://docs.python.org/2/library/unittest.html#module-unittest)). 4 | 5 | ### Demo 6 | 7 | A demo version of this service is hosted on AWS - [`https://udshnoxw3k.execute-api.us-east-1.amazonaws.com/dev`](https://udshnoxw3k.execute-api.us-east-1.amazonaws.com/dev) 8 | 9 | ### Requirements 10 | 11 | - [Install Python](https://www.python.org/downloads/release/python-363/) 12 | - [Install Virtualenv](https://virtualenv.pypa.io/en/stable/installation/) 13 | - [Install the Serverless Framework](https://serverless.com/framework/docs/providers/aws/guide/installation/) 14 | - [Configure your AWS CLI](https://serverless.com/framework/docs/providers/aws/guide/credentials/) 15 | 16 | ### Installation 17 | 18 | Create a new project 19 | 20 | ```sh 21 | $ serverless install --url https://github.com/AnomalyInnovations/serverless-python-starter --name my-project 22 | ``` 23 | 24 | Create a virtual environment for your project 25 | 26 | ```sh 27 | $ cd my-project 28 | $ virtualenv -p /usr/bin/python3.6 venv 29 | ``` 30 | 31 | Activate the virtual environment 32 | 33 | ```sh 34 | $ source venv/bin/activate 35 | ``` 36 | 37 | Install Serverless plugin: serverless-python-requirements 38 | 39 | ```sh 40 | $ npm install 41 | ``` 42 | 43 | ### Usage 44 | 45 | Install a Python dependency (for example, [Requests](http://docs.python-requests.org/en/master/)) 46 | 47 | ```sh 48 | $ pip install requests 49 | ``` 50 | 51 | Store a reference to your dependencies 52 | 53 | ```sh 54 | $ pip freeze > requirements.txt 55 | ``` 56 | 57 | Re-install your dependencies from your requirements 58 | 59 | ```sh 60 | $ pip install -r requirements.txt 61 | ``` 62 | 63 | Invoke a function locally 64 | 65 | ``` 66 | $ serverless invoke local -f hello 67 | ``` 68 | 69 | Run your tests 70 | ``` 71 | $ python -m unittest discover -s tests 72 | ``` 73 | 74 | Deactivate your virtual environment 75 | 76 | ```sh 77 | $ deactivate 78 | ``` 79 | 80 | ### Deploying 81 | 82 | Deploy your project 83 | 84 | ```sh 85 | $ serverless deploy 86 | ``` 87 | 88 | Deploy a single function 89 | 90 | ```sh 91 | $ serverless deploy function --function hello 92 | ``` 93 | 94 | To compile non-pure Python modules, install [Docker](https://docs.docker.com/engine/installation/) and the [Lambda Docker Image](https://github.com/lambci/docker-lambda). Enable **dockerizePip** in **serverless.yml** and `serverless deploy` again. 95 | 96 | ```yml 97 | # enable dockerize Pip 98 | custom: 99 | pythonRequirements: 100 | dockerizePip: true 101 | ``` 102 | 103 | **Note**, if you are deploying using [SEED](https://seed.run), you don't need to enable **dockerizePip** or install Docker. [SEED](https://seed.run) does it automatically. 104 | 105 | ### Support 106 | 107 | - Send us an [email](mailto:contact@anoma.ly) if you have any questions 108 | - Open a [new issue](https://github.com/AnomalyInnovations/serverless-python-starter/issues/new) if you've found a bug or have some suggestions. 109 | - Or submit a pull request! 110 | 111 | ### Maintainers 112 | 113 | Maintained by Frank Wang ([@fanjiewang](https://twitter.com/fanjiewang)) & Jay V ([@jayair](https://twitter.com/jayair)). [**Subscribe to our newsletter**](http://eepurl.com/cEaBlf) for updates. Send us an [email](mailto:contact@anoma.ly) if you have any questions. 114 | -------------------------------------------------------------------------------- /handler.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | def hello(event, context): 4 | body = { 5 | "message": "Go Serverless v1.0! Your function executed successfully!", 6 | } 7 | 8 | return { 9 | "statusCode": 200, 10 | "body": json.dumps(body) 11 | } 12 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "python-hello-sls-plugin", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "archiver": { 8 | "version": "1.3.0", 9 | "resolved": "https://registry.npmjs.org/archiver/-/archiver-1.3.0.tgz", 10 | "integrity": "sha1-TyGU1tj5nfP1MeaIHxTxXVX6ryI=", 11 | "requires": { 12 | "archiver-utils": "1.3.0", 13 | "async": "2.6.0", 14 | "buffer-crc32": "0.2.13", 15 | "glob": "7.1.2", 16 | "lodash": "4.17.4", 17 | "readable-stream": "2.3.3", 18 | "tar-stream": "1.5.4", 19 | "walkdir": "0.0.11", 20 | "zip-stream": "1.2.0" 21 | } 22 | }, 23 | "archiver-utils": { 24 | "version": "1.3.0", 25 | "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz", 26 | "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=", 27 | "requires": { 28 | "glob": "7.1.2", 29 | "graceful-fs": "4.1.11", 30 | "lazystream": "1.0.0", 31 | "lodash": "4.17.4", 32 | "normalize-path": "2.1.1", 33 | "readable-stream": "2.3.3" 34 | } 35 | }, 36 | "async": { 37 | "version": "2.6.0", 38 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", 39 | "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", 40 | "requires": { 41 | "lodash": "4.17.4" 42 | } 43 | }, 44 | "balanced-match": { 45 | "version": "1.0.0", 46 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 47 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 48 | }, 49 | "bl": { 50 | "version": "1.2.1", 51 | "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz", 52 | "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=", 53 | "requires": { 54 | "readable-stream": "2.3.3" 55 | } 56 | }, 57 | "bluebird": { 58 | "version": "3.5.1", 59 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", 60 | "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" 61 | }, 62 | "brace-expansion": { 63 | "version": "1.1.8", 64 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", 65 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", 66 | "requires": { 67 | "balanced-match": "1.0.0", 68 | "concat-map": "0.0.1" 69 | } 70 | }, 71 | "buffer-crc32": { 72 | "version": "0.2.13", 73 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", 74 | "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" 75 | }, 76 | "compress-commons": { 77 | "version": "1.2.2", 78 | "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.2.tgz", 79 | "integrity": "sha1-UkqfEJA/OoEzibAiXSfEi7dRiQ8=", 80 | "requires": { 81 | "buffer-crc32": "0.2.13", 82 | "crc32-stream": "2.0.0", 83 | "normalize-path": "2.1.1", 84 | "readable-stream": "2.3.3" 85 | } 86 | }, 87 | "concat-map": { 88 | "version": "0.0.1", 89 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 90 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 91 | }, 92 | "core-util-is": { 93 | "version": "1.0.2", 94 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 95 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 96 | }, 97 | "crc": { 98 | "version": "3.5.0", 99 | "resolved": "https://registry.npmjs.org/crc/-/crc-3.5.0.tgz", 100 | "integrity": "sha1-mLi6fUiWZbo5efWbITgTdBAaGWQ=" 101 | }, 102 | "crc32-stream": { 103 | "version": "2.0.0", 104 | "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz", 105 | "integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=", 106 | "requires": { 107 | "crc": "3.5.0", 108 | "readable-stream": "2.3.3" 109 | } 110 | }, 111 | "end-of-stream": { 112 | "version": "1.4.0", 113 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", 114 | "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", 115 | "requires": { 116 | "once": "1.4.0" 117 | } 118 | }, 119 | "fs-extra": { 120 | "version": "3.0.1", 121 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", 122 | "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", 123 | "requires": { 124 | "graceful-fs": "4.1.11", 125 | "jsonfile": "3.0.1", 126 | "universalify": "0.1.1" 127 | } 128 | }, 129 | "fs.realpath": { 130 | "version": "1.0.0", 131 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 132 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 133 | }, 134 | "glob": { 135 | "version": "7.1.2", 136 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 137 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 138 | "requires": { 139 | "fs.realpath": "1.0.0", 140 | "inflight": "1.0.6", 141 | "inherits": "2.0.3", 142 | "minimatch": "3.0.4", 143 | "once": "1.4.0", 144 | "path-is-absolute": "1.0.1" 145 | } 146 | }, 147 | "glob-all": { 148 | "version": "3.1.0", 149 | "resolved": "https://registry.npmjs.org/glob-all/-/glob-all-3.1.0.tgz", 150 | "integrity": "sha1-iRPd+17hrHgSZWJBsD1SF8ZLAqs=", 151 | "requires": { 152 | "glob": "7.1.2", 153 | "yargs": "1.2.6" 154 | } 155 | }, 156 | "graceful-fs": { 157 | "version": "4.1.11", 158 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 159 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" 160 | }, 161 | "inflight": { 162 | "version": "1.0.6", 163 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 164 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 165 | "requires": { 166 | "once": "1.4.0", 167 | "wrappy": "1.0.2" 168 | } 169 | }, 170 | "inherits": { 171 | "version": "2.0.3", 172 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 173 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 174 | }, 175 | "isarray": { 176 | "version": "1.0.0", 177 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 178 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 179 | }, 180 | "jsonfile": { 181 | "version": "3.0.1", 182 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", 183 | "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", 184 | "requires": { 185 | "graceful-fs": "4.1.11" 186 | } 187 | }, 188 | "lazystream": { 189 | "version": "1.0.0", 190 | "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", 191 | "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", 192 | "requires": { 193 | "readable-stream": "2.3.3" 194 | } 195 | }, 196 | "lodash": { 197 | "version": "4.17.4", 198 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", 199 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" 200 | }, 201 | "minimatch": { 202 | "version": "3.0.4", 203 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 204 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 205 | "requires": { 206 | "brace-expansion": "1.1.8" 207 | } 208 | }, 209 | "minimist": { 210 | "version": "0.1.0", 211 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.1.0.tgz", 212 | "integrity": "sha1-md9lelJXTCHJBXSX33QnkLK0wN4=" 213 | }, 214 | "normalize-path": { 215 | "version": "2.1.1", 216 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", 217 | "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", 218 | "requires": { 219 | "remove-trailing-separator": "1.1.0" 220 | } 221 | }, 222 | "once": { 223 | "version": "1.4.0", 224 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 225 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 226 | "requires": { 227 | "wrappy": "1.0.2" 228 | } 229 | }, 230 | "path-is-absolute": { 231 | "version": "1.0.1", 232 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 233 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 234 | }, 235 | "process-nextick-args": { 236 | "version": "1.0.7", 237 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", 238 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" 239 | }, 240 | "readable-stream": { 241 | "version": "2.3.3", 242 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", 243 | "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", 244 | "requires": { 245 | "core-util-is": "1.0.2", 246 | "inherits": "2.0.3", 247 | "isarray": "1.0.0", 248 | "process-nextick-args": "1.0.7", 249 | "safe-buffer": "5.1.1", 250 | "string_decoder": "1.0.3", 251 | "util-deprecate": "1.0.2" 252 | } 253 | }, 254 | "remove-trailing-separator": { 255 | "version": "1.1.0", 256 | "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", 257 | "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" 258 | }, 259 | "safe-buffer": { 260 | "version": "5.1.1", 261 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 262 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 263 | }, 264 | "serverless-python-requirements": { 265 | "version": "3.0.9", 266 | "resolved": "https://registry.npmjs.org/serverless-python-requirements/-/serverless-python-requirements-3.0.9.tgz", 267 | "integrity": "sha1-qfy0fEy2ujknhHB8gASIRd3EQnY=", 268 | "requires": { 269 | "archiver": "1.3.0", 270 | "bluebird": "3.5.1", 271 | "fs-extra": "3.0.1", 272 | "glob-all": "3.1.0", 273 | "graceful-fs": "4.1.11", 274 | "lodash": "4.17.4" 275 | } 276 | }, 277 | "string_decoder": { 278 | "version": "1.0.3", 279 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", 280 | "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", 281 | "requires": { 282 | "safe-buffer": "5.1.1" 283 | } 284 | }, 285 | "tar-stream": { 286 | "version": "1.5.4", 287 | "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.4.tgz", 288 | "integrity": "sha1-NlSc8E7RrumyowwBQyUiONr5QBY=", 289 | "requires": { 290 | "bl": "1.2.1", 291 | "end-of-stream": "1.4.0", 292 | "readable-stream": "2.3.3", 293 | "xtend": "4.0.1" 294 | } 295 | }, 296 | "universalify": { 297 | "version": "0.1.1", 298 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", 299 | "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" 300 | }, 301 | "util-deprecate": { 302 | "version": "1.0.2", 303 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 304 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 305 | }, 306 | "walkdir": { 307 | "version": "0.0.11", 308 | "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.0.11.tgz", 309 | "integrity": "sha1-oW0CXrkxvQO1LzCMrtD0D86+lTI=" 310 | }, 311 | "wrappy": { 312 | "version": "1.0.2", 313 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 314 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 315 | }, 316 | "xtend": { 317 | "version": "4.0.1", 318 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 319 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" 320 | }, 321 | "yargs": { 322 | "version": "1.2.6", 323 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.2.6.tgz", 324 | "integrity": "sha1-nHtKgv1dWVsr8Xq23MQxNUMv40s=", 325 | "requires": { 326 | "minimist": "0.1.0" 327 | } 328 | }, 329 | "zip-stream": { 330 | "version": "1.2.0", 331 | "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.2.0.tgz", 332 | "integrity": "sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ=", 333 | "requires": { 334 | "archiver-utils": "1.3.0", 335 | "compress-commons": "1.2.2", 336 | "lodash": "4.17.4", 337 | "readable-stream": "2.3.3" 338 | } 339 | } 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "python-hello-sls-plugin", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "tests" 8 | }, 9 | "scripts": { 10 | "test": "python -m unittest discover -s tests" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/AnomalyInnovations/serverless-stack-python-starter.git" 15 | }, 16 | "author": "", 17 | "license": "ISC", 18 | "bugs": { 19 | "url": "https://github.com/AnomalyInnovations/serverless-stack-python-starter/issues" 20 | }, 21 | "homepage": "https://github.com/AnomalyInnovations/serverless-stack-python-starter#readme", 22 | "dependencies": { 23 | "serverless-python-requirements": "^3.0.9" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /serverless.yml: -------------------------------------------------------------------------------- 1 | service: serverless-stack-python-starter 2 | 3 | plugins: 4 | - serverless-python-requirements 5 | 6 | custom: 7 | pythonRequirements: 8 | dockerizePip: false 9 | 10 | provider: 11 | name: aws 12 | runtime: python3.6 13 | stage: dev 14 | region: us-east-1 15 | 16 | functions: 17 | hello: 18 | handler: handler.hello 19 | events: 20 | - http: 21 | path: / 22 | method: get 23 | -------------------------------------------------------------------------------- /tests/test_handler.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from handler import hello 4 | 5 | class HandlerTest(unittest.TestCase): 6 | 7 | def test_event_failsWithNumberAsEvent(self): 8 | response = hello(1, 2) 9 | self.assertEqual(response.get('statusCode'), 200) 10 | self.assertTrue(isinstance(response.get('body'), str)) 11 | --------------------------------------------------------------------------------