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
12 changes: 5 additions & 7 deletions .github/workflows/commit_checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:

typecheck:
needs: commitlint
name: PyreFly Type Checker
name: ty Type Checker
runs-on: ubuntu-24.04

steps:
Expand All @@ -35,15 +35,13 @@ jobs:
- uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0
with:
enable-cache: true
activate-environment: "true"
python-version: "3.13"

- uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: '3.13'

- name: Run Pyrefly Type Checker
- name: Run ty Type Checker
run: |
uv sync
uv run pyrefly check
uv run ty check --output-format github

ruff:
needs: commitlint
Expand Down
12 changes: 2 additions & 10 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ repos:
- '--fix=lf'

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 'v0.14.10'
rev: 'v0.15.1'
hooks:
- id: ruff
args: [--fix]
Expand All @@ -26,19 +26,11 @@ repos:

- repo: https://github.com/astral-sh/uv-pre-commit
# uv version.
rev: 0.9.18
rev: 0.10.3
hooks:
- id: uv-lock

- repo: https://github.com/codespell-project/codespell
rev: v2.4.1
hooks:
- id: codespell

- repo: https://github.com/facebook/pyrefly-pre-commit
rev: 0.46.0
hooks:
- id: pyrefly-check
name: Pyrefly (type checking)
pass_filenames: false
language: system
15 changes: 13 additions & 2 deletions examples/ort_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,23 @@

@click.command()
@click.argument("datafile")
def main(datafile: str) -> None:
@click.option("-a", "--analyzer", is_flag=True)
@click.option("-v", "--advisor", is_flag=True)
def main(
datafile: str,
analyzer: bool,
advisor: bool,
) -> None:
try:
with Path(datafile).open() as fd:
data = yaml.safe_load(fd)
parsed = OrtResult(**data)
pprint(parsed)
if analyzer:
pprint(parsed.analyzer)
if advisor:
pprint(parsed.advisor)
else:
pprint(parsed)
except ValidationError as e:
logger.error(e)
sys.exit(1)
Expand Down
4 changes: 2 additions & 2 deletions examples/repo_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pydantic import ValidationError
from rich.pretty import pprint

from ort import OrtRepositoryConfiguration
from ort import RepositoryConfiguration

logger = logging.getLogger()

Expand All @@ -21,7 +21,7 @@ def main(datafile: str) -> None:
try:
with Path(datafile).open() as fd:
data = yaml.safe_load(fd)
parsed = OrtRepositoryConfiguration(**data)
parsed = RepositoryConfiguration(**data)
pprint(parsed)
except ValidationError as e:
logger.error(e)
Expand Down
12 changes: 5 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "uv_build"

[project]
name = "python-ort"
version = "0.5.0"
version = "0.6.0"
description = "A Python Ort model serialization library"
readme = "README.md"
license = "MIT"
Expand All @@ -31,13 +31,11 @@ module-root = "src"

[dependency-groups]
dev = [
"datamodel-code-generator[http]>=0.53.0",
"pre-commit>=4.5.1",
"pycodestyle>=2.14.0",
"pyrefly>=0.49.0",
"datamodel-code-generator[http]>=0.54.0",
"pytest>=9.0.2",
"rich>=14.2.0",
"ruff>=0.14.14",
"rich>=14.3.2",
"ruff>=0.15.1",
"ty>=0.0.17",
"types-pyyaml>=6.0.12.20250915",
]

Expand Down
8 changes: 0 additions & 8 deletions python-ort.code-workspace

This file was deleted.

4 changes: 2 additions & 2 deletions src/ort/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

from ort.models.analyzer_result import AnalyzerResult
from ort.models.ort_result import OrtResult
from ort.models.repository_configuration import OrtRepositoryConfiguration
from ort.models.repository_configuration import RepositoryConfiguration

__all__ = [
"AnalyzerResult",
"OrtRepositoryConfiguration",
"RepositoryConfiguration",
"OrtResult",
]
54 changes: 54 additions & 0 deletions src/ort/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,64 @@
# SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <heliocastro@gmail.com>
# SPDX-License-Identifier: MIT

from .advisor_capability import AdvisorCapability
from .advisor_result import AdvisorResult
from .advisor_run import AdvisorRun
from .analyzer_result import AnalyzerResult
from .analyzer_run import AnalyzerRun
from .dependency_graph import DependencyGraph
from .dependency_graph_edge import DependencyGraphEdge
from .dependency_graph_node import DependencyGraphNode
from .dependency_reference import DependencyReference
from .hash import Hash
from .hash_algorithm import HashAlgorithm
from .identifier import Identifier
from .issue import Issue
from .ort_result import OrtResult
from .package import Package
from .package_curation import PackageCuration
from .package_curation_data import PackageCurationData
from .package_linkage import PackageLinkage
from .package_reference import PackageReference
from .project import Project
from .remote_artifact import RemoteArtifact
from .repository import Repository
from .repository_configuration import RepositoryConfiguration
from .root_dependency_index import RootDependencyIndex
from .scope import Scope
from .source_code_origin import SourceCodeOrigin
from .vcsinfo import VcsInfo
from .vcsinfo_curation_data import VcsInfoCurationData
from .vcstype import VcsType

