Skip to content

Commit 774cd0d

Browse files
committed
Merge branch 'main' into feature/#426-Enhance_PTB_to_allow_configuring_the_python_version_used_for_coverage
2 parents b48a0fd + b697249 commit 774cd0d

File tree

32 files changed

+887
-556
lines changed

32 files changed

+887
-556
lines changed

.github/actions/python-environment/action.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ inputs:
1919
default: "."
2020

2121
extras:
22-
description: 'Comma-separated list of extras'
22+
description: 'Space-separated list of extras'
2323
required: false
2424

2525
use-cache:
@@ -53,7 +53,6 @@ runs:
5353
working-directory: ${{ inputs.working-directory }}
5454
shell: bash
5555
run: |
56-
EXTRAS=$(echo "${{ inputs.extras }}" | tr -d ' ')
5756
if [[ -n "$EXTRAS" ]]; then
5857
poetry install --extras "$EXTRAS"
5958
else

.github/actions/security-issues/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ runs:
3939
- name: Install Python Toolbox / Security tool
4040
shell: bash
4141
run: |
42-
pip install exasol-toolbox==1.2.0
42+
pip install exasol-toolbox==1.3.0
4343
4444
- name: Create Security Issue Report
4545
shell: bash

doc/changes/changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Changelog
22

33
* [unreleased](unreleased.md)
4+
* [1.3.0](changes_1.3.0.md)
45
* [1.2.0](changes_1.2.0.md)
56
* [1.1.0](changes_1.1.0.md)
67
* [1.0.1](changes_1.0.1.md)
@@ -34,6 +35,7 @@
3435
hidden:
3536
---
3637
unreleased
38+
changes_1.3.0
3739
changes_1.2.0
3840
changes_1.1.0
3941
changes_1.0.1

doc/changes/changes_1.3.0.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# 1.3.0 - 2025-06-02
2+
3+
## Summary
4+
5+
This version of the PTB updates nox task `version:check`, see #441.
6+
This requires file `noxconfig.py` of each project to specify the path to `version.py` in `Config.version_file`.
7+
8+
With this version of the PTB you can customize the arguments for `pyupgrade` in file `noxconfig.py`, see ticket #449 for details:
9+
```python
10+
pyupgrade_args = ("--py310-plus",)
11+
```
12+
13+
## 📚 Documentation
14+
* Updated getting_started.rst for allowing tag-based releases
15+
16+
## ✨ Features
17+
18+
* [#441](https://github.com/exasol/python-toolbox/issues/441): Switched nox task for `version:check` to use the config value of `version_file` to specify the location of the `version.py`
19+
20+
## 🐞 Bug Fixes
21+
* Updated `python-environment` action to use space-separated values for extras
22+
23+
24+
## ⚒️ Refactorings
25+
26+
* [#449](https://github.com/exasol/python-toolbox/issues/449): Refactored `dependency:licenses`:
27+
* to use pydantic models & `poetry show` for dependencies
28+
* to updated reading the `pyproject.toml` to be compatible with poetry 2.x+
29+
30+
## 🔩 Internal
31+
32+
* Relocked dependencies

doc/changes/unreleased.md

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,6 @@
22

33
## Summary
44

5-
With #441, please ensure that the location of the `version.py` is given for `Config.version_file`,
6-
which is specified in the `noxconfig.py`
7-
8-
## 📚 Documentation
9-
* Updated getting_started.rst for allowing tag-based releases
10-
115
## ✨ Features
126

13-
* [#441](https://github.com/exasol/python-toolbox/issues/441): Switched nox task for `version:check` to use the config value of `version_file` to specify the location of the `version.py`
14-
## Features
15-
167
* #426: Allowed configuring the python version used for coverage

exasol/toolbox/nox/_dependencies.py

Lines changed: 15 additions & 207 deletions
Original file line numberDiff line numberDiff line change
@@ -3,214 +3,19 @@
33
import argparse
44
import json
55
import subprocess
6-
import tempfile
7-
from dataclasses import dataclass
8-
from inspect import cleandoc
9-
from json import loads
106
from pathlib import Path
117

128
import nox
13-
import tomlkit
149
from nox import Session
1510

16-
17-
@dataclass(frozen=True)
18-
class Package:
19-
name: str
20-
package_link: str
21-
version: str
22-
license: str
23-
license_link: str
24-
25-
26-
def _dependencies(toml_str: str) -> dict[str, list]:
27-
toml = tomlkit.loads(toml_str)
28-
poetry = toml.get("tool", {}).get("poetry", {})
29-
dependencies: dict[str, list] = {}
30-
31-
packages = poetry.get("dependencies", {})
32-
if packages:
33-
dependencies["project"] = []
34-
for package in packages:
35-
dependencies["project"].append(package)
36-
37-
packages = poetry.get("dev", {}).get("dependencies", {})
38-
if packages:
39-
dependencies["dev"] = []
40-
for package in packages:
41-
dependencies["dev"].append(package)
42-
43-
groups = poetry.get("group", {})
44-
for group in groups:
45-
packages = groups.get(group, {}).get("dependencies")
46-
if packages and not dependencies.get(group, {}):
47-
dependencies[group] = []
48-
for package in packages:
49-
dependencies[group].append(package)
50-
return dependencies
51-
52-
53-
def _normalize(_license: str) -> str:
54-
def is_multi_license(l):
55-
return ";" in l
56-
57-
def select_most_restrictive(licenses: list) -> str:
58-
_max = 0
59-
lic = "Unknown"
60-
_mapping = {
61-
"Unknown": -1,
62-
"Unlicensed": 0,
63-
"BSD": 1,
64-
"MIT": 2,
65-
"MPLv2": 3,
66-
"LGPLv2": 4,
67-
"GPLv2": 5,
68-
"GPLv3": 6,
69-
}
70-
for l in licenses:
71-
if l in _mapping:
72-
if _mapping[l] > _mapping[lic]:
73-
lic = l
74-
else:
75-
return "<br>".join(licenses)
76-
return lic
77-
78-
mapping = {
79-
"BSD License": "BSD",
80-
"MIT License": "MIT",
81-
"The Unlicensed (Unlicensed)": "Unlicensed",
82-
"Mozilla Public License 2.0 (MPL 2.0)": "MPLv2",
83-
"GNU General Public License (GPL)": "GPL",
84-
"GNU Lesser General Public License v2 (LGPLv2)": "LGPLv2",
85-
"GNU General Public License v2 (GPLv2)": "GPLv2",
86-
"GNU General Public License v2 or later (GPLv2+)": "GPLv2+",
87-
"GNU General Public License v3 (GPLv3)": "GPLv3",
88-
"Apache Software License": "Apache",
89-
}
90-
91-
if is_multi_license(_license):
92-
items = []
93-
for item in _license.split(";"):
94-
item = str(item).strip()
95-
if item in mapping:
96-
items.append(mapping[item])
97-
else:
98-
items.append(item)
99-
return select_most_restrictive(items)
100-
101-
if _license not in mapping:
102-
return _license
103-
104-
return mapping[_license]
105-
106-
107-
def _packages_from_json(json: str) -> list[Package]:
108-
packages = loads(json)
109-
packages_list = []
110-
mapping = {
111-
"GPLv1": "https://www.gnu.org/licenses/old-licenses/gpl-1.0.html",
112-
"GPLv2": "https://www.gnu.org/licenses/old-licenses/gpl-2.0.html",
113-
"LGPLv2": "https://www.gnu.org/licenses/old-licenses/lgpl-2.0.html",
114-
"GPLv3": "https://www.gnu.org/licenses/gpl-3.0.html",
115-
"LGPLv3": "https://www.gnu.org/licenses/lgpl-3.0.html",
116-
"Apache": "https://www.apache.org/licenses/LICENSE-2.0",
117-
"MIT": "https://mit-license.org/",
118-
"BSD": "https://opensource.org/license/bsd-3-clause",
119-
}
120-
for package in packages:
121-
package_license = _normalize(package["License"])
122-
packages_list.append(
123-
Package(
124-
name=package["Name"],
125-
package_link="" if package["URL"] == "UNKNOWN" else package["URL"],
126-
version=package["Version"],
127-
license=package_license,
128-
license_link=(
129-
"" if package_license not in mapping else mapping[package_license]
130-
),
131-
)
132-
)
133-
return packages_list
134-
135-
136-
def _licenses() -> list[Package]:
137-
with tempfile.NamedTemporaryFile() as file:
138-
subprocess.run(
139-
[
140-
"poetry",
141-
"run",
142-
"pip-licenses",
143-
"--format=json",
144-
"--output-file=" + file.name,
145-
"--with-system",
146-
"--with-urls",
147-
],
148-
capture_output=True,
149-
)
150-
result = _packages_from_json(file.read().decode())
151-
return result
152-
153-
154-
def _packages_to_markdown(
155-
dependencies: dict[str, list], packages: list[Package]
156-
) -> str:
157-
def heading():
158-
text = "# Dependencies\n"
159-
return text
160-
161-
def dependency(group: str, group_packages: list, packages: list[Package]) -> str:
162-
def _header(_group: str):
163-
_group = "".join([word.capitalize() for word in _group.strip().split()])
164-
text = f"## {_group} Dependencies\n"
165-
text += "|Package|version|Licence|\n"
166-
text += "|---|---|---|\n"
167-
return text
168-
169-
def _rows(_group_packages: list, _packages: list[Package]) -> str:
170-
def _normalize_package_name(name: str) -> str:
171-
_name = name.lower()
172-
while "_" in _name:
173-
_name = _name.replace("_", "-")
174-
return _name
175-
176-
text = ""
177-
for package in _group_packages:
178-
consistent = filter(
179-
lambda elem: (_normalize_package_name(elem.name) == package),
180-
_packages,
181-
)
182-
for content in consistent:
183-
if content.package_link:
184-
text += f"|[{content.name}]({content.package_link})"
185-
else:
186-
text += f"|{content.name}"
187-
text += f"|{content.version}"
188-
if content.license_link:
189-
text += f"|[{content.license}]({content.license_link})|\n"
190-
else:
191-
text += f"|{content.license}|\n"
192-
text += "\n"
193-
return text
194-
195-
_template = cleandoc(
196-
"""
197-
{header}{rows}
198-
"""
199-
)
200-
return _template.format(
201-
header=_header(group), rows=_rows(group_packages, packages)
202-
)
203-
204-
template = cleandoc(
205-
"""
206-
{heading}{rows}
207-
"""
208-
)
209-
210-
rows = ""
211-
for group in dependencies:
212-
rows += dependency(group, dependencies[group], packages)
213-
return template.format(heading=heading(), rows=rows)
11+
from exasol.toolbox.util.dependencies.licenses import (
12+
licenses,
13+
packages_to_markdown,
14+
)
15+
from exasol.toolbox.util.dependencies.poetry_dependencies import (
16+
PoetryDependencies,
17+
PoetryToml,
18+
)
21419

21520

21621
class Audit:
@@ -282,10 +87,13 @@ def run(self, session: Session) -> None:
28287
@nox.session(name="dependency:licenses", python=False)
28388
def dependency_licenses(session: Session) -> None:
28489
"""returns the packages and their licenses"""
285-
toml = Path("pyproject.toml")
286-
dependencies = _dependencies(toml.read_text())
287-
package_infos = _licenses()
288-
print(_packages_to_markdown(dependencies=dependencies, packages=package_infos))
90+
working_directory = Path()
91+
poetry_dep = PoetryToml.load_from_toml(working_directory=working_directory)
92+
dependencies = PoetryDependencies(
93+
groups=poetry_dep.groups, working_directory=working_directory
94+
).direct_dependencies
95+
package_infos = licenses()
96+
print(packages_to_markdown(dependencies=dependencies, packages=package_infos))
28997

29098

29199
@nox.session(name="dependency:audit", python=False)

exasol/toolbox/nox/_format.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from __future__ import annotations
22

3-
from typing import Iterable
3+
from collections.abc import Iterable
44

55
import nox
66
from nox import Session
@@ -10,7 +10,12 @@
1010
_version,
1111
python_files,
1212
)
13-
from noxconfig import PROJECT_CONFIG
13+
from noxconfig import (
14+
PROJECT_CONFIG,
15+
Config,
16+
)
17+
18+
_PYUPGRADE_ARGS = ("--py39-plus",)
1419

1520

1621
def _code_format(session: Session, mode: Mode, files: Iterable[str]) -> None:
@@ -21,12 +26,11 @@ def command(*args: str) -> Iterable[str]:
2126
session.run(*command("black"), *files)
2227

2328

24-
def _pyupgrade(session: Session, files: Iterable[str]) -> None:
29+
def _pyupgrade(session: Session, config: Config, files: Iterable[str]) -> None:
30+
pyupgrade_args = getattr(config, "pyupgrade_args", _PYUPGRADE_ARGS)
2531
session.run(
26-
"poetry",
27-
"run",
2832
"pyupgrade",
29-
"--py38-plus",
33+
*pyupgrade_args,
3034
"--exit-zero-even-if-changed",
3135
*files,
3236
)
@@ -37,7 +41,7 @@ def fix(session: Session) -> None:
3741
"""Runs all automated fixes on the code base"""
3842
py_files = [f"{file}" for file in python_files(PROJECT_CONFIG.root)]
3943
_version(session, Mode.Fix)
40-
_pyupgrade(session, py_files)
44+
_pyupgrade(session, config=PROJECT_CONFIG, files=py_files)
4145
_code_format(session, Mode.Fix, py_files)
4246

4347

0 commit comments

Comments
 (0)