python-ort 0.8.16__tar.gz → 0.9.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. {python_ort-0.8.16 → python_ort-0.9.0}/PKG-INFO +1 -1
  2. python_ort-0.9.0/pyproject.toml +163 -0
  3. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/__init__.py +2 -0
  4. python_ort-0.9.0/src/ort/models/licenses/license_categorization.py +27 -0
  5. python_ort-0.9.0/src/ort/models/licenses/license_category.py +26 -0
  6. python_ort-0.9.0/src/ort/models/licenses/license_classifications.py +124 -0
  7. python_ort-0.8.16/pyproject.toml +0 -160
  8. {python_ort-0.8.16 → python_ort-0.9.0}/LICENSE +0 -0
  9. {python_ort-0.8.16 → python_ort-0.9.0}/README.md +0 -0
  10. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/__init__.py +0 -0
  11. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/advisor_capability.py +0 -0
  12. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/advisor_details.py +0 -0
  13. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/advisor_result.py +0 -0
  14. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/advisor_run.py +0 -0
  15. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/advisor_summary.py +0 -0
  16. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/analyzer_result.py +0 -0
  17. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/analyzer_run.py +0 -0
  18. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/base_run.py +0 -0
  19. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/__init__.py +0 -0
  20. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/advisor_configuration.py +0 -0
  21. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/analyzer_configuration.py +0 -0
  22. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/curations.py +0 -0
  23. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/excludes.py +0 -0
  24. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/file_archiver_configuration.py +0 -0
  25. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/file_list_storage_configuration.py +0 -0
  26. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/file_storage_configuration.py +0 -0
  27. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/http_file_storage_configuration.py +0 -0
  28. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/includes.py +0 -0
  29. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/issue_resolution.py +0 -0
  30. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/issue_resolution_reason.py +0 -0
  31. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/license_choices.py +0 -0
  32. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/license_finding_curation.py +0 -0
  33. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/license_finding_curation_reason.py +0 -0
  34. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/local_file_storage_configuration.py +0 -0
  35. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/package_configuration.py +0 -0
  36. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/package_manager_configuration.py +0 -0
  37. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/path_exclude.py +0 -0
  38. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/path_exclude_reason.py +0 -0
  39. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/path_include.py +0 -0
  40. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/path_include_reason.py +0 -0
  41. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/postgres_connection.py +0 -0
  42. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/provenance_storage_configuration.py +0 -0
  43. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/repository_analyzer_configuration.py +0 -0
  44. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/repository_configuration.py +0 -0
  45. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/resolutions.py +0 -0
  46. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/rule_violation_reason.py +0 -0
  47. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/rule_violation_resolution.py +0 -0
  48. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/s3_file_storage_configuration.py +0 -0
  49. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/scan_storage_configuration.py +0 -0
  50. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/scanner_configuration.py +0 -0
  51. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/scope_exclude.py +0 -0
  52. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/scope_exclude_reason.py +0 -0
  53. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/snippet/__init__.py +0 -0
  54. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/snippet/snippet_choice.py +0 -0
  55. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/snippet/snippet_choice_reason.py +0 -0
  56. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/snippet/snippet_choices.py +0 -0
  57. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/snippet/snippet_provenance.py +0 -0
  58. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/vcsmatcher.py +0 -0
  59. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/vulnerability_resolution.py +0 -0
  60. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/config/vulnerability_resolution_reason.py +0 -0
  61. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/copyright_finding.py +0 -0
  62. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/defect.py +0 -0
  63. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/dependency_graph.py +0 -0
  64. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/dependency_graph_edge.py +0 -0
  65. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/dependency_graph_node.py +0 -0
  66. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/dependency_reference.py +0 -0
  67. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/evaluator_run.py +0 -0
  68. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/file_list.py +0 -0
  69. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/hash.py +0 -0
  70. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/identifier.py +0 -0
  71. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/issue.py +0 -0
  72. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/license_finding.py +0 -0
  73. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/license_source.py +0 -0
  74. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/ort_result.py +0 -0
  75. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/package.py +0 -0
  76. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/package_curation.py +0 -0
  77. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/package_curation_data.py +0 -0
  78. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/package_linkage.py +0 -0
  79. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/package_reference.py +0 -0
  80. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/project.py +0 -0
  81. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/provenance.py +0 -0
  82. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/provenance_resolution_result.py +0 -0
  83. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/remote_artifact.py +0 -0
  84. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/repository.py +0 -0
  85. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/resolutions.py +0 -0
  86. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/root_dependency_index.py +0 -0
  87. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/rule_violation.py +0 -0
  88. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/scan_result.py +0 -0
  89. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/scan_summary.py +0 -0
  90. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/scanner_details.py +0 -0
  91. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/scanner_run.py +0 -0
  92. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/scope.py +0 -0
  93. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/severity.py +0 -0
  94. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/snippet.py +0 -0
  95. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/snippet_finding.py +0 -0
  96. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/source_code_origin.py +0 -0
  97. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/text_location.py +0 -0
  98. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/vcsinfo.py +0 -0
  99. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/vcsinfo_curation_data.py +0 -0
  100. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/vcstype.py +0 -0
  101. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/vulnerabilities/__init__.py +0 -0
  102. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/vulnerabilities/cvss2_rating.py +0 -0
  103. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/vulnerabilities/cvss3_rating.py +0 -0
  104. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/vulnerabilities/cvss4_rating.py +0 -0
  105. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/vulnerabilities/vulnerability.py +0 -0
  106. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/models/vulnerabilities/vulnerability_reference.py +0 -0
  107. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/severity.py +0 -0
  108. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/types/__init__.py +0 -0
  109. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/types/purl_type.py +0 -0
  110. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/utils/__init__.py +0 -0
  111. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/utils/environment.py +0 -0
  112. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/utils/processed_declared_license.py +0 -0
  113. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/utils/spdx/__init__.py +0 -0
  114. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/utils/spdx/spdx_expression.py +0 -0
  115. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/utils/spdx/spdx_license_choice.py +0 -0
  116. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/utils/validated_enum.py +0 -0
  117. {python_ort-0.8.16 → python_ort-0.9.0}/src/ort/utils/yaml_loader.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-ort
