Skip to content

Commit baaeeee

Browse files
authored
Merge pull request #172 from sw360/171-support-python-dependency-detection-for-python-projects-using-poetry-2x
adapt `getdependencies python` to the Poetry 2.x pyproject.toml…
2 parents e375c5b + 93996a5 commit baaeeee

File tree

7 files changed

+1992
-8
lines changed

7 files changed

+1992
-8
lines changed

ChangeLog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
* Dependency updates.
2121
* `project prerequisites` now has a summary at the end of the output to show how many
2222
components have been scanned and how many warnings and errors there are.
23+
* Adapt `getdependencies python` to the Poetry 2.x pyproject.toml format.
2324

2425
## 2.9.1
2526

capycli/dependencies/python.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class GetPythonDependencies(capycli.common.script_base.ScriptBase):
6868

6969
def __init__(self) -> None:
7070
self.verbose = False
71+
self.proj_file_override = ""
7172

7273
@staticmethod
7374
def normalize_packagename(name: str) -> str:
@@ -404,8 +405,7 @@ def determine_file_type(self, full_filename: str) -> InputFileType:
404405
LOG.debug("Guessing requirements file")
405406
return InputFileType.REQUIREMENTS
406407

407-
if (filename == "poetry.lock") or (filename == "poetry2.lock"):
408-
# "poetry2.lock is only for unit test
408+
if (filename == "poetry.lock"):
409409
data = self.read_poetry_lock_file(full_filename)
410410
if data:
411411
LOG.debug("Guessing poetry.lock file")
@@ -510,6 +510,13 @@ def add_entry(self,
510510
else:
511511
LOG.warning(f"Dependency {dep2} not found!")
512512

513+
@staticmethod
514+
def get_pure_dep_name(name: str) -> str:
515+
"""Get pure dependency name (without extras)."""
516+
if "(" in name:
517+
return name.split("(")[0].strip()
518+
return name
519+
513520
def get_lock_file_entries_for_sbom(self,
514521
pyproject_file: str,
515522
all_entries: List[LockFileEntry]) -> List[LockFileEntry]:
@@ -521,10 +528,17 @@ def get_lock_file_entries_for_sbom(self,
521528
# => return all dependencies
522529
return all_entries
523530

524-
cfg = pyproject_info["tool"]["poetry"]
531+
poetry2xflag = False
532+
if "project" in pyproject_info:
533+
cfg = pyproject_info["project"]
534+
poetry2xflag = True
535+
else:
536+
cfg = pyproject_info["tool"]["poetry"]
525537
# get only real dependencies
526538
dependencies = cfg.get("dependencies", [])
527539
for dep in dependencies:
540+
if poetry2xflag:
541+
dep = self.get_pure_dep_name(dep)
528542
dep_name = GetPythonDependencies.normalize_packagename(dep)
529543
if dep_name.lower() == "python":
530544
# ignore python (version) 'dependency'
@@ -536,7 +550,7 @@ def get_lock_file_entries_for_sbom(self,
536550
LOG.warning(f"Dependency {dep_name} not found!")
537551

538552
# are there other groups of dependencies?
539-
dep_groups = cfg.get("group")
553+
dep_groups = pyproject_info["tool"]["poetry"].get("group")
540554
for group in dep_groups:
541555
print_yellow("Ignoring dependency group " + group)
542556
for dep in dep_groups[group].get("dependencies", []):
@@ -546,7 +560,12 @@ def get_lock_file_entries_for_sbom(self,
546560

547561
def sbom_from_poetry_lock_file(self, filename: str, search_meta_data: bool, package_source: str = "") -> Bom:
548562
folder = os.path.dirname(filename)
549-
pyproject_file = os.path.join(folder, "pyproject.toml")
563+
564+
if self.proj_file_override:
565+
# override for unit tests
566+
pyproject_file = self.proj_file_override
567+
else:
568+
pyproject_file = os.path.join(folder, "pyproject.toml")
550569
creator = SbomCreator()
551570
sbom = creator.create([], addlicense=True, addprofile=True, addtools=True)
552571
entry_list_all = self.get_all_lock_file_entries(filename)
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# SPDX-FileCopyrightText: (c) 2018-2024 Siemens
2+
# SPDX-License-Identifier: MIT
3+
4+
[tool.poetry]
5+
name = "capycli"
6+
version = "2.6.0.dev1"
7+
description = "CaPyCli - Clearing Automation Python Command Line Interface for SW360"
8+
authors = ["Thomas Graf <[email protected]>"]
9+
license = "MIT"
10+
readme="Readme.md"
11+
repository = "https://github.com/sw360/capycli"
12+
homepage = "https://github.com/sw360/capycli"
13+
keywords = ["sw360", "cli, automation", "license", "compliance", "clearing"]
14+
include = [
15+
"LICENSE.md",
16+
{ path = "capycli/data/granularity_list.csv", format = "wheel" },
17+
{ path = "capycli/data/__init__.py", format = "wheel" },
18+
{ path = "capycli/data/granularity_list.csv", format = "sdist" },
19+
{ path = "capycli/data/__init__.py", format = "sdist" },
20+
]
21+
classifiers = [
22+
"Development Status :: 5 - Production/Stable",
23+
"Intended Audience :: Developers",
24+
"Natural Language :: English",
25+
"Operating System :: OS Independent",
26+
"Programming Language :: Python :: 3 :: Only",
27+
]
28+
29+
30+
[tool.poetry.urls]
31+
issues = "https://github.com/sw360/capycli/issues"
32+
33+
[tool.poetry.scripts]
34+
capycli = "capycli.main.cli:main"
35+
36+
[tool.poetry.dependencies]
37+
python = "^3.8" # drop support for 3.6 and 3.7 because of wheel and cli-support
38+
colorama = "^0.4.3"
39+
requests = "^2.31.0" # fix CVE-2023-32681
40+
semver = "3.0.2"
41+
packageurl-python = "^0.15.6"
42+
pyjwt = "^1.7.1"
43+
openpyxl = "^3.0.3"
44+
requirements-parser = "0.11.0"
45+
sw360 = "^1.5.0"
46+
wheel = "^0.38.4"
47+
cli-support = "2.0.1"
48+
chardet = "5.2.0"
49+
cyclonedx-python-lib = "^8.0.0"
50+
tomli = "^2.0.2"
51+
dateparser = "^1.1.8"
52+
urllib3 = "*"
53+
importlib-resources = "^5.12.0"
54+
beautifulsoup4 = "^4.11.1"
55+
jsonschema = "^4.23.0"
56+
57+
[tool.poetry.group.dev.dependencies]
58+
flake8 = ">=3.7.8"
59+
coverage = "^5.4"
60+
responses = "0.24.1"
61+
pytest = "7.4.3"
62+
vcrpy = "4.4.0" # arrghh, no version of vcrpy supports urllib3 >= 2
63+
cli-test-helpers = "^3.1.0"
64+
isort = "^5.12.0"
65+
mypy = "^1.8.0"
66+
types-colorama = "^0.4.15.12"
67+
types-urllib3 = "^1.26.25.14"
68+
types-openpyxl = "^3.1.0.32"
69+
types-python-dateutil = "^2.8.19.14"
70+
types-requests = "2.31.0.6" # this is the last version that uses urllib3 < 2
71+
types-beautifulsoup4 = "^4.12.0.20240106"
72+
codespell = "^2.2.6"
73+
74+
[build-system]
75+
requires = ["poetry>=0.12"]
76+
build-backend = "poetry.masonry.api"
77+
78+
[tool.pytest.ini_options]
79+
filterwarnings = [
80+
# note the use of single quote below to denote "raw" strings in TOML
81+
"ignore:pkg_resources is deprecated as an API:DeprecationWarning",
82+
"ignore:Both `id` and `name` have been supplied - `name` will be ignored!",
83+
# cyclonedx-python-lib - UserWarning: The Component this BOM is describing None...
84+
"ignore::UserWarning",
85+
# cyclonedx-python-lib - DeprecationWarning: `@.tools` is deprecated from CycloneDX v1.5 onwards
86+
"ignore::DeprecationWarning"
87+
]
88+
89+
[tool.mypy]
90+
exclude = [
91+
"/tests",
92+
]
93+
94+
show_error_codes = true
95+
pretty = true
96+
97+
warn_unreachable = true
98+
allow_redefinition = true
99+
100+
### Strict mode ###
101+
warn_unused_configs = true
102+
disallow_subclassing_any = true
103+
104+
disallow_any_generics = true
105+
disallow_untyped_calls = true
106+
disallow_untyped_defs = true
107+
disallow_incomplete_defs = true
108+
check_untyped_defs = true
109+
disallow_untyped_decorators = true
110+
no_implicit_optional = true
111+
warn_redundant_casts = true
112+
warn_unused_ignores = true
113+
no_implicit_reexport = true
114+
115+
[tool.codespell]
116+
skip = "./htmlcov/*,./_internal_tests_/*,./__internal__/*,./tests/fixtures/*,*.svg,./capycli/data/granularity_list.csv,./ComponentCache.*"
117+
ignore-words-list = "manuel, assertIn"

0 commit comments

Comments
 (0)