Skip to content

Commit 1436c17

Browse files
authored
Add support for specifying custom dependency groups in Poetry (serverless#746)
1 parent 012b55f commit 1436c17

File tree

10 files changed

+153
-0
lines changed

10 files changed

+153
-0
lines changed

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,16 @@ custom:
141141
requirePoetryLockFile: false
142142
```
143143

144+
If your Poetry configuration includes custom dependency groups, they will not be installed automatically. To include them in the deployment package, use the `poetryWithGroups`, `poetryWithoutGroups` and `poetryOnlyGroups` options which wrap `poetry export`'s `--with`, `--without` and `--only` parameters.
145+
146+
```yaml
147+
custom:
148+
pythonRequirements:
149+
poetryWithGroups:
150+
- internal_dependencies
151+
- lambda_dependencies
152+
```
153+
144154
### Poetry with git dependencies
145155

146156
Poetry by default generates the exported requirements.txt file with `-e` and that breaks pip with `-t` parameter

index.js

+3
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ class ServerlessPythonRequirements {
5858
noDeploy: [],
5959
vendor: '',
6060
requirePoetryLockFile: false,
61+
poetryWithGroups: [],
62+
poetryWithoutGroups: [],
63+
poetryOnlyGroups: [],
6164
},
6265
(this.serverless.service.custom &&
6366
this.serverless.service.custom.pythonRequirements) ||

lib/poetry.js

+9
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ async function pyprojectTomlToRequirements(modulePath, pluginInstance) {
5757
'-o',
5858
'requirements.txt',
5959
'--with-credentials',
60+
...(options.poetryWithGroups.length
61+
? [`--with=${options.poetryWithGroups.join(',')}`]
62+
: []),
63+
...(options.poetryWithoutGroups.length
64+
? [`--without=${options.poetryWithoutGroups.join(',')}`]
65+
: []),
66+
...(options.poetryOnlyGroups.length
67+
? [`--only=${options.poetryOnlyGroups.join(',')}`]
68+
: []),
6069
],
6170
{
6271
cwd: moduleProjectPath,

test.js

+49
Original file line numberDiff line numberDiff line change
@@ -1654,3 +1654,52 @@ test('poetry py3.7 fails packaging if poetry.lock is missing and flag requirePoe
16541654
);
16551655
t.end();
16561656
});
1657+
1658+
test('poetry py3.7 packages additional optional packages', async (t) => {
1659+
process.chdir('tests/poetry_packages');
1660+
const path = npm(['pack', '../..']);
1661+
npm(['i', path]);
1662+
sls(['package'], {
1663+
env: {
1664+
poetryWithGroups: 'poetryWithGroups',
1665+
},
1666+
});
1667+
const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip');
1668+
t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged');
1669+
t.true(zipfiles.includes(`bottle.py`), 'bottle is packaged');
1670+
t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged');
1671+
t.end();
1672+
});
1673+
1674+
test('poetry py3.7 skips additional optional packages specified in withoutGroups', async (t) => {
1675+
process.chdir('tests/poetry_packages');
1676+
const path = npm(['pack', '../..']);
1677+
npm(['i', path]);
1678+
sls(['package'], {
1679+
env: {
1680+
poetryWithGroups: 'poetryWithGroups',
1681+
poetryWithoutGroups: 'poetryWithoutGroups',
1682+
},
1683+
});
1684+
const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip');
1685+
t.true(zipfiles.includes(`flask${sep}__init__.py`), 'flask is packaged');
1686+
t.false(zipfiles.includes(`bottle.py`), 'bottle is NOT packaged');
1687+
t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged');
1688+
t.end();
1689+
});
1690+
1691+
test('poetry py3.7 only installs optional packages specified in onlyGroups', async (t) => {
1692+
process.chdir('tests/poetry_packages');
1693+
const path = npm(['pack', '../..']);
1694+
npm(['i', path]);
1695+
sls(['package'], {
1696+
env: {
1697+
poetryOnlyGroups: 'poetryOnlyGroups',
1698+
},
1699+
});
1700+
const zipfiles = await listZipFiles('.serverless/sls-py-req-test.zip');
1701+
t.false(zipfiles.includes(`flask${sep}__init__.py`), 'flask is NOT packaged');
1702+
t.false(zipfiles.includes(`bottle.py`), 'bottle is NOT packaged');
1703+
t.true(zipfiles.includes(`boto3${sep}__init__.py`), 'boto3 is packaged');
1704+
t.end();
1705+
});
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
empty: []
2+
poetryWithGroups:
3+
- custom1
4+
- custom2
5+
poetryWithoutGroups:
6+
- custom1
7+
poetryOnlyGroups:
8+
- custom2
+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
slimPatterns:
2+
- '**/__main__.py'

tests/poetry_packages/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()

tests/poetry_packages/package.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-6.0.0.tgz"
13+
}
14+
}

tests/poetry_packages/pyproject.toml

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[tool.poetry]
2+
name = "poetry"
3+
version = "0.1.0"
4+
description = ""
5+
authors = ["Your Name <[email protected]>"]
6+
7+
[tool.poetry.dependencies]
8+
python = "^3.6"
9+
Flask = "^1.0"
10+
11+
[tool.poetry.group.custom1.dependencies]
12+
bottle = {git = "https://[email protected]/bottlepy/bottle.git", tag = "0.12.16"}
13+
14+
[tool.poetry.group.custom2.dependencies]
15+
boto3 = "^1.9"
16+
17+
[build-system]
18+
requires = ["poetry-core"]
19+
build-backend = "poetry.core.masonry.api"

tests/poetry_packages/serverless.yml

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
service: sls-py-req-test
2+
3+
provider:
4+
name: aws
5+
runtime: python3.7
6+
7+
plugins:
8+
- serverless-python-requirements
9+
custom:
10+
pythonRequirements:
11+
zip: ${env:zip, self:custom.defaults.zip}
12+
slim: ${env:slim, self:custom.defaults.slim}
13+
slimPatterns: ${file(./slimPatterns.yml):slimPatterns, self:custom.defaults.slimPatterns}
14+
slimPatternsAppendDefaults: ${env:slimPatternsAppendDefaults, self:custom.defaults.slimPatternsAppendDefaults}
15+
dockerizePip: ${env:dockerizePip, self:custom.defaults.dockerizePip}
16+
requirePoetryLockFile: ${env:requirePoetryLockFile, false}
17+
poetryWithGroups: ${file(./_poetryGroups.yml):${env:poetryWithGroups, "empty"}}
18+
poetryWithoutGroups: ${file(./_poetryGroups.yml):${env:poetryWithoutGroups, "empty"}}
19+
poetryOnlyGroups: ${file(./_poetryGroups.yml):${env:poetryOnlyGroups, "empty"}}
20+
defaults:
21+
zip: false
22+
slimPatterns: false
23+
slimPatternsAppendDefaults: true
24+
slim: false
25+
dockerizePip: false
26+
27+
package:
28+
patterns:
29+
- '!**/*'
30+
- 'handler.py'
31+
32+
functions:
33+
hello:
34+
handler: handler.hello

0 commit comments

Comments
 (0)