3
- Version: 0.8.16
3
+ Version: 0.9.0
4
4
  Summary: A Python Ort model serialization library
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -0,0 +1,163 @@
1
+ [project]
2
+ name = "python-ort"
3
+ version = "0.9.0"
4
+ description = "A Python Ort model serialization library"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ classifiers = [
10
+ "Development Status :: 4 - Beta",
11
+ "Operating System :: OS Independent",
12
+ "Programming Language :: Python :: 3 :: Only",
13
+ "Programming Language :: Python :: 3.10",
14
+ "Programming Language :: Python :: 3.11",
15
+ "Programming Language :: Python :: 3.12",
16
+ "Programming Language :: Python :: 3.13",
17
+ "Programming Language :: Python :: 3.14",
18
+ "Topic :: Software Development :: Libraries :: Python Modules",
19
+ ]
20
+ dependencies = [
21
+ "license-expression>=30.4.4",
22
+ "packageurl-python>=0.17.6",
23
+ "pydantic>=2.13.4",
24
+ ]
25
+
26
+ [dependency-groups]
27
+ dev = [
28
+ "datamodel-code-generator[http]>=0.64.0",
29
+ "pytest>=9.1.0",
30
+ "rich>=15.0.0",
31
+ "ruff>=0.15.17",
32
+ "ty>=0.0.50",
33
+ "types-pyyaml>=6.0.12.20260518",
34
+ ]
35
+
36
+ [build-system]
37
+ requires = ["uv_build>=0.8.12,<0.12.0"]
38
+ build-backend = "uv_build"
39
+
40
+ [tool.codespell]
41
+ skip = [
42
+ ".agents",
43
+ ]
44
+
45
+ [tool.pylint.messages_control]
46
+ disable = [
47
+ "abstract-method",
48
+ "arguments-differ",
49
+ "attribute-defined-outside-init",
50
+ "blacklisted-name",
51
+ "chained-comparison",
52
+ "duplicate-code",
53
+ "eval-used",
54
+ "exec-used",
55
+ "expression-not-assigned",
56
+ "fixme",
57
+ "global-statement",
58
+ "invalid-name",
59
+ "import-error",
60
+ "logging-fstring-interpolation",
61
+ "missing-docstring",
62
+ "no-member",
63
+ "no-name-in-module",
64
+ "protected-access",
65
+ "redefined-argument-from-local",
66
+ "redefined-outer-name",
67
+ "reimported",
68
+ "stop-iteration-return",
69
+ "too-few-public-methods",
70
+ "too-many-ancestors",
71
+ "too-many-arguments",
72
+ "too-many-branches",
73
+ "too-many-instance-attributes",
74
+ "too-many-lines",
75
+ "too-many-locals",
76
+ "too-many-return-statements",
77
+ "too-many-statements",
78
+ "unexpected-special-method-signature",
79
+ "unspecified-encoding",
80
+ ]
81
+
82
+ check_untyped_defs = true
83
+ disallow_any_generics = true
84
+ disallow_untyped_defs = true
85
+ disallow_untyped_calls = false
86
+ follow_imports = "normal"
87
+ ignore_missing_imports = true
88
+ no_implicit_reexport = true
89
+ strict_optional = true
90
+ warn_redundant_casts = true
91
+ warn_unused_ignores = true
92
+
93
+ [tool.pytest.ini_options]
94
+ addopts = ["--import-mode=importlib"]
95
+ log_cli = true
96
+ log_cli_level = "INFO"
97
+ pythonpath = ["src"]
98
+ testpaths = ["tests"]
99
+
100
+ [tool.ruff]
101
+ fix = true
102
+ line-length = 120
103
+
104
+ # Exclude a variety of commonly ignored directories.
105
+ extend-exclude = [
106
+ ".bzr",
107
+ ".direnv",
108
+ ".eggs",
109
+ ".git",
110
+ ".hg",
111
+ ".mypy_cache",
112
+ ".nox",
113
+ ".pants.d",
114
+ ".ruff_cache",
115
+ ".svn",
116
+ ".tox",
117
+ ".venv",
118
+ "__pypackages__",
119
+ "_build",
120
+ "buck-out",
121
+ "build",
122
+ "dist",
123
+ "node_modules",
124
+ "venv",
125
+ ]
126
+
127
+ # Assume Python 3.10.
128
+ target-version = "py310"
129
+
130
+ [tool.ruff.lint]
131
+ extend-select = [
132
+ "E", # pycodestyle error
133
+ "W", # pycodestyle warning
134
+ "F", # pyflakes
135
+ "A", # flakes8-builtins
136
+ "C4", # flake8-comprehensions
137
+ "Q", # flake8-quotes
138
+ "SIM", # flake8-simplify
139
+ "PTH", # flake8-use-pathlib
140
+ "I", # isort
141
+ "N", # pep8 naming
142
+ "UP", # pyupgrade
143
+ "S", # bandit
144
+ ]
145
+ ignore = [
146
+ "SIM105", # Suggest contextlib instead of try/except with pass
147
+ ]
148
+ # Unlike Flake8, default to a complexity level of 10.
149
+ mccabe.max-complexity = 10
150
+ per-file-ignores = {}
151
+ flake8-tidy-imports.ban-relative-imports = "all"
152
+
153
+ [tool.ruff.format]
154
+ quote-style = "double"
155
+ indent-style = "space"
156
+ skip-magic-trailing-comma = false
157
+
158
+ [tool.uv]
159
+ index-url = "https://pypi.org/simple"
160
+
161
+ [tool.uv.build-backend]
162
+ module-name = "ort"
163
+ module-root = "src"
@@ -20,6 +20,7 @@ from .dependency_reference import DependencyReference
20
20
  from .hash import Hash
21
21
  from .identifier import Identifier
22
22
  from .issue import Issue
23
+ from .licenses.license_classifications import LicenseClassifications
23
24
  from .ort_result import OrtResult
24
25
  from .package import Package
25
26
  from .package_curation import PackageCuration
@@ -51,6 +52,7 @@ __all__ = [
51
52
  "Includes",
52
53
  "Excludes",
53
54
  "Issue",
55
+ "LicenseClassifications",
54
56
  "OrtResult",
55
57
  "Package",
56
58
  "PackageCuration",
@@ -0,0 +1,27 @@
1
+ # SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <heliocastro@gmail.com>
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ from pydantic import BaseModel, ConfigDict, Field
5
+
6
+
7
+ class LicenseCategorization(BaseModel):
8
+ """
9
+ A class for configuring metadata for a specific license referred to by an SPDX license identifier.
10
+
11
+ The metadata consists of assignments to generic categories whose exact meaning is customer specific.
12
+ The categories a license belong to can be evaluated by other components, such as rules or templates,
13
+ which can decide - based on this information - how to handle a specific license.
14
+
15
+ """
16
+
17
+ model_config = ConfigDict(
18
+ extra="forbid",
19
+ frozen=True,
20
+ )
21
+
22
+ id: str = Field(description="The [SpdxSingleLicenseExpression] of this [LicenseCategorization].")
23
+
24
+ categories: set[str] = Field(
25
+ default_factory=set,
26
+ description="The identifiers of the [license categories][LicenseCategory] this license is assigned to.",
27
+ )
@@ -0,0 +1,26 @@
1
+ # SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <heliocastro@gmail.com>
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ from pydantic import BaseModel, ConfigDict, Field
5
+
6
+
7
+ class LicenseCategory(BaseModel):
8
+ """
9
+ A category where licenses can be assigned to. The assignment is expressed via a [LicenseCategorization]. Categories
10
+ do not have any specific semantic, but users are free to define their own set of categories.
11
+
12
+ """
13
+
14
+ model_config = ConfigDict(
15
+ extra="forbid",
16
+ )
17
+
18
+ name: str = Field(
19
+ description="The name of this [LicenseCategory]. The name can be chosen freely, "
20
+ "but must be unique over all categories."
21
+ )
22
+
23
+ description: str = Field(
24
+ default_factory=str,
25
+ description="A description for this [LicenseCategory].",
26
+ )
@@ -0,0 +1,124 @@
1
+ # SPDX-FileCopyrightText: 2026 Helio Chissini de Castro <heliocastro@gmail.com>
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ from pydantic import BaseModel, ConfigDict, Field, model_validator
5
+
6
+ from .license_categorization import LicenseCategorization
7
+ from .license_category import LicenseCategory
8
+
9
+
10
+ class LicenseClassifications(BaseModel):
11
+ """
12
+ Classifications for licenses which allow assigning metadata to licenses. This allows defining rather generic
13
+ categories and assigning licenses to these. That way flexible classifications can be created based on
14
+ customizable categories. The available license categories need to be declared explicitly; when creating an
15
+ instance, it is checked that all the references from the [categorizations] point to existing [categories].
16
+ """
17
+
18
+ model_config = ConfigDict(
19
+ extra="forbid",
20
+ )
21
+
22
+ categories: list[LicenseCategory] = Field(
23
+ default_factory=list,
24
+ description="Defines metadata for the license categories.",
25
+ )
26
+
27
+ categorizations: list[LicenseCategorization] = Field(
28
+ default_factory=list,
29
+ description="Defines metadata for licenses.",
30
+ )
31
+
32
+ @model_validator(mode="after")
33
+ def _check_consistency(self) -> "LicenseClassifications":
34
+ category_names = [category.name for category in self.categories]
35
+ duplicate_categories = {name for name in category_names if category_names.count(name) > 1}
36
+ if duplicate_categories:
37
+ raise ValueError(f"Found multiple license categories with the same name: {sorted(duplicate_categories)}")
38
+
39
+ license_ids = [categorization.id for categorization in self.categorizations]
40
+ duplicate_ids = {license_id for license_id in license_ids if license_ids.count(license_id) > 1}
41
+ if duplicate_ids:
42
+ raise ValueError(f"Found multiple license categorizations with the same id: {sorted(duplicate_ids)}")
43
+
44
+ known_categories = set(category_names)
45
+ invalid_categorizations = {
46
+ categorization.id: sorted(categorization.categories - known_categories)
47
+ for categorization in self.categorizations
48
+ if categorization.categories - known_categories
49
+ }
50
+ if invalid_categorizations:
51
+ referenced_ids = ", ".join(invalid_categorizations.keys())
52
+ unknown_categories = sorted({name for names in invalid_categorizations.values() for name in names})
53
+ raise ValueError(
54
+ f"Found licenses that reference non-existing categories: {referenced_ids}; "
55
+ f"unknown categories are {unknown_categories}."
56
+ )
57
+
58
+ return self
59
+
60
+ @property
61
+ def category_names(self) -> set[str]:
62
+ """The names of all categories defined."""
63
+ return {category.name for category in self.categories}
64
+
65
+ @property
66
+ def licenses_by_category(self) -> dict[str, set[str]]:
67
+ """A mapping for fast look-ups of the licenses assigned to a given category."""
68
+ result: dict[str, set[str]] = {}
69
+ for categorization in self.categorizations:
70
+ for category in categorization.categories:
71
+ result.setdefault(category, set()).add(categorization.id)
72
+
73
+ for category in self.categories:
74
+ result.setdefault(category.name, set())
75
+
76
+ return result
77
+
78
+ @property
79
+ def categories_by_license(self) -> dict[str, set[str]]:
80
+ """A mapping for fast look-ups of the categories assigned to a given license."""
81
+ return {categorization.id: categorization.categories for categorization in self.categorizations}
82
+
83
+ def __getitem__(self, license_id: str) -> set[str] | None:
84
+ """Return the categories for the given license [license_id], or None if the license is not categorized."""
85
+ return self.categories_by_license.get(license_id)
86
+
87
+ def is_categorized(self, license_id: str) -> bool:
88
+ """Check whether there is a categorization for the given license [license_id]."""
89
+ return license_id in self.categories_by_license
90
+
91
+ def merge(self, other: "LicenseClassifications") -> "LicenseClassifications":
92
+ """Merge [other] into these classifications, overwriting any conflicting existing classifications."""
93
+ filtered_categories_by_license: dict[str, set[str]] = {}
94
+
95
+ # Remove categories that are also used in the other classification as different classifications might use
96
+ # different semantics for the same category name.
97
+ other_category_names = other.category_names
98
+ for categorization in self.categorizations:
99
+ filtered_categories = {
100
+ category for category in categorization.categories if category not in other_category_names
101
+ }
102
+ if filtered_categories:
103
+ filtered_categories_by_license[categorization.id] = filtered_categories
104
+
105
+ # Merge other into existing categories for each license.
106
+ for categorization in other.categorizations:
107
+ filtered_categories_by_license.setdefault(categorization.id, set()).update(categorization.categories)
108
+
109
+ used_categories = {
110
+ category for categories in filtered_categories_by_license.values() for category in categories
111
+ }
112
+
113
+ merged_categories: list[LicenseCategory] = []
114
+ for category in [*self.categories, *other.categories]:
115
+ if category.name in used_categories and category not in merged_categories:
116
+ merged_categories.append(category)
117
+
118
+ return LicenseClassifications(
119
+ categories=merged_categories,
120
+ categorizations=[
121
+ LicenseCategorization(id=license_id, categories=categories)
122
+ for license_id, categories in filtered_categories_by_license.items()
123
+ ],
124
+ )
@@ -1,160 +0,0 @@
1
- [build-system]
2
- requires = ["uv_build>=0.8.12,<0.11.0"]
3
- build-backend = "uv_build"
4
-
5
- [project]
6
- name = "python-ort"
7
- version = "0.8.16"
8
- description = "A Python Ort model serialization library"
9
- readme = "README.md"
10
- license = "MIT"
11
- license-files = ["LICENSE"]
12
- requires-python = ">=3.10"
13
- dependencies = [
14
- "license-expression>=30.4.4",
15
- "packageurl-python>=0.17.6",
16
- "pydantic>=2.13.4",
17
- ]
18
- classifiers = [
19
- "Development Status :: 4 - Beta",
20
- "Operating System :: OS Independent",
21
- "Programming Language :: Python :: 3 :: Only",
22
- "Programming Language :: Python :: 3.10",
23
- "Programming Language :: Python :: 3.11",
24
- "Programming Language :: Python :: 3.12",
25
- "Programming Language :: Python :: 3.13",
26
- "Programming Language :: Python :: 3.14",
27
- "Topic :: Software Development :: Libraries :: Python Modules",
28
- ]
29
-
30
- [tool.uv]
31
- index-url = "https://pypi.org/simple"
32
-
33
- [tool.uv.build-backend]
34
- module-name = "ort"
35
- module-root = "src"
36
-
37
- [dependency-groups]
38
- dev = [
39
- "datamodel-code-generator[http]>=0.57.0",
40
- "pytest>=9.0.3",
41
- "rich>=15.0.0",
42
- "ruff>=0.15.12",
43
- "ty>=0.0.35",
44
- "types-pyyaml>=6.0.12.20260510",
45
- ]
46
-
47
- [tool.pytest.ini_options]
48
- addopts = ["--import-mode=importlib"]
49
- log_cli = true
50
- log_cli_level = "INFO"
51
- pythonpath = ["src"]
52
- testpaths = ["tests"]
53
-
54
- [tool.pylint.messages_control]
55
- disable = [
56
- "abstract-method",
57
- "arguments-differ",
58
- "attribute-defined-outside-init",
59
- "blacklisted-name",
60
- "chained-comparison",
61
- "duplicate-code",
62
- "eval-used",
63
- "exec-used",
64
- "expression-not-assigned",
65
- "fixme",
66
- "global-statement",
67
- "invalid-name",
68
- "import-error",
69
- "logging-fstring-interpolation",
70
- "missing-docstring",
71
- "no-member",
72
- "no-name-in-module",
73
- "protected-access",
74
- "redefined-argument-from-local",
75
- "redefined-outer-name",
76
- "reimported",
77
- "stop-iteration-return",
78
- "too-few-public-methods",
79
- "too-many-ancestors",
80
- "too-many-arguments",
81
- "too-many-branches",
82
- "too-many-instance-attributes",
83
- "too-many-lines",
84
- "too-many-locals",
85
- "too-many-return-statements",
86
- "too-many-statements",
87
- "unexpected-special-method-signature",
88
- "unspecified-encoding",
89
- ]
90
-
91
- check_untyped_defs = true
92
- disallow_any_generics = true
93
- disallow_untyped_defs = true
94
- disallow_untyped_calls = false
95
- follow_imports = "normal"
96
- ignore_missing_imports = true
97
- no_implicit_reexport = true
98
- strict_optional = true
99
- warn_redundant_casts = true
100
- warn_unused_ignores = true
101
-
102
- [tool.ruff]
103
- fix = true
104
- line-length = 120
105
-
106
- # Exclude a variety of commonly ignored directories.
107
- extend-exclude = [
108
- ".bzr",
109
- ".direnv",
110
- ".eggs",
111
- ".git",
112
- ".hg",
113
- ".mypy_cache",
114
- ".nox",
115
- ".pants.d",
116
- ".ruff_cache",
117
- ".svn",
118
- ".tox",
119
- ".venv",
120
- "__pypackages__",
121
- "_build",
122
- "buck-out",
123
- "build",
124
- "dist",
125
- "node_modules",
126
- "venv",
127
- ]
128
-
129
- # Assume Python 3.10.
130
- target-version = "py310"
131
-
132
- [tool.ruff.lint]
133
- extend-select = [
134
- "E", # pycodestyle error
135
- "W", # pycodestyle warning
136
- "F", # pyflakes
137
- "A", # flakes8-builtins
138
- "C4", # flake8-comprehensions
139
- "Q", # flake8-quotes
140
- "SIM", # flake8-simplify
141
- "PTH", # flake8-use-pathlib
142
- "I", # isort
143
- "N", # pep8 naming
144
- "UP", # pyupgrade
145
- "S", # bandit
146
- ]
147
- ignore = [
148
- 'SIM105', # Suggest contextlib instead of try/except with pass
149
- ]
150
- # Unlike Flake8, default to a complexity level of 10.
151
- mccabe.max-complexity = 10
152
- per-file-ignores = {}
153
- flake8-tidy-imports.ban-relative-imports = "all"
154
- # Allow unused variables when underscore-prefixed.
155
- dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
156
-
157
- [tool.ruff.format]
158
- quote-style = "double"
159
- indent-style = "space"
160
- skip-magic-trailing-comma = false
File without changes
File without changes