Skip to content

Commit dfe425b

Browse files
committed
Parse pyproject.toml to determine poetry use.
Why: * The pyproject.toml file is for more than just poetry. This change addresses the need by: * Add test for use case where pyproject.toml is only used for black. * Add toml parser to package.json. * Update poetry.js to base poetry usage on whether or not the build system requires it. Fixes: #324
1 parent 1c14588 commit dfe425b

File tree

9 files changed

+116
-6
lines changed

9 files changed

+116
-6
lines changed

lib/poetry.js

+28-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1+
const fs = require('fs');
12
const fse = require('fs-extra');
23
const path = require('path');
34
const { spawnSync } = require('child_process');
5+
const tomlParse = require('@iarna/toml/parse-string');
46

57
/**
68
* poetry install
79
*/
810
function pyprojectTomlToRequirements() {
9-
if (
10-
!this.options.usePoetry ||
11-
!fse.existsSync(path.join(this.servicePath, 'pyproject.toml'))
12-
) {
11+
if (!this.options.usePoetry || !isPoetryProject(this.servicePath)) {
1312
return;
1413
}
1514

@@ -40,4 +39,29 @@ function pyprojectTomlToRequirements() {
4039
);
4140
}
4241

42+
/**
43+
* Check if pyproject.toml file exists and is a poetry project.
44+
*/
45+
function isPoetryProject(servicePath) {
46+
const pyprojectPath = path.join(servicePath, 'pyproject.toml');
47+
48+
if (!fse.existsSync(pyprojectPath)) {
49+
return false;
50+
}
51+
52+
const pyprojectToml = fs.readFileSync(pyprojectPath);
53+
const pyproject = tomlParse(pyprojectToml);
54+
55+
const buildSystemReqs =
56+
(pyproject['build-system'] && pyproject['build-system']['requires']) || [];
57+
58+
for (var i = 0; i < buildSystemReqs.length; i++) {
59+
if (buildSystemReqs[i].startsWith('poetry')) {
60+
return true;
61+
}
62+
}
63+
64+
return false;
65+
}
66+
4367
module.exports = { pyprojectTomlToRequirements };

package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"tape": "*"
5151
},
5252
"dependencies": {
53+
"@iarna/toml": "^2.2.3",
5354
"appdirectory": "^0.1.0",
5455
"bluebird": "^3.0.6",
5556
"fs-extra": "^7.0.0",
@@ -61,8 +62,8 @@
6162
"lodash.uniqby": "^4.0.0",
6263
"lodash.values": "^4.3.0",
6364
"rimraf": "^2.6.2",
64-
"shell-quote": "^1.6.1",
65-
"sha256-file": "1.0.0"
65+
"sha256-file": "1.0.0",
66+
"shell-quote": "^1.6.1"
6667
},
6768
"eslintConfig": {
6869
"extends": "eslint:recommended",

test.js

+11
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,17 @@ test("pipenv py3.6 doesn't package bottle with noDeploy option", t => {
712712
t.end();
713713
});
714714

715+
test('non build pyproject.toml uses requirements.txt', t => {
716+
process.chdir('tests/non_build_pyproject');
717+
const path = npm(['pack', '../..']);
718+
npm(['i', path]);
719+
sls(['package']);
720+
const zipfiles = listZipFiles('.serverless/sls-py-req-test.zip');
721+
t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged');
722+
t.false(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is NOT packaged');
723+
t.end();
724+
});
725+
715726
test('poetry py3.6 can package flask with default options', t => {
716727
process.chdir('tests/poetry');
717728
const path = npm(['pack', '../..']);

tests/non_build_pyproject/.gitignore

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Distribution / packaging
2+
.Python
3+
env/
4+
build/
5+
develop-eggs/
6+
dist/
7+
downloads/
8+
eggs/
9+
.eggs/
10+
lib/
11+
lib64/
12+
parts/
13+
sdist/
14+
var/
15+
*.egg-info/
16+
.installed.cfg
17+
*.egg
18+
19+
# Serverless
20+
.serverless
21+
.requirements
22+
unzip_requirements.py

tests/non_build_pyproject/handler.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import requests
2+
3+
4+
def hello(event, context):
5+
return requests.get('https://httpbin.org/get').json()
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "example",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"author": "",
10+
"license": "ISC",
11+
"dependencies": {
12+
"serverless-python-requirements": "file:serverless-python-requirements-4.2.5.tgz"
13+
}
14+
}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[tool.black]
2+
line-length = 79
3+
py36 = true
4+
skip-string-normalization = true
5+
exclude = '''
6+
/(
7+
\.serverless
8+
| node_modules
9+
)/
10+
'''
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
flask
2+
boto3
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
service: sls-py-req-test
2+
3+
provider:
4+
name: aws
5+
runtime: python3.6
6+
7+
plugins:
8+
- serverless-python-requirements
9+
custom:
10+
pythonRequirements:
11+
usePoetry: false
12+
13+
package:
14+
exclude:
15+
- '**/*'
16+
include:
17+
- handler.py
18+
19+
functions:
20+
hello:
21+
handler: handler.hello

0 commit comments

Comments
 (0)