Skip to content

Commit 0b1e07f

Browse files
feat: add support for poetry lock format v2.0 (#469)
Signed-off-by: tewfik-ghariani <tewfik.ghariani@1und1.de> Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com> Co-authored-by: tewfik-ghariani <tewfik.ghariani@1und1.de>
1 parent 895f597 commit 0b1e07f

File tree

6 files changed

+74
-27
lines changed

6 files changed

+74
-27
lines changed

cyclonedx_py/parser/poetry.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ def __init__(
4242
debug_message('loading poetry_lock_contents')
4343
poetry_lock = load_toml(poetry_lock_contents)
4444

45+
poetry_lock_metadata = poetry_lock['metadata']
46+
try:
47+
poetry_lock_version = tuple(int(p) for p in str(poetry_lock_metadata['lock-version']).split('.'))
48+
except Exception:
49+
poetry_lock_version = (0,)
50+
debug_message('detected poetry_lock_version: {!r}', poetry_lock_version)
51+
4552
debug_message('processing poetry_lock')
4653
for package in poetry_lock['package']:
4754
debug_message('processing package: {!r}', package)
@@ -51,7 +58,12 @@ def __init__(
5158
name=package['name'], bom_ref=bom_ref, version=package['version'],
5259
purl=purl
5360
)
54-
for file_metadata in poetry_lock['metadata']['files'][package['name']]:
61+
debug_message('detecting package_files')
62+
package_files = package['files'] \
63+
if poetry_lock_version >= (2,) \
64+
else poetry_lock_metadata['files'][package['name']]
65+
debug_message('processing package_files: {!r}', package_files)
66+
for file_metadata in package_files:
5567
debug_message('processing file_metadata: {!r}', file_metadata)
5668
try:
5769
component.external_references.add(ExternalReference(
@@ -64,7 +76,6 @@ def __init__(
6476
# @todo traceback and details to the output?
6577
debug_message('Warning: suppressed {!r}', error)
6678
del error
67-
6879
self._components.append(component)
6980

7081

poetry.lock

Lines changed: 29 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ toml = "^0.10.0"
4747
[tool.poetry.dev-dependencies]
4848
autopep8 = "^1.6.0"
4949
isort = { version = "^5.10.0", python = ">= 3.6.1" }
50+
ddt = "^1.6.0"
5051
tox = "^3.25.1"
5152
coverage = [
5253
{ python = ">=3.6,<3.7", version = "^6.2", extras = ["toml"] },
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# This file is automatically @generated by Poetry and should not be changed by hand.
2+
3+
[[package]]
4+
name = "toml"
5+
version = "0.10.2"
6+
description = "Python Library for Tom's Obvious, Minimal Language"
7+
category = "main"
8+
optional = false
9+
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
10+
files = [
11+
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
12+
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
13+
]
14+
15+
[metadata]
16+
lock-version = "2.0"
17+
python-versions = "^3.9"
18+
content-hash = "b97d7a3bc03286e93fd688187cbdcd469fe0e5108cdc7936c432995f983f478c"

tests/test_parser_poetry.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,19 @@
2020
import os
2121
from unittest import TestCase
2222

23+
from ddt import data, ddt
24+
2325
from cyclonedx_py.parser.poetry import PoetryFileParser
2426

2527

28+
@ddt
2629
class TestPoetryParser(TestCase):
2730

28-
def test_simple(self) -> None:
29-
tests_poetry_lock_file = os.path.join(os.path.dirname(__file__), 'fixtures/poetry-lock-simple.txt')
30-
31-
parser = PoetryFileParser(poetry_lock_filename=tests_poetry_lock_file)
31+
@data('poetry-lock11-simple.txt',
32+
'poetry-lock20-simple.txt')
33+
def test_simple(self, lock_file_name: str) -> None:
34+
poetry_lock_filename = os.path.join(os.path.dirname(__file__), 'fixtures', lock_file_name)
35+
parser = PoetryFileParser(poetry_lock_filename=poetry_lock_filename)
3236
self.assertEqual(1, parser.component_count())
3337
component = next(filter(lambda c: c.name == 'toml', parser.get_components()), None)
3438
self.assertIsNotNone(component)
@@ -37,10 +41,11 @@ def test_simple(self) -> None:
3741
self.assertEqual('0.10.2', component.version)
3842
self.assertEqual(2, len(component.external_references), f'{component.external_references}')
3943

40-
def test_simple_purl_bom_ref(self) -> None:
41-
tests_poetry_lock_file = os.path.join(os.path.dirname(__file__), 'fixtures/poetry-lock-simple.txt')
42-
43-
parser = PoetryFileParser(poetry_lock_filename=tests_poetry_lock_file, use_purl_bom_ref=True)
44+
@data('poetry-lock11-simple.txt',
45+
'poetry-lock20-simple.txt')
46+
def test_simple_purl_bom_ref(self, lock_file_name: str) -> None:
47+
poetry_lock_filename = os.path.join(os.path.dirname(__file__), 'fixtures', lock_file_name)
48+
parser = PoetryFileParser(poetry_lock_filename=poetry_lock_filename, use_purl_bom_ref=True)
4449
self.assertEqual(1, parser.component_count())
4550
component = next(filter(lambda c: c.name == 'toml', parser.get_components()), None)
4651
self.assertIsNotNone(component)

0 commit comments

Comments
 (0)