-
Notifications
You must be signed in to change notification settings - Fork 1
feat(result): Initial OrtResult code - Analyzer #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1e49bc3
d0d5195
9d4bfc1
5bf25f0
01fd4aa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| analyzer: | ||
| enabled_package_managers: | ||
| - PIP | ||
|
|
||
| excludes: | ||
| paths: | ||
| - pattern: 'tests/data/**' | ||
| comment: 'Test data' | ||
| reason: TEST_OF |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <[email protected]> | ||
| # SPDX-License-Identifier: MIT | ||
| # | ||
| import logging | ||
| import sys | ||
| from pathlib import Path | ||
|
|
||
| import click | ||
| import yaml | ||
| from pydantic import ValidationError | ||
| from rich.pretty import pprint | ||
|
|
||
| from ort import OrtResult | ||
|
|
||
| logger = logging.getLogger() | ||
|
|
||
|
|
||
| @click.command() | ||
| @click.argument("datafile") | ||
| def main(datafile: str) -> None: | ||
| try: | ||
| with Path(datafile).open() as fd: | ||
| data = yaml.safe_load(fd) | ||
| parsed = OrtResult(**data) | ||
| pprint(parsed) | ||
| except ValidationError as e: | ||
| logger.error(e) | ||
| sys.exit(1) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,14 +4,14 @@ build-backend = "uv_build" | |
|
|
||
| [project] | ||
| name = "python-ort" | ||
| version = "0.4.3" | ||
| version = "0.5.0" | ||
heliocastro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| description = "A Python Ort model serialization library" | ||
| readme = "README.md" | ||
| license = "MIT" | ||
| license-files = ["LICENSE"] | ||
| requires-python = ">=3.10" | ||
| dependencies = [ | ||
| "pydantic>=2.12.4", | ||
| "pydantic>=2.12.5", | ||
| ] | ||
| classifiers = [ | ||
| "Development Status :: 3 - Alpha", | ||
|
|
@@ -31,13 +31,13 @@ module-root = "src" | |
|
|
||
| [dependency-groups] | ||
| dev = [ | ||
| "datamodel-code-generator[http]>=0.35.0", | ||
| "pre-commit>=4.3.0", | ||
| "datamodel-code-generator[http]>=0.53.0", | ||
heliocastro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| "pre-commit>=4.5.1", | ||
| "pycodestyle>=2.14.0", | ||
| "pyrefly>=0.40.0", | ||
| "pytest>=8.4.2", | ||
| "pyrefly>=0.49.0", | ||
| "pytest>=9.0.2", | ||
| "rich>=14.2.0", | ||
| "ruff>=0.14.4", | ||
| "ruff>=0.14.14", | ||
|
Comment on lines
+37
to
+40
|
||
| "types-pyyaml>=6.0.12.20250915", | ||
| ] | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| # SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <[email protected]> | ||
| # SPDX-License-Identifier: MIT | ||
|
|
||
| from .identifier import Identifier | ||
| from .vcstype import VcsType | ||
|
|
||
| __all__ = [ | ||
| "Identifier", | ||
| "VcsType", | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| # SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <[email protected]> | ||
| # SPDX-License-Identifier: MIT | ||
|
|
||
|
|
||
| from pydantic import BaseModel, ConfigDict, Field | ||
|
|
||
| from ort.models.dependency_graph import DependencyGraph | ||
| from ort.models.identifier import Identifier | ||
| from ort.models.issue import Issue | ||
| from ort.models.package import Package | ||
| from ort.models.project import Project | ||
|
|
||
|
|
||
| class AnalyzerResult(BaseModel): | ||
| """ | ||
| A class that merges all information from individual [ProjectAnalyzerResult]s created for each found definition file. | ||
| """ | ||
|
|
||
| model_config = ConfigDict( | ||
| extra="forbid", | ||
| ) | ||
|
|
||
| projects: set[Project] = Field( | ||
| description="Sorted set of the projects, as they appear in the individual analyzer results.", | ||
| ) | ||
|
|
||
| packages: set[Package] = Field( | ||
| description="The set of identified packages for all projects.", | ||
| ) | ||
|
|
||
| issues: dict[Identifier, list[Issue]] = Field( | ||
| default_factory=dict, | ||
| description="The lists of Issue objects that occurred within the analyzed projects themselves. Issues related" | ||
| "to project dependencies are contained in the dependencies of the project's scopes. This property is not" | ||
| "serialized if the map is empty to reduce the size of the result file.", | ||
| ) | ||
|
|
||
| dependency_graphs: dict[str, DependencyGraph] = Field( | ||
| default_factory=dict, | ||
| description="A map with DependencyGraph objects keyed by the name of the package manager that created this" | ||
| "graph. Package managers supporting this feature can construct a shared DependencyGraph over all projects and" | ||
| "store it in this map.", | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| # SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <[email protected]> | ||
| # SPDX-License-Identifier: MIT | ||
|
|
||
| from datetime import datetime | ||
|
|
||
| from pydantic import BaseModel, ConfigDict, Field | ||
|
|
||
| from ort.models.analyzer_result import AnalyzerResult | ||
| from ort.models.config.analyzer_configuration import AnalyzerConfiguration | ||
| from ort.utils.environment import Environment | ||
|
|
||
|
|
||
| class AnalyzerRun(BaseModel): | ||
| """ | ||
| The summary of a single run of the analyzer. | ||
|
|
||
| """ | ||
|
|
||
| model_config = ConfigDict( | ||
| extra="forbid", | ||
| ) | ||
| start_time: datetime = Field( | ||
| description="The time the analyzer was started.", | ||
| ) | ||
| end_time: datetime = Field( | ||
| description="The time the analyzer has finished.", | ||
| ) | ||
| environment: Environment = Field( | ||
| description="The [Environment] in which the analyzer was executed.", | ||
| ) | ||
| config: AnalyzerConfiguration = Field( | ||
| description="The [AnalyzerConfiguration] used for this run.", | ||
| ) | ||
| result: AnalyzerResult | None = Field( | ||
| default=None, | ||
| description="The result of this run.", | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| # SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <[email protected]> | ||
| # SPDX-License-Identifier: MIT | ||
|
|
||
|
|
||
| from pydantic import BaseModel, ConfigDict, Field, field_validator | ||
|
|
||
| from ort.models.dependency_graph_edge import DependencyGraphEdge | ||
| from ort.models.dependency_graph_node import DependencyGraphNode | ||
| from ort.models.dependency_reference import DependencyReference | ||
| from ort.models.identifier import Identifier | ||
| from ort.models.root_dependency_index import RootDependencyIndex | ||
|
|
||
|
|
||
| class DependencyGraph(BaseModel): | ||
| """ | ||
| Represents the graph of dependencies of a project. | ||
|
|
||
| This class holds information about a project's scopes and their dependencies in a format that minimizes the | ||
| consumption of memory. In projects with many scopes there is often a high degree of duplication in the dependencies | ||
| of the scopes. To avoid this, this class aims to share as many parts of the dependency graph as possible between | ||
| the different scopes. Ideally, there is only a single dependency graph containing the dependencies used by all | ||
| scopes. This is not always possible due to inconsistencies in dependency relations, like a package using different | ||
| dependencies in different scopes. Then the dependency graph is split into multiple fragments, and each fragment has | ||
| a consistent view on the dependencies it contains. | ||
|
|
||
| When constructing a dependency graph the dependencies are organized as a connected structure of DependencyReference | ||
| objects in memory. Originally, the serialization format of a graph was based on this structure, but that turned out | ||
| to be not ideal: During serialization, sub graphs referenced from multiple nodes (e.g. libraries with transitive | ||
| dependencies referenced from multiple projects) get duplicated, which can cause a significant amount of redundancy. | ||
| Therefore, the data representation has been changed again to a form, which can be serialized without introducing | ||
| redundancy. It consists of the following elements: | ||
|
|
||
| - packages: A list with the coordinates of all the packages (free of duplication) that are referenced by the graph. | ||
| This allows extracting the packages directly, but also has the advantage that the package coordinates do not have | ||
| to be repeated over and over: All the references to packages are expressed by indices into this list. | ||
| - nodes: An ordered list with the nodes of the dependency graph. A single node represents a package, and therefore | ||
| has a reference into the list with package coordinates. It can, however, happen that packages occur multiple | ||
| times in the graph if they are in different subtrees with different sets of transitive dependencies. Then there | ||
| are multiple nodes for the packages affected, and a fragment_index is used to identify them uniquely. Nodes also | ||
| store information about issues of a package and their linkage. | ||
| - edges: Here the structure of the graph comes in. Each edge connects two nodes and represents a directed | ||
| depends-on relationship. The nodes are referenced by numeric indices into the list of nodes. | ||
| - scopes: This is a map that associates the scopes used by projects with their direct dependencies. A single | ||
| dependency graph contains the dependencies of all the projects processed by a specific package manager. | ||
| Therefore, the keys of this map are scope names qualified by the coordinates of a project; which makes them | ||
| unique. The values are references to the nodes in the graph that correspond to the packages the scopes depend on | ||
| directly. | ||
|
|
||
| To navigate this structure, start with a scope and gather the references to its direct dependency nodes. Then, by | ||
| following the edges starting from these nodes, the set of transitive dependencies can be determined. The numeric | ||
| indices can be resolved via the packages list. | ||
| """ | ||
|
|
||
| model_config = ConfigDict( | ||
| extra="forbid", | ||
| ) | ||
|
|
||
| packages: list[Identifier] = Field( | ||
| default_factory=list, | ||
| description="A list with the identifiers of the packages that appear in the dependency graph. This list is " | ||
| "used to resolve the numeric indices contained in the dependency_graph_node objects.", | ||
| ) | ||
|
|
||
| scope_roots: set[DependencyReference] = Field( | ||
| default_factory=set, | ||
| description="Stores the dependency graph as a list of root nodes for the direct dependencies referenced by " | ||
| "scopes. Starting with these nodes, the whole graph can be traversed. The nodes are constructed " | ||
| "from the direct dependencies declared by scopes that cannot be reached via other paths in the " | ||
| "dependency graph. Note that this property exists for backwards compatibility only; it is replaced " | ||
| "by the lists of nodes and edges.", | ||
| ) | ||
|
|
||
| scopes: dict[str, list[RootDependencyIndex]] = Field( | ||
| default_factory=dict, | ||
| description="A mapping from scope names to the direct dependencies of the scopes. Based on this information, " | ||
| "the set of scopes of a project can be constructed from the serialized form.", | ||
| ) | ||
|
|
||
| nodes: list[DependencyGraphNode] = Field( | ||
| default_factory=list, | ||
| description="A list with the nodes of this dependency graph. Nodes correspond to packages, but in contrast to " | ||
| "the packages list, there can be multiple nodes for a single package. The order of nodes in this " | ||
| "list is relevant; the edges of the graph reference their nodes by numeric indices.", | ||
| ) | ||
|
|
||
| edges: set[DependencyGraphEdge] = Field( | ||
| default_factory=set, | ||
| description="A set with the edges of this dependency graph. By traversing the edges, the dependencies of " | ||
| "packages can be determined.", | ||
| ) | ||
|
|
||
| @field_validator("edges", mode="before") | ||
| @classmethod | ||
| def sort_and_set_edges(cls, v): | ||
| if v is None: | ||
| return set() | ||
|
|
||
| return {DependencyGraphEdge.model_validate(e) for e in v} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| # SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <[email protected]> | ||
| # SPDX-License-Identifier: MIT | ||
|
|
||
|
|
||
| from pydantic import BaseModel, ConfigDict, Field | ||
|
|
||
|
|
||
| class DependencyGraphEdge(BaseModel): | ||
| """ | ||
| A data class representing an edge in the dependency graph. | ||
|
|
||
| An edge corresponds to a directed depends-on relationship between two packages. The packages are identified by the | ||
| numeric indices into the list of nodes. | ||
| """ | ||
|
|
||
| model_config = ConfigDict( | ||
| extra="forbid", | ||
| frozen=True, | ||
| ) | ||
|
|
||
| from_: int = Field( | ||
| ..., | ||
| alias="from", | ||
| description="The index of the source node of this edge.", | ||
| ) | ||
| to_: int = Field( | ||
| ..., | ||
| alias="to", | ||
| description="The index of the destination node of this edge.", | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pyrefly hook id has been changed from "pyrefly-typecheck-system" to "pyrefly-check", and the language field is now explicitly set to "system". This appears to be updating to a newer version of pyrefly's pre-commit integration. Ensure that this change is compatible with the version update in pyproject.toml (0.46.0 in pre-commit vs 0.49.0 in dev dependencies).