Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
# Python-Ort

Python-Ort is a pydantic based library to serialize OSS Review Toolkit generated reports using the default models.
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.

## Install

```bash
pip install python-ort
```

## Simple usage example based on a report in yml format:

```python
from pprint import pprint
from pathlib import Path
from pydantic import ValidationError

from ort import OrtResult, ort_yaml_load


try:
with Path("some-result.yml").open() as fd:
data = ort_yaml_load(fd)
parsed = OrtResult(**data)
pprint(parsed)
except ValidationError as e:
print(e)
```
9 changes: 5 additions & 4 deletions prek.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ hooks = [

[[repos]]
repo = "https://github.com/astral-sh/ruff-pre-commit"
rev = "v0.15.4"
rev = "v0.15.6"
hooks = [
{
id = "ruff",
Expand All @@ -43,21 +43,21 @@ hooks = [

[[repos]]
repo = "https://github.com/astral-sh/uv-pre-commit"
rev = "0.10.8"
rev = "0.10.9"
hooks = [
{ id = "uv-lock" }
]

[[repos]]
repo = "https://github.com/codespell-project/codespell"
rev = "v2.4.1"
rev = "v2.4.2"
hooks = [
{ id = "codespell" }
]

[[repos]]
repo = "https://github.com/allganize/ty-pre-commit"
rev = "v0.0.20"
rev = "v0.0.22"
hooks = [
{
id = "ty-check",
Expand All @@ -72,6 +72,7 @@ hooks = [
"packageurl-python",
"click",
"rich",
"license-expression",
]
}
]
9 changes: 4 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ build-backend = "uv_build"

[project]
name = "python-ort"
version = "0.7.0"
version = "0.8.0"
description = "A Python Ort model serialization library"
readme = "README.md"
license = "MIT"
license-files = ["LICENSE"]
requires-python = ">=3.10"
dependencies = [
"license-expression>=30.4.4",
"packageurl-python>=0.17.6",
"pydantic>=2.12.5",
]
Expand Down Expand Up @@ -38,8 +39,8 @@ dev = [
"datamodel-code-generator[http]>=0.55.0",
"pytest>=9.0.2",
"rich>=14.3.3",
"ruff>=0.15.5",
"ty>=0.0.21",
"ruff>=0.15.6",
"ty>=0.0.22",
"types-pyyaml>=6.0.12.20250915",
]

Expand Down Expand Up @@ -144,9 +145,7 @@ extend-select = [
"S", # bandit
]
ignore = [
'N802', # function name should be lowercase
'SIM105', # Suggest contextlib instead of try/except with pass
'A004', # Python shadow builtins
]
# Unlike Flake8, default to a complexity level of 10.
mccabe.max-complexity = 10
Expand Down
3 changes: 2 additions & 1 deletion src/ort/models/base_run.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <heliocastro@gmail.com>
# SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <dev@heliocastro.info>
# # SPDX-FileCopyrightText: 2026 CARIAD SE
# SPDX-License-Identifier: MIT

from datetime import datetime
Expand Down
32 changes: 32 additions & 0 deletions src/ort/models/config/file_archiver_configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <dev@heliocastro.info>
# SPDX-FileCopyrightText: 2026 CARIAD SE
# SPDX-License-Identifier: MIT


from pydantic import BaseModel, ConfigDict, Field

from .file_storage_configuration import FileStorageConfiguration
from .scan_storage_configuration import PostgresStorageConfiguration


class FileArchiverConfiguration(BaseModel):
"""
The configuration model for a FileArchiver.
"""

model_config = ConfigDict(
extra="forbid",
)

enabled: bool = Field(
default=True,
description="Toggle to enable or disable the file archiver functionality altogether.",
)
file_storage: FileStorageConfiguration | None = Field(
default=None,
description="Configuration of the FileStorage used for archiving the files.",
)
postgres_storage: PostgresStorageConfiguration | None = Field(
default=None,
description="Configuration of the PostgresProvenanceFileStorage used for archiving the files.",
)
26 changes: 26 additions & 0 deletions src/ort/models/config/file_list_storage_configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <dev@heliocastro.info>
# SPDX-FileCopyrightText: 2026 CARIAD SE
# SPDX-License-Identifier: MIT


from pydantic import BaseModel, ConfigDict, Field

from .file_storage_configuration import FileStorageConfiguration
from .scan_storage_configuration import PostgresStorageConfiguration


class FileListStorageConfiguration(BaseModel):
"""
Configuration for the storage backends used for persisting file lists.
"""

model_config = ConfigDict(extra="forbid")

file_storage: FileStorageConfiguration | None = Field(
default=None,
description=("Configuration of the FileStorage used for storing the file lists."),
)
postgres_storage: PostgresStorageConfiguration | None = Field(
default=None,
description="Configuration of the PostgresProvenanceFileStorage used for storing the file lists.",
)
34 changes: 34 additions & 0 deletions src/ort/models/config/file_storage_configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <dev@heliocastro.info>
# SPDX-FileCopyrightText: 2026 CARIAD SE
# SPDX-License-Identifier: MIT


from pydantic import BaseModel, ConfigDict, Field

from .http_file_storage_configuration import HttpFileStorageConfiguration
from .local_file_storage_configuration import LocalFileStorageConfiguration
from .s3_file_storage_configuration import S3FileStorageConfiguration


class FileStorageConfiguration(BaseModel):
"""
The configuration model for a FileStorage. Only one of the storage options
can be configured.
"""

model_config = ConfigDict(
extra="forbid",
)

http_file_storage: HttpFileStorageConfiguration | None = Field(
default=None,
description="The configuration of a HttpFileStorage.",
)
local_file_storage: LocalFileStorageConfiguration | None = Field(
default=None,
description="The configuration of a LocalFileStorage.",
)
s3_file_storage: S3FileStorageConfiguration | None = Field(
default=None,
description="The configuration of a S3FileStorage.",
)
25 changes: 25 additions & 0 deletions src/ort/models/config/http_file_storage_configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <dev@heliocastro.info>
# SPDX-FileCopyrightText: 2026 CARIAD SE
# SPDX-License-Identifier: MIT

from pydantic import BaseModel, ConfigDict, Field


class HttpFileStorageConfiguration(BaseModel):
"""
Configuration for HTTP-based file storage.
"""

url: str = Field(
description='The URL of the HTTP server, e.g. "https://example.com/storage".',
)
query: str = Field(
default="",
description='Query string appended to the URL and path. Can contain auth data, e.g. "?user=standard&pwd=123".',
)
headers: dict[str, str] = Field(
default_factory=dict,
description="Custom headers added to all HTTP requests. Values may contain credentials.",
)

model_config = ConfigDict(extra="forbid")
16 changes: 8 additions & 8 deletions src/ort/models/config/license_finding_curation_reason.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
# SPDX-License-Identifier: MIT


from enum import Enum
from ...utils.validated_enum import ValidatedIntEnum


class LicenseFindingCurationReason(Enum):
class LicenseFindingCurationReason(ValidatedIntEnum):
"""
A curation for a license finding. Use it to correct a license finding or to add a license that was not
previously detected.
Expand All @@ -20,9 +20,9 @@ class LicenseFindingCurationReason(Enum):
REFERENCE: The findings reference a file or URL, e.g. SEE LICENSE IN LICENSE or https://jquery.org/license/.
"""

CODE = "CODE"
DATA_OF = "DATA_OF"
DOCUMENTATION_OF = "DOCUMENTATION_OF"
INCORRECT = "INCORRECT"
NOT_DETECTED = "NOT_DETECTED"
REFERENCE = "REFERENCE"
CODE = 1
DATA_OF = 2
DOCUMENTATION_OF = 3
INCORRECT = 4
NOT_DETECTED = 5
REFERENCE = 6
22 changes: 22 additions & 0 deletions src/ort/models/config/local_file_storage_configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <dev@heliocastro.info>
# SPDX-FileCopyrightText: 2026 CARIAD SE
# SPDX-License-Identifier: MIT

from pydantic import BaseModel, ConfigDict, Field


class LocalFileStorageConfiguration(BaseModel):
"""
A class to hold the configuration for using local files as a storage.
"""

model_config = ConfigDict(extra="forbid")

directory: str = Field(
...,
description="The directory to use as a storage root.",
)
compression: bool = Field(
default=True,
description="Whether to use compression for storing files or not. Defaults to true.",
)
97 changes: 97 additions & 0 deletions src/ort/models/config/postgres_connection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <heliocastro@gmail.com>
# SPDX-FileCopyrightText: 2026 CARIAD SE
# SPDX-License-Identifier: MIT


from pydantic import BaseModel, ConfigDict, Field


class PostgresConnection(BaseModel):
"""
PostgreSQL connection configuration and HikariCP pool settings.
"""

model_config = ConfigDict(extra="forbid")

url: str = Field(
...,
description=("The database URL in JDBC format."),
)

provider_schema: str = Field(
default="public",
alias="schema",
description=("The name of the database to use."),
)

username: str = Field(
...,
description=("The username to use for authentication."),
)

password: str = Field(
default_factory=str,
description=("The password to use for authentication."),
)

sslmode: str = Field(
default="verify-full",
description='The SSL mode to use, one of "disable", "allow", "prefer", "require", '
'"verify-ca" or "verify-full". See: '
"https://jdbc.postgresql.org/documentation/ssl/#configuring-the-client",
)

sslcert: str | None = Field(
None,
description="The full path of the certificate file. See: https://jdbc.postgresql.org/documentation/head/connect.html",
)

sslkey: str | None = Field(
None,
description="The full path of the key file. See: https://jdbc.postgresql.org/documentation/head/connect.html",
)

sslrootcert: str | None = Field(
None,
description="The full path of the root certificate file. See: "
"https://jdbc.postgresql.org/documentation/head/connect.html",
)

connection_timeout: int | None = Field(
None,
description="Maximum milliseconds to wait for connections from the pool. See: "
"https://github.com/brettwooldridge/HikariCP#frequently-used",
)

idle_timeout: int | None = Field(
None,
description="Maximum milliseconds a connection may sit idle in the pool. Requires "
"minimum_idle < maximum_pool_size. See: "
"https://github.com/brettwooldridge/HikariCP#frequently-used",
)

keepalive_time: int | None = Field(
None,
description="Frequency in milliseconds that the pool will keep an idle connection "
"alive. Must be lower than max_lifetime. See: "
"https://github.com/brettwooldridge/HikariCP#frequently-used",
)

max_lifetime: int | None = Field(
None,
description=(
"Maximum lifetime of a connection in milliseconds. See: "
"https://github.com/brettwooldridge/HikariCP#frequently-used"
),
)

maximum_pool_size: int | None = Field(
None,
description="Maximum size of the connection pool. See: https://github.com/brettwooldridge/HikariCP#frequently-used",
)

minimum_idle: int | None = Field(
None,
description="Minimum number of idle connections that the pool tries to maintain. "
"See: https://github.com/brettwooldridge/HikariCP#frequently-used",
)
Loading
Loading