diff --git a/lib/poetry.js b/lib/poetry.js index 0ddf8da7..53b521e0 100644 --- a/lib/poetry.js +++ b/lib/poetry.js @@ -1,15 +1,14 @@ +const fs = require('fs'); const fse = require('fs-extra'); const path = require('path'); const { spawnSync } = require('child_process'); +const tomlParse = require('@iarna/toml/parse-string'); /** * poetry install */ function pyprojectTomlToRequirements() { - if ( - !this.options.usePoetry || - !fse.existsSync(path.join(this.servicePath, 'pyproject.toml')) - ) { + if (!this.options.usePoetry || !isPoetryProject(this.servicePath)) { return; } @@ -40,4 +39,29 @@ function pyprojectTomlToRequirements() { ); } +/** + * Check if pyproject.toml file exists and is a poetry project. + */ +function isPoetryProject(servicePath) { + const pyprojectPath = path.join(servicePath, 'pyproject.toml'); + + if (!fse.existsSync(pyprojectPath)) { + return false; + } + + const pyprojectToml = fs.readFileSync(pyprojectPath); + const pyproject = tomlParse(pyprojectToml); + + const buildSystemReqs = + (pyproject['build-system'] && pyproject['build-system']['requires']) || []; + + for (var i = 0; i < buildSystemReqs.length; i++) { + if (buildSystemReqs[i].startsWith('poetry')) { + return true; + } + } + + return false; +} + module.exports = { pyprojectTomlToRequirements }; diff --git a/package.json b/package.json index 1178d436..e105fead 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "tape": "*" }, "dependencies": { + "@iarna/toml": "^2.2.3", "appdirectory": "^0.1.0", "bluebird": "^3.0.6", "fs-extra": "^7.0.0", @@ -61,8 +62,8 @@ "lodash.uniqby": "^4.0.0", "lodash.values": "^4.3.0", "rimraf": "^2.6.2", - "shell-quote": "^1.6.1", - "sha256-file": "1.0.0" + "sha256-file": "1.0.0", + "shell-quote": "^1.6.1" }, "eslintConfig": { "extends": "eslint:recommended", diff --git a/test.js b/test.js index 78f60aad..55f083c1 100644 --- a/test.js +++ b/test.js @@ -712,6 +712,17 @@ test("pipenv py3.6 doesn't package bottle with noDeploy option", t => { t.end(); }); +test('non build pyproject.toml uses requirements.txt', t => { + process.chdir('tests/non_build_pyproject'); + const path = npm(['pack', '../..']); + npm(['i', path]); + sls(['package']); + const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip'); + t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged'); + t.false(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is NOT packaged'); + t.end(); +}); + test('poetry py3.6 can package flask with default options', t => { process.chdir('tests/poetry'); const path = npm(['pack', '../..']); diff --git a/tests/non_build_pyproject/.gitignore b/tests/non_build_pyproject/.gitignore new file mode 100644 index 00000000..3c2369dc --- /dev/null +++ b/tests/non_build_pyproject/.gitignore @@ -0,0 +1,22 @@ +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# Serverless +.serverless +.requirements +unzip_requirements.py diff --git a/tests/non_build_pyproject/handler.py b/tests/non_build_pyproject/handler.py new file mode 100644 index 00000000..5e2e67ff --- /dev/null +++ b/tests/non_build_pyproject/handler.py @@ -0,0 +1,5 @@ +import requests + + +def hello(event, context): + return requests.get('https://httpbin.org/get').json() diff --git a/tests/non_build_pyproject/package.json b/tests/non_build_pyproject/package.json new file mode 100644 index 00000000..d13fd651 --- /dev/null +++ b/tests/non_build_pyproject/package.json @@ -0,0 +1,14 @@ +{ + "name": "example", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "serverless-python-requirements": "file:serverless-python-requirements-4.2.5.tgz" + } +} diff --git a/tests/non_build_pyproject/pyproject.toml b/tests/non_build_pyproject/pyproject.toml new file mode 100644 index 00000000..41932632 --- /dev/null +++ b/tests/non_build_pyproject/pyproject.toml @@ -0,0 +1,10 @@ +[tool.black] +line-length = 79 +py36 = true +skip-string-normalization = true +exclude = ''' +/( + \.serverless + | node_modules +)/ +''' diff --git a/tests/non_build_pyproject/requirements.txt b/tests/non_build_pyproject/requirements.txt new file mode 100644 index 00000000..aa55d989 --- /dev/null +++ b/tests/non_build_pyproject/requirements.txt @@ -0,0 +1,2 @@ +flask +boto3 diff --git a/tests/non_build_pyproject/serverless.yml b/tests/non_build_pyproject/serverless.yml new file mode 100644 index 00000000..973132c8 --- /dev/null +++ b/tests/non_build_pyproject/serverless.yml @@ -0,0 +1,21 @@ +service: sls-py-req-test + +provider: + name: aws + runtime: python3.6 + +plugins: + - serverless-python-requirements +custom: + pythonRequirements: + usePoetry: false + +package: + exclude: + - '**/*' + include: + - handler.py + +functions: + hello: + handler: handler.hello