Skip to content

Commit 1741fdd

Browse files
aqua-botDmitriyLewennikpivkin
authored
fix(python): add poetry v2 support [backport: release/v0.59] (#8335)
Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Co-authored-by: Nikita Pivkin <nikita.pivkin@smartforce.io>
1 parent 3fd8e27 commit 1741fdd

File tree

13 files changed

+1065
-2199
lines changed

13 files changed

+1065
-2199
lines changed

pkg/dependency/parser/python/poetry/parse.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package poetry
22

33
import (
4+
"slices"
45
"sort"
56

67
"github.com/BurntSushi/toml"
@@ -17,6 +18,7 @@ import (
1718
type Lockfile struct {
1819
Packages []struct {
1920
Category string `toml:"category"`
21+
Groups []string `toml:"groups"`
2022
Description string `toml:"description"`
2123
Marker string `toml:"marker,omitempty"`
2224
Name string `toml:"name"`
@@ -50,15 +52,16 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc
5052
var pkgs []ftypes.Package
5153
var deps []ftypes.Dependency
5254
for _, pkg := range lockfile.Packages {
53-
if pkg.Category == "dev" {
54-
continue
55-
}
56-
5755
pkgID := packageID(pkg.Name, pkg.Version)
5856
pkgs = append(pkgs, ftypes.Package{
5957
ID: pkgID,
6058
Name: pkg.Name,
6159
Version: pkg.Version,
60+
// TODO upgrade logic for working with groups
61+
// Mark only:
62+
// - `category = "dev"`
63+
// - groups without `main`. e.g. `groups = ["dev"]`
64+
Dev: pkg.Category == "dev" || (len(pkg.Groups) > 0 && !slices.Contains(pkg.Groups, "main")),
6265
})
6366

6467
dependsOn := p.parseDependencies(pkg.Dependencies, pkgVersions)

pkg/dependency/parser/python/poetry/parse_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,20 @@ func TestParser_Parse(t *testing.T) {
2525
wantPkgs: poetryNormal,
2626
wantErr: assert.NoError,
2727
},
28-
{
29-
name: "many",
30-
file: "testdata/poetry_many.lock",
31-
wantPkgs: poetryMany,
32-
wantDeps: poetryManyDeps,
33-
wantErr: assert.NoError,
34-
},
3528
{
3629
name: "flask",
3730
file: "testdata/poetry_flask.lock",
3831
wantPkgs: poetryFlask,
3932
wantDeps: poetryFlaskDeps,
4033
wantErr: assert.NoError,
4134
},
35+
{
36+
name: "flask + poetry v2",
37+
file: "testdata/poetry_v2_flask.lock",
38+
wantPkgs: poetryFlask,
39+
wantDeps: poetryV2FlaskDeps,
40+
wantErr: assert.NoError,
41+
},
4242
}
4343
for _, tt := range tests {
4444
t.Run(tt.name, func(t *testing.T) {

pkg/dependency/parser/python/poetry/parse_testcase.go

Lines changed: 36 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -14,122 +14,55 @@ var (
1414
{ID: "pypi@2.1", Name: "pypi", Version: "2.1"},
1515
}
1616

17-
// docker run --name poetry --rm -it python@sha256:e1141f10176d74d1a0e87a7c0a0a5a98dd98ec5ac12ce867768f40c6feae2fd9 sh
18-
// apk add curl
19-
// curl -sSL https://install.python-poetry.org | POETRY_VERSION=1.1.7 python3 -
20-
// export PATH=/root/.local/bin:$PATH
21-
// poetry new many && cd many
22-
// curl -o poetry.lock https://raw.githubusercontent.com/python-poetry/poetry/c8945eb110aeda611cc6721565d7ad0c657d453a/poetry.lock
23-
// curl -o pyproject.toml https://raw.githubusercontent.com/python-poetry/poetry/c8945eb110aeda611cc6721565d7ad0c657d453a/pyproject.toml
24-
// poetry show -a | awk '{gsub(/\(!\)/, ""); printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\"},\n") }'
25-
// `--no-dev` flag uncorrected returns deps. Then need to remove `dev` deps manually
26-
// list of dev deps - cat poetry.lock | grep 'category = "dev"' -B 3
27-
poetryMany = []ftypes.Package{
28-
{ID: "attrs@22.2.0", Name: "attrs", Version: "22.2.0"},
29-
{ID: "backports-cached-property@1.0.2", Name: "backports-cached-property", Version: "1.0.2"},
30-
{ID: "build@0.10.0", Name: "build", Version: "0.10.0"},
31-
{ID: "cachecontrol@0.12.11", Name: "cachecontrol", Version: "0.12.11"},
32-
{ID: "certifi@2022.12.7", Name: "certifi", Version: "2022.12.7"},
33-
{ID: "cffi@1.15.1", Name: "cffi", Version: "1.15.1"},
34-
{ID: "charset-normalizer@3.0.1", Name: "charset-normalizer", Version: "3.0.1"},
35-
{ID: "cleo@2.0.1", Name: "cleo", Version: "2.0.1"},
36-
{ID: "colorama@0.4.6", Name: "colorama", Version: "0.4.6"},
37-
{ID: "crashtest@0.4.1", Name: "crashtest", Version: "0.4.1"},
38-
{ID: "cryptography@39.0.0", Name: "cryptography", Version: "39.0.0"},
39-
{ID: "distlib@0.3.6", Name: "distlib", Version: "0.3.6"},
40-
{ID: "dulwich@0.21.2", Name: "dulwich", Version: "0.21.2"},
41-
{ID: "filelock@3.9.0", Name: "filelock", Version: "3.9.0"},
42-
{ID: "html5lib@1.1", Name: "html5lib", Version: "1.1"},
43-
{ID: "idna@3.4", Name: "idna", Version: "3.4"},
44-
{ID: "importlib-metadata@6.0.0", Name: "importlib-metadata", Version: "6.0.0"},
45-
{ID: "importlib-resources@5.10.2", Name: "importlib-resources", Version: "5.10.2"},
46-
{ID: "installer@0.6.0", Name: "installer", Version: "0.6.0"},
47-
{ID: "jaraco-classes@3.2.3", Name: "jaraco-classes", Version: "3.2.3"},
48-
{ID: "jeepney@0.8.0", Name: "jeepney", Version: "0.8.0"},
49-
{ID: "jsonschema@4.17.3", Name: "jsonschema", Version: "4.17.3"},
50-
{ID: "keyring@23.13.1", Name: "keyring", Version: "23.13.1"},
51-
{ID: "lockfile@0.12.2", Name: "lockfile", Version: "0.12.2"},
52-
{ID: "more-itertools@9.0.0", Name: "more-itertools", Version: "9.0.0"},
53-
{ID: "msgpack@1.0.4", Name: "msgpack", Version: "1.0.4"},
54-
{ID: "packaging@23.0", Name: "packaging", Version: "23.0"},
55-
{ID: "pexpect@4.8.0", Name: "pexpect", Version: "4.8.0"},
56-
{ID: "pkginfo@1.9.6", Name: "pkginfo", Version: "1.9.6"},
57-
{ID: "pkgutil-resolve-name@1.3.10", Name: "pkgutil-resolve-name", Version: "1.3.10"},
58-
{ID: "platformdirs@2.6.2", Name: "platformdirs", Version: "2.6.2"},
59-
{ID: "poetry-core@1.5.0", Name: "poetry-core", Version: "1.5.0"},
60-
{ID: "poetry-plugin-export@1.3.0", Name: "poetry-plugin-export", Version: "1.3.0"},
61-
{ID: "ptyprocess@0.7.0", Name: "ptyprocess", Version: "0.7.0"},
62-
{ID: "pycparser@2.21", Name: "pycparser", Version: "2.21"},
63-
{ID: "pyproject-hooks@1.0.0", Name: "pyproject-hooks", Version: "1.0.0"},
64-
{ID: "pyrsistent@0.19.3", Name: "pyrsistent", Version: "0.19.3"},
65-
{ID: "pywin32-ctypes@0.2.0", Name: "pywin32-ctypes", Version: "0.2.0"},
66-
{ID: "rapidfuzz@2.13.7", Name: "rapidfuzz", Version: "2.13.7"},
67-
{ID: "requests@2.28.2", Name: "requests", Version: "2.28.2"},
68-
{ID: "requests-toolbelt@0.10.1", Name: "requests-toolbelt", Version: "0.10.1"},
69-
{ID: "secretstorage@3.3.3", Name: "secretstorage", Version: "3.3.3"},
70-
{ID: "shellingham@1.5.0.post1", Name: "shellingham", Version: "1.5.0.post1"},
71-
{ID: "six@1.16.0", Name: "six", Version: "1.16.0"},
72-
{ID: "tomli@2.0.1", Name: "tomli", Version: "2.0.1"},
73-
{ID: "tomlkit@0.11.6", Name: "tomlkit", Version: "0.11.6"},
74-
{ID: "trove-classifiers@2023.1.20", Name: "trove-classifiers", Version: "2023.1.20"},
75-
{ID: "typing-extensions@4.4.0", Name: "typing-extensions", Version: "4.4.0"},
76-
{ID: "urllib3@1.26.14", Name: "urllib3", Version: "1.26.14"},
77-
{ID: "virtualenv@20.16.5", Name: "virtualenv", Version: "20.16.5"},
78-
{ID: "virtualenv@20.17.1", Name: "virtualenv", Version: "20.17.1"},
79-
{ID: "webencodings@0.5.1", Name: "webencodings", Version: "0.5.1"},
80-
{ID: "xattr@0.10.1", Name: "xattr", Version: "0.10.1"},
81-
{ID: "zipp@3.12.0", Name: "zipp", Version: "3.12.0"},
82-
}
83-
84-
// cat poetry.lock | grep "\[package.dependencies\]" -B 3 -A 8 - it might help to complete this slice
85-
poetryManyDeps = []ftypes.Dependency{
86-
{ID: "build@0.10.0", DependsOn: []string{"colorama@0.4.6", "importlib-metadata@6.0.0", "packaging@23.0", "pyproject-hooks@1.0.0", "tomli@2.0.1"}},
87-
{ID: "cachecontrol@0.12.11", DependsOn: []string{"lockfile@0.12.2", "msgpack@1.0.4", "requests@2.28.2"}},
88-
{ID: "cffi@1.15.1", DependsOn: []string{"pycparser@2.21"}},
89-
{ID: "cleo@2.0.1", DependsOn: []string{"crashtest@0.4.1", "rapidfuzz@2.13.7"}},
90-
{ID: "cryptography@39.0.0", DependsOn: []string{"cffi@1.15.1"}},
91-
{ID: "dulwich@0.21.2", DependsOn: []string{"typing-extensions@4.4.0", "urllib3@1.26.14"}},
92-
{ID: "html5lib@1.1", DependsOn: []string{"six@1.16.0", "webencodings@0.5.1"}},
93-
{ID: "importlib-metadata@6.0.0", DependsOn: []string{"typing-extensions@4.4.0", "zipp@3.12.0"}},
94-
{ID: "importlib-resources@5.10.2", DependsOn: []string{"zipp@3.12.0"}},
95-
{ID: "jaraco-classes@3.2.3", DependsOn: []string{"more-itertools@9.0.0"}},
96-
{ID: "jsonschema@4.17.3", DependsOn: []string{"attrs@22.2.0", "importlib-metadata@6.0.0", "importlib-resources@5.10.2", "pkgutil-resolve-name@1.3.10", "pyrsistent@0.19.3", "typing-extensions@4.4.0"}},
97-
{ID: "keyring@23.13.1", DependsOn: []string{"importlib-metadata@6.0.0", "importlib-resources@5.10.2", "jaraco-classes@3.2.3", "jeepney@0.8.0", "pywin32-ctypes@0.2.0", "secretstorage@3.3.3"}},
98-
{ID: "pexpect@4.8.0", DependsOn: []string{"ptyprocess@0.7.0"}},
99-
{ID: "platformdirs@2.6.2", DependsOn: []string{"typing-extensions@4.4.0"}},
100-
{ID: "poetry-core@1.5.0", DependsOn: []string{"importlib-metadata@6.0.0"}},
101-
{ID: "poetry-plugin-export@1.3.0", DependsOn: []string{"poetry-core@1.5.0"}},
102-
{ID: "pyproject-hooks@1.0.0", DependsOn: []string{"tomli@2.0.1"}},
103-
{ID: "requests@2.28.2", DependsOn: []string{"certifi@2022.12.7", "charset-normalizer@3.0.1", "idna@3.4", "urllib3@1.26.14"}},
104-
{ID: "requests-toolbelt@0.10.1", DependsOn: []string{"requests@2.28.2"}},
105-
{ID: "secretstorage@3.3.3", DependsOn: []string{"cryptography@39.0.0", "jeepney@0.8.0"}},
106-
{ID: "virtualenv@20.16.5", DependsOn: []string{"distlib@0.3.6", "filelock@3.9.0", "platformdirs@2.6.2"}},
107-
{ID: "virtualenv@20.17.1", DependsOn: []string{"distlib@0.3.6", "filelock@3.9.0", "importlib-metadata@6.0.0", "platformdirs@2.6.2"}},
108-
{ID: "xattr@0.10.1", DependsOn: []string{"cffi@1.15.1"}},
109-
}
110-
11117
// docker run --name poetry --rm -it python@sha256:e1141f10176d74d1a0e87a7c0a0a5a98dd98ec5ac12ce867768f40c6feae2fd9 sh
11218
// apk add curl
11319
// curl -sSL https://install.python-poetry.org | POETRY_VERSION=1.1.7 python3 -
11420
// export PATH=/root/.local/bin:$PATH
11521
// poetry new web && cd web
22+
// poetry add pluggy@0.13.1 -E pre-commit,tox
11623
// poetry add flask@1.0.3
24+
// poetry add pytest@5.4.3 --dev
11725
// poetry show -a | awk '{gsub(/\(!\)/, ""); printf("{ID: \""$1"@"$2"\", Name: \""$1"\", Version: \""$2"\"},\n") }'
26+
// mark dev deps
11827
poetryFlask = []ftypes.Package{
119-
{ID: "click@8.1.3", Name: "click", Version: "8.1.3"},
28+
{ID: "atomicwrites@1.4.1", Name: "atomicwrites", Version: "1.4.1", Dev: true},
29+
{ID: "attrs@25.1.0", Name: "attrs", Version: "25.1.0", Dev: true},
30+
{ID: "click@8.1.8", Name: "click", Version: "8.1.8"},
12031
{ID: "colorama@0.4.6", Name: "colorama", Version: "0.4.6"},
12132
{ID: "flask@1.0.3", Name: "flask", Version: "1.0.3"},
122-
{ID: "itsdangerous@2.1.2", Name: "itsdangerous", Version: "2.1.2"},
123-
{ID: "jinja2@3.1.2", Name: "jinja2", Version: "3.1.2"},
124-
{ID: "markupsafe@2.1.2", Name: "markupsafe", Version: "2.1.2"},
125-
{ID: "werkzeug@2.2.3", Name: "werkzeug", Version: "2.2.3"},
33+
{ID: "itsdangerous@2.2.0", Name: "itsdangerous", Version: "2.2.0"},
34+
{ID: "jinja2@3.1.5", Name: "jinja2", Version: "3.1.5"},
35+
{ID: "markupsafe@3.0.2", Name: "markupsafe", Version: "3.0.2"},
36+
{ID: "more-itertools@10.6.0", Name: "more-itertools", Version: "10.6.0", Dev: true},
37+
{ID: "packaging@24.2", Name: "packaging", Version: "24.2", Dev: true},
38+
{ID: "pluggy@0.13.1", Name: "pluggy", Version: "0.13.1", Dev: false},
39+
{ID: "py@1.11.0", Name: "py", Version: "1.11.0", Dev: true},
40+
{ID: "pytest@5.4.3", Name: "pytest", Version: "5.4.3", Dev: true},
41+
{ID: "wcwidth@0.2.13", Name: "wcwidth", Version: "0.2.13", Dev: true},
42+
{ID: "werkzeug@3.1.3", Name: "werkzeug", Version: "3.1.3"},
12643
}
12744

12845
// cat poetry.lock | grep "\[package.dependencies\]" -B 3 -A 8 - it might help to complete this slice
12946
poetryFlaskDeps = []ftypes.Dependency{
130-
{ID: "click@8.1.3", DependsOn: []string{"colorama@0.4.6"}},
131-
{ID: "flask@1.0.3", DependsOn: []string{"click@8.1.3", "itsdangerous@2.1.2", "jinja2@3.1.2", "werkzeug@2.2.3"}},
132-
{ID: "jinja2@3.1.2", DependsOn: []string{"markupsafe@2.1.2"}},
133-
{ID: "werkzeug@2.2.3", DependsOn: []string{"markupsafe@2.1.2"}},
47+
{ID: "click@8.1.8", DependsOn: []string{"colorama@0.4.6"}},
48+
{ID: "flask@1.0.3", DependsOn: []string{"click@8.1.8", "itsdangerous@2.2.0", "jinja2@3.1.5", "werkzeug@3.1.3"}},
49+
{ID: "jinja2@3.1.5", DependsOn: []string{"markupsafe@3.0.2"}},
50+
{ID: "pytest@5.4.3", DependsOn: []string{"colorama@0.4.6", "pluggy@0.13.1"}},
51+
{ID: "werkzeug@3.1.3", DependsOn: []string{"markupsafe@3.0.2"}},
52+
}
53+
54+
// use instruction above with `POETRY_VERSION=2.0.1`
55+
56+
poetryV2FlaskDeps = []ftypes.Dependency{
57+
{ID: "click@8.1.8", DependsOn: []string{"colorama@0.4.6"}},
58+
{ID: "flask@1.0.3", DependsOn: []string{"click@8.1.8", "itsdangerous@2.2.0", "jinja2@3.1.5", "werkzeug@3.1.3"}},
59+
{ID: "jinja2@3.1.5", DependsOn: []string{"markupsafe@3.0.2"}},
60+
{
61+
ID: "pytest@5.4.3", DependsOn: []string{
62+
"atomicwrites@1.4.1", "attrs@25.1.0", "colorama@0.4.6", "more-itertools@10.6.0", "packaging@24.2",
63+
"pluggy@0.13.1", "py@1.11.0", "wcwidth@0.2.13",
64+
},
65+
},
66+
{ID: "werkzeug@3.1.3", DependsOn: []string{"markupsafe@3.0.2"}},
13467
}
13568
)

0 commit comments

Comments
 (0)