Skip to content

Commit 04cd0be

Browse files
committed
feat(scanner): Add scan result parser
Signed-off-by: Helio Chissini de Castro <dev@heliocastro.info> Signed-off-by: Helio Chissini de Castro <helio.chissini.de.castro@cariad.technology>
1 parent 45f9f81 commit 04cd0be

31 files changed

Lines changed: 1537 additions & 77 deletions

README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,28 @@
11
# Python-Ort
22

3-
Python-Ort is a pydantic based library to serialize OSS Review Toolkit generated reports using the default models.
3+
Python-Ort is a pydantic v2 based library to serialize [OSS Review Toolkit](https://oss-review-toolkit.org/ort/) generated reports using the default models.
4+
5+
## Install
6+
7+
```bash
8+
pip install python-ort
9+
```
10+
11+
## Simple usage example based on a report in yml format:
12+
13+
```python
14+
import pprint
15+
from pathlib import Path
16+
from pydantic import ValidationError
17+
18+
from ort import OrtResult, ort_yaml_load
19+
20+
21+
try:
22+
with Path("some-result.yml").open() as fd:
23+
data = ort_yaml_load(fd)
24+
parsed = OrtResult(**data)
25+
pprint(parsed)
26+
except ValidationError as e:
27+
print(e)
28+
```

prek.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ hooks = [
2222

2323
[[repos]]
2424
repo = "https://github.com/astral-sh/ruff-pre-commit"
25-
rev = "v0.15.4"
25+
rev = "v0.15.6"
2626
hooks = [
2727
{
2828
id = "ruff",
@@ -43,21 +43,21 @@ hooks = [
4343

4444
[[repos]]
4545
repo = "https://github.com/astral-sh/uv-pre-commit"
46-
rev = "0.10.8"
46+
rev = "0.10.9"
4747
hooks = [
4848
{ id = "uv-lock" }
4949
]
5050

5151
[[repos]]
5252
repo = "https://github.com/codespell-project/codespell"
53-
rev = "v2.4.1"
53+
rev = "v2.4.2"
5454
hooks = [
5555
{ id = "codespell" }
5656
]
5757

5858
[[repos]]
5959
repo = "https://github.com/allganize/ty-pre-commit"
60-
rev = "v0.0.20"
60+
rev = "v0.0.22"
6161
hooks = [
6262
{
6363
id = "ty-check",
@@ -72,6 +72,7 @@ hooks = [
7272
"packageurl-python",
7373
"click",
7474
"rich",
75+
"license-expression",
7576
]
7677
}
7778
]

pyproject.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ build-backend = "uv_build"
44

55
[project]
66
name = "python-ort"
7-
version = "0.7.0"
7+
version = "0.8.0"
88
description = "A Python Ort model serialization library"
99
readme = "README.md"
1010
license = "MIT"
1111
license-files = ["LICENSE"]
1212
requires-python = ">=3.10"
1313
dependencies = [
14+
"license>=0.1a3",
15+
"license-expression>=30.4.4",
1416
"packageurl-python>=0.17.6",
1517
"pydantic>=2.12.5",
1618
]
@@ -38,8 +40,8 @@ dev = [
3840
"datamodel-code-generator[http]>=0.55.0",
3941
"pytest>=9.0.2",
4042
"rich>=14.3.3",
41-
"ruff>=0.15.5",
42-
"ty>=0.0.21",
43+
"ruff>=0.15.6",
44+
"ty>=0.0.22",
4345
"types-pyyaml>=6.0.12.20250915",
4446
]
4547

@@ -144,9 +146,7 @@ extend-select = [
144146
"S", # bandit
145147
]
146148
ignore = [
147-
'N802', # function name should be lowercase
148149
'SIM105', # Suggest contextlib instead of try/except with pass
149-
'A004', # Python shadow builtins
150150
]
151151
# Unlike Flake8, default to a complexity level of 10.
152152
mccabe.max-complexity = 10

src/ort/models/base_run.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
# SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <heliocastro@gmail.com>
1+
# SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <dev@heliocastro.info>
2+
# # SPDX-FileCopyrightText: 2026 CARIAD SE
23
# SPDX-License-Identifier: MIT
34

45
from datetime import datetime
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <dev@heliocastro.info>
2+
# SPDX-FileCopyrightText: 2026 CARIAD SE
3+
# SPDX-License-Identifier: MIT
4+
5+
6+
from pydantic import BaseModel, ConfigDict, Field
7+
8+
from .file_storage_configuration import FileStorageConfiguration
9+
from .scan_storage_configuration import PostgresStorageConfiguration
10+
11+
12+
class FileArchiverConfiguration(BaseModel):
13+
"""
14+
The configuration model for a FileArchiver.
15+
"""
16+
17+
model_config = ConfigDict(
18+
extra="forbid",
19+
)
20+
21+
enabled: bool = Field(
22+
default=True,
23+
description="Toggle to enable or disable the file archiver functionality altogether.",
24+
)
25+
file_storage: FileStorageConfiguration | None = Field(
26+
default=None,
27+
description="Configuration of the FileStorage used for archiving the files.",
28+
)
29+
postgres_storage: PostgresStorageConfiguration | None = Field(
30+
default=None,
31+
description="Configuration of the PostgresProvenanceFileStorage used for archiving the files.",
32+
)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <dev@heliocastro.info>
2+
# SPDX-FileCopyrightText: 2026 CARIAD SE
3+
# SPDX-License-Identifier: MIT
4+
5+
6+
from pydantic import BaseModel, ConfigDict, Field
7+
8+
from .file_storage_configuration import FileStorageConfiguration
9+
from .scan_storage_configuration import PostgresStorageConfiguration
10+
11+
12+
class FileListStorageConfiguration(BaseModel):
13+
"""
14+
Configuration for the storage backends used for persisting file lists.
15+
"""
16+
17+
model_config = ConfigDict(extra="forbid")
18+
19+
file_storage: FileStorageConfiguration | None = Field(
20+
default=None,
21+
description=("Configuration of the FileStorage used for storing the file lists."),
22+
)
23+
postgres_storage: PostgresStorageConfiguration | None = Field(
24+
default=None,
25+
description="Configuration of the PostgresProvenanceFileStorage used for storing the file lists.",
26+
)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <dev@heliocastro.info>
2+
# SPDX-FileCopyrightText: 2026 CARIAD SE
3+
# SPDX-License-Identifier: MIT
4+
5+
6+
from pydantic import BaseModel, ConfigDict, Field
7+
8+
from .http_file_storage_configuration import HttpFileStorageConfiguration
9+
from .local_file_storage_configuration import LocalFileStorageConfiguration
10+
from .s3_file_storage_configuration import S3FileStorageConfiguration
11+
12+
13+
class FileStorageConfiguration(BaseModel):
14+
"""
15+
The configuration model for a FileStorage. Only one of the storage options
16+
can be configured.
17+
"""
18+
19+
model_config = ConfigDict(
20+
extra="forbid",
21+
)
22+
23+
http_file_storage: HttpFileStorageConfiguration | None = Field(
24+
default=None,
25+
description="The configuration of a HttpFileStorage.",
26+
)
27+
local_file_storage: LocalFileStorageConfiguration | None = Field(
28+
default=None,
29+
description="The configuration of a LocalFileStorage.",
30+
)
31+
s3_file_storage: S3FileStorageConfiguration | None = Field(
32+
default=None,
33+
description="The configuration of a S3FileStorage.",
34+
)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <dev@heliocastro.info>
2+
# SPDX-FileCopyrightText: 2026 CARIAD SE
3+
# SPDX-License-Identifier: MIT
4+
5+
from pydantic import BaseModel, ConfigDict, Field
6+
7+
8+
class HttpFileStorageConfiguration(BaseModel):
9+
"""
10+
Configuration for HTTP-based file storage.
11+
"""
12+
13+
url: str = Field(
14+
description='The URL of the HTTP server, e.g. "https://example.com/storage".',
15+
)
16+
query: str = Field(
17+
default="",
18+
description='Query string appended to the URL and path. Can contain auth data, e.g. "?user=standard&pwd=123".',
19+
)
20+
headers: dict[str, str] = Field(
21+
default_factory=dict,
22+
description="Custom headers added to all HTTP requests. Values may contain credentials.",
23+
)
24+
25+
model_config = ConfigDict(extra="forbid")
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <dev@heliocastro.info>
2+
# SPDX-FileCopyrightText: 2026 CARIAD SE
3+
# SPDX-License-Identifier: MIT
4+
5+
from pydantic import BaseModel, ConfigDict, Field
6+
7+
8+
class LocalFileStorageConfiguration(BaseModel):
9+
"""
10+
A class to hold the configuration for using local files as a storage.
11+
"""
12+
13+
model_config = ConfigDict(extra="forbid")
14+
15+
directory: str = Field(
16+
...,
17+
description="The directory to use as a storage root.",
18+
)
19+
compression: bool = Field(
20+
default=True,
21+
description="Whether to use compression for storing files or not. Defaults to true.",
22+
)
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <heliocastro@gmail.com>
2+
# SPDX-FileCopyrightText: 2026 CARIAD SE
3+
# SPDX-License-Identifier: MIT
4+
5+
6+
from pydantic import BaseModel, ConfigDict, Field
7+
8+
9+
class PostgresConnection(BaseModel):
10+
"""
11+
PostgreSQL connection configuration and HikariCP pool settings.
12+
"""
13+
14+
model_config = ConfigDict(extra="forbid")
15+
16+
url: str = Field(
17+
...,
18+
description=("The database URL in JDBC format."),
19+
)
20+
21+
provider_schema: str = Field(
22+
default="public",
23+
alias="schema",
24+
description=("The name of the database to use."),
25+
)
26+
27+
username: str = Field(
28+
...,
29+
description=("The username to use for authentication."),
30+
)
31+
32+
password: str = Field(
33+
default_factory=str,
34+
description=("The password to use for authentication."),
35+
)
36+
37+
sslmode: str = Field(
38+
default="verify-full",
39+
description='The SSL mode to use, one of "disable", "allow", "prefer", "require", '
40+
'"verify-ca" or "verify-full". See: '
41+
"https://jdbc.postgresql.org/documentation/ssl/#configuring-the-client",
42+
)
43+
44+
sslcert: str | None = Field(
45+
None,
46+
description="The full path of the certificate file. See: https://jdbc.postgresql.org/documentation/head/connect.html",
47+
)
48+
49+
sslkey: str | None = Field(
50+
None,
51+
description="The full path of the key file. See: https://jdbc.postgresql.org/documentation/head/connect.html",
52+
)
53+
54+
sslrootcert: str | None = Field(
55+
None,
56+
description="The full path of the root certificate file. See: "
57+
"https://jdbc.postgresql.org/documentation/head/connect.html",
58+
)
59+
60+
connection_timeout: int | None = Field(
61+
None,
62+
description="Maximum milliseconds to wait for connections from the pool. See: "
63+
"https://github.com/brettwooldridge/HikariCP#frequently-used",
64+
)
65+
66+
idle_timeout: int | None = Field(
67+
None,
68+
description="Maximum milliseconds a connection may sit idle in the pool. Requires "
69+
"minimum_idle < maximum_pool_size. See: "
70+
"https://github.com/brettwooldridge/HikariCP#frequently-used",
71+
)
72+
73+
keepalive_time: int | None = Field(
74+
None,
75+
description="Frequency in milliseconds that the pool will keep an idle connection "
76+
"alive. Must be lower than max_lifetime. See: "
77+
"https://github.com/brettwooldridge/HikariCP#frequently-used",
78+
)
79+
80+
max_lifetime: int | None = Field(
81+
None,
82+
description=(
83+
"Maximum lifetime of a connection in milliseconds. See: "
84+
"https://github.com/brettwooldridge/HikariCP#frequently-used"
85+
),
86+
)
87+
88+
maximum_pool_size: int | None = Field(
89+
None,
90+
description="Maximum size of the connection pool. See: https://github.com/brettwooldridge/HikariCP#frequently-used",
91+
)
92+
93+
minimum_idle: int | None = Field(
94+
None,
95+
description="Minimum number of idle connections that the pool tries to maintain. "
96+
"See: https://github.com/brettwooldridge/HikariCP#frequently-used",
97+
)

0 commit comments

Comments
 (0)