__all__ = [
"AdvisorCapability",
"AdvisorResult",
"AdvisorRun",
"AnalyzerResult",
"AnalyzerRun",
"DependencyGraph",
"DependencyGraphEdge",
"DependencyGraphNode",
"DependencyReference",
"Hash",
"HashAlgorithm",
"Identifier",
"Issue",
"OrtResult",
"Package",
"PackageCuration",
"PackageCurationData",
"PackageLinkage",
"PackageReference",
"Project",
"RemoteArtifact",
"Repository",
"RepositoryConfiguration",
"RootDependencyIndex",
"Scope",
"SourceCodeOrigin",
"VcsInfo",
"VcsInfoCurationData",
"VcsType",
]
21 changes: 21 additions & 0 deletions src/ort/models/advisor_capability.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <heliocastro@gmail.com>
# SPDX-License-Identifier: MIT


from enum import IntEnum


class AdvisorCapability(IntEnum):
"""
An enum class that defines the capabilities of a specific advisor implementation.

There are multiple types of findings that can be retrieved by an advisor, such as security vulnerabilities or
defects. An [AdvisorResult] has different fields for the different findings types. This enum corresponds to these
fields. It allows an advisor implementation to declare, which of these fields it can populate. This information is
of interest, for instance, when generating reports for specific findings to determine, which advisor may have
contributed.

"""

DEFECTS = 1
VULNERABILITIES = 2
41 changes: 41 additions & 0 deletions src/ort/models/advisor_details.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <heliocastro@gmail.com>
# SPDX-License-Identifier: MIT


from pydantic import BaseModel, ConfigDict, Field, field_validator

from ort.models import AdvisorCapability


class AdvisorDetails(BaseModel):
"""
Details about the used provider of vulnerability information.

"""

model_config = ConfigDict(
extra="forbid",
)

name: str = Field(description="The name of the used advisor.")
capabilities: set[AdvisorCapability] = Field(
description="The capabilities of the used advisor. This property indicates, which kind of findings"
"are retrieved by the advisor."
)

@field_validator("capabilities", mode="before")
@classmethod
def convert_capability(cls, v):
def _convert(item):
if isinstance(item, str):
try:
return AdvisorCapability[item]
except KeyError:
raise ValueError(f"Invalid capability: {item}")
return item

if isinstance(v, (list, set)):
return {_convert(item) for item in v}
if isinstance(v, str):
return _convert(v)
return v
42 changes: 42 additions & 0 deletions src/ort/models/advisor_result.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <heliocastro@gmail.com>
# SPDX-License-Identifier: MIT

from pydantic import BaseModel, ConfigDict, Field

from ort.models.vulnerabilities import Vulnerability

from .advisor_details import AdvisorDetails
from .advisor_summary import AdvisorSummary
from .defect import Defect


class AdvisorResult(BaseModel):
"""
The result of a specific advisor execution for a single package.

Different advisor implementations may produce findings of different types. To reflect this, this class has multiple
fields for findings of these types. It is up to a concrete advisor, which of these fields it populates.

"""

model_config = ConfigDict(
extra="forbid",
)

advisor: AdvisorDetails = Field(
description="Details about the used advisor.",
)

summary: AdvisorSummary = Field(
description="A summary of the advisor results.",
)

defects: list[Defect] = Field(
default_factory=list,
description="The defects.",
)

vulnerabilities: list[Vulnerability] = Field(
default_factory=list,
description="The vulnerabilities.",
)
39 changes: 39 additions & 0 deletions src/ort/models/advisor_run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <heliocastro@gmail.com>
# SPDX-License-Identifier: MIT

from datetime import datetime

from pydantic import BaseModel, ConfigDict, Field

from ort.models import AdvisorResult
from ort.models.config.advisor_configuration import AdvisorConfiguration
from ort.utils.environment import Environment

from .identifier import Identifier


class AdvisorRun(BaseModel):
"""
Type alias for a function that allows filtering of [AdvisorResult]s.

"""

model_config = ConfigDict(
extra="forbid",
)
start_time: datetime = Field(
description="The time the advisor was started.",
)
end_time: datetime = Field(
description="The time the advisor has finished.",
)
environment: Environment = Field(
description="The [Environment] in which the advisor was executed.",
)
config: AdvisorConfiguration = Field(
description="The [AdvisorConfiguration] used for this run.",
)
results: dict[Identifier, list[AdvisorResult]] = Field(
default_factory=dict,
description="The result of this run.",
)
Loading