python-ort 0.2.0__tar.gz → 0.3.1__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 (22) hide show
  1. {python_ort-0.2.0 → python_ort-0.3.1}/PKG-INFO +2 -2
  2. {python_ort-0.2.0 → python_ort-0.3.1}/pyproject.toml +6 -7
  3. python_ort-0.3.1/src/ort/models/config/curations.py +30 -0
  4. python_ort-0.3.1/src/ort/models/config/license_finding_curation.py +61 -0
  5. python_ort-0.3.1/src/ort/models/config/license_finding_curation_reason.py +28 -0
  6. python_ort-0.3.1/src/ort/models/hash.py +19 -0
  7. python_ort-0.3.1/src/ort/models/hash_algorithm.py +37 -0
  8. python_ort-0.3.1/src/ort/models/package_curation.py +15 -0
  9. python_ort-0.3.1/src/ort/models/package_curation_data.py +36 -0
  10. {python_ort-0.2.0 → python_ort-0.3.1}/src/ort/models/repository_configuration.py +9 -106
  11. python_ort-0.3.1/src/ort/models/vcsinfo.py +33 -0
  12. python_ort-0.3.1/src/ort/models/vcsinfo_curation_data.py +37 -0
  13. python_ort-0.3.1/src/ort/models/vcstype.py +45 -0
  14. {python_ort-0.2.0 → python_ort-0.3.1}/LICENSE +0 -0
  15. {python_ort-0.2.0 → python_ort-0.3.1}/README.md +0 -0
  16. {python_ort-0.2.0 → python_ort-0.3.1}/src/ort/__init__.py +0 -0
  17. {python_ort-0.2.0 → python_ort-0.3.1}/src/ort/models/__init__.py +0 -0
  18. {python_ort-0.2.0 → python_ort-0.3.1}/src/ort/models/analyzer_configurations.py +0 -0
  19. {python_ort-0.2.0 → python_ort-0.3.1}/src/ort/models/ort_configuration.py +0 -0
  20. {python_ort-0.2.0 → python_ort-0.3.1}/src/ort/models/package_managers.py +0 -0
  21. {python_ort-0.2.0 → python_ort-0.3.1}/src/ort/models/resolutions.py +0 -0
  22. {python_ort-0.2.0 → python_ort-0.3.1}/src/ort/models/source_code_origin.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-ort
3
- Version: 0.2.0
3
+ Version: 0.3.1
4
4
  Summary: A Python Ort model serialization library
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -11,9 +11,9 @@ Classifier: Programming Language :: Python :: 3.10
11
11
  Classifier: Programming Language :: Python :: 3.11
12
12
  Classifier: Programming Language :: Python :: 3.12
13
13
  Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
14
15
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
15
16
  Requires-Dist: pydantic>=2.12.4
16
- Requires-Dist: pyyaml>=6.0.3
17
17
  Requires-Python: >=3.10
18
18
  Description-Content-Type: text/markdown
19
19
 
@@ -2,12 +2,9 @@
2
2
  requires = ["uv_build>=0.8.12,<0.10.0"]
3
3
  build-backend = "uv_build"
4
4
 
5
- [tool.hatch.build.targets.wheel]
6
- packages = ["src/ort"]
7
-
8
5
  [project]
9
6
  name = "python-ort"
10
- version = "0.2.0"
7
+ version = "0.3.1"
11
8
  description = "A Python Ort model serialization library"
12
9
  readme = "README.md"
13
10
  license = "MIT"
@@ -15,7 +12,6 @@ license-files = ["LICENSE"]
15
12
  requires-python = ">=3.10"
16
13
  dependencies = [
17
14
  "pydantic>=2.12.4",
18
- "pyyaml>=6.0.3",
19
15
  ]
20
16
  classifiers = [
21
17
  "Development Status :: 3 - Alpha",
@@ -25,6 +21,7 @@ classifiers = [
25
21
  "Programming Language :: Python :: 3.11",
26
22
  "Programming Language :: Python :: 3.12",
27
23
  "Programming Language :: Python :: 3.13",
24
+ "Programming Language :: Python :: 3.14",
28
25
  "Topic :: Software Development :: Libraries :: Python Modules",
29
26
  ]
30
27
 
@@ -39,7 +36,8 @@ dev = [
39
36
  "pycodestyle>=2.14.0",
40
37
  "pyrefly>=0.40.0",
41
38
  "pytest>=8.4.2",
42
- "ruff>=0.14.3",
39
+ "rich>=14.2.0",
40
+ "ruff>=0.14.4",
43
41
  "types-pyyaml>=6.0.12.20250915",
44
42
  ]
45
43
 
@@ -47,7 +45,8 @@ dev = [
47
45
  addopts = ["--import-mode=importlib"]
48
46
  log_cli = true
49
47
  log_cli_level = "INFO"
50
- pythonpath = "src"
48
+ pythonpath = ["src"]
49
+ testpaths = ["tests"]
51
50
 
52
51
  [tool.pylint.messages_control]
53
52
  disable = [
@@ -0,0 +1,30 @@
1
+ # SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <heliocastro@gmail.com>
2
+ # SPDX-License-Identifier: MIT
3
+
4
+
5
+ from pydantic import BaseModel, ConfigDict, Field
6
+
7
+ from ort.models.config.license_finding_curation import LicenseFindingCuration
8
+ from ort.models.package_curation import PackageCuration
9
+
10
+
11
+ class Curations(BaseModel):
12
+ """
13
+ Curations for artifacts in a repository.
14
+
15
+ Attributes:
16
+ packages(list[PackageCuration]): Curations for third-party packages.
17
+ license_findings(list[LicenseFindingCuration]): Curations for license findings.
18
+ """
19
+
20
+ model_config = ConfigDict(
21
+ extra="forbid",
22
+ )
23
+ packages: list[PackageCuration] = Field(
24
+ default_factory=list,
25
+ description="Curations for third-party packages.",
26
+ )
27
+ license_findings: list[LicenseFindingCuration] = Field(
28
+ default_factory=list,
29
+ description="Curations for license findings.",
30
+ )
@@ -0,0 +1,61 @@
1
+ # SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <heliocastro@gmail.com>
2
+ # SPDX-License-Identifier: MIT
3
+
4
+
5
+ from pydantic import BaseModel, ConfigDict, Field
6
+
7
+ from ort.models.config.license_finding_curation_reason import LicenseFindingCurationReason
8
+
9
+
10
+ class LicenseFindingCuration(BaseModel):
11
+ """
12
+ A curation for a license finding. Use it to correct a license finding or to add a license
13
+ that was not previously detected.
14
+
15
+ Attributes:
16
+ path (str): A glob to match the file path of a license finding.
17
+ start_lines (list[int] | None): A matcher for the start line of a license finding, matches if the start line
18
+ matches any of [startLines] or if [startLines] is empty.
19
+ line_count (int | None): A matcher for the line count of a license finding
20
+ matches if the line count equals [lineCount] or if [lineCount] is None
21
+ detected_license (str | None): The concluded license as SPDX expression or None
22
+ for no license, see https://spdx.dev/spdx-specification-21-web-version#h.jxpfx0ykyb60.
23
+ concluded_license (str): The concluded license as SPDX expression or None for no license,
24
+ see https://spdx.dev/spdx-specification-21-web-version#h.jxpfx0ykyb60.
25
+ reason (LicenseFindingCurationReason): The reason why the curation was made, out of a predefined choice.
26
+ comment (str | None): A comment explaining this [LicenseFindingCuration].
27
+ """
28
+
29
+ model_config = ConfigDict(
30
+ extra="forbid",
31
+ )
32
+ path: str = Field(
33
+ description="A glob to match the file path of a license finding.",
34
+ )
35
+ start_lines: list[int] | None = Field(
36
+ default=None,
37
+ description="A matcher for the start line of a license finding, matches if the start line matches any of"
38
+ "[startLines] or if [startLines] is empty.",
39
+ )
40
+ line_count: int | None = Field(
41
+ default=None,
42
+ description="A matcher for the line count of a license finding"
43
+ "matches if the line count equals [lineCount] or if [lineCount] is None",
44
+ )
45
+
46
+ detected_license: str | None = Field(
47
+ default=None,
48
+ description="The concluded license as SPDX expression or None"
49
+ "for no license, see https://spdx.dev/spdx-specification-21-web-version#h.jxpfx0ykyb60.",
50
+ )
51
+ concluded_license: str = Field(
52
+ description="The concluded license as SPDX expression or None for no license,"
53
+ " see https://spdx.dev/spdx-specification-21-web-version#h.jxpfx0ykyb60.",
54
+ )
55
+ reason: LicenseFindingCurationReason = Field(
56
+ description="The reason why the curation was made, out of a predefined choice.",
57
+ )
58
+ comment: str | None = Field(
59
+ default=None,
60
+ description="A comment explaining this [LicenseFindingCuration].",
61
+ )
@@ -0,0 +1,28 @@
1
+ # SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <heliocastro@gmail.com>
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+
5
+
6
+ from enum import Enum
7
+
8
+
9
+ class LicenseFindingCurationReason(Enum):
10
+ """
11
+ A curation for a license finding. Use it to correct a license finding or to add a license that was not
12
+ previously detected.
13
+
14
+ Attributes:
15
+ CODE: The findings occur in source code, for example the name of a variable.
16
+ DATA_OF: The findings occur in a data, for example a JSON object defining all SPDX licenses.
17
+ DOCUMENTATION_OF: The findings occur in documentation, for example in code comments or in the README.md.
18
+ INCORRECT: The detected licenses are not correct. Use only if none of the other reasons apply.
19
+ NOT_DETECTED: Add applicable license as the scanner did not detect it.
20
+ REFERENCE: The findings reference a file or URL, e.g. SEE LICENSE IN LICENSE or https://jquery.org/license/.
21
+ """
22
+
23
+ CODE = "CODE"
24
+ DATA_OF = "DATA_OF"
25
+ DOCUMENTATION_OF = "DOCUMENTATION_OF"
26
+ INCORRECT = "INCORRECT"
27
+ NOT_DETECTED = "NOT_DETECTED"
28
+ REFERENCE = "REFERENCE"
@@ -0,0 +1,19 @@
1
+ # SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <heliocastro@gmail.com>
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ from pydantic import BaseModel, Field
5
+
6
+ from ort.models.hash_algorithm import HashAlgorithm
7
+
8
+
9
+ class Hash(BaseModel):
10
+ """
11
+ A class that bundles a hash algorithm with its hash value.
12
+
13
+ Attributes:
14
+ value (str): The value calculated using the hash algorithm.
15
+ algorithm (HashAlgorithm): The algorithm used to calculate the hash value.
16
+ """
17
+
18
+ value: str = Field(description="The value calculated using the hash algorithm.")
19
+ algorithm: HashAlgorithm = Field(description="The algorithm used to calculate the hash value.")
@@ -0,0 +1,37 @@
1
+ # SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <heliocastro@gmail.com>
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+
5
+
6
+ from enum import Enum
7
+
8
+
9
+ class HashAlgorithm(Enum):
10
+ """
11
+ An enum of supported hash algorithms. Each algorithm has one or more [aliases] associated to it,
12
+ where the first alias is the definite name.
13
+
14
+ Attributes:
15
+ NONE: No hash algorithm.
16
+ UNKNOWN: An unknown hash algorithm.
17
+ MD5: The Message-Digest 5 hash algorithm, see [MD5](http://en.wikipedia.org/wiki/MD5).
18
+ SHA1: The Secure Hash Algorithm 1, see [SHA-1](https://en.wikipedia.org/wiki/SHA-1).
19
+ SHA256: The Secure Hash Algorithm 2 with 256 bits, see [SHA-256](https://en.wikipedia.org/wiki/SHA-256).
20
+ SHA384: The Secure Hash Algorithm 2 with 384 bits, see [SHA-384](https://en.wikipedia.org/wiki/SHA-384).
21
+ SHA512: The Secure Hash Algorithm 2 with 512 bits, see [SHA-512](https://en.wikipedia.org/wiki/SHA-512).
22
+ SHA1GIT: The Secure Hash Algorithm 1, but calculated on a Git "blob" object, see
23
+ - https://git-scm.com/book/en/v2/Git-Internals-Git-Objects#_object_storage
24
+ - https://docs.softwareheritage.org/devel/swh-model/persistent-identifiers.html#git-compatibility
25
+ """
26
+
27
+ NONE = "NONE"
28
+ UNKNOWN = "UNKNOWN"
29
+ MD5 = "MD5"
30
+ SHA1 = "SHA1"
31
+ SHA256 = "SHA256"
32
+ SHA384 = "SHA384"
33
+ SHA512 = "SHA512"
34
+ SHA1GIT = (
35
+ ["SHA-1-GIT", "SHA1-GIT", "SHA1GIT", "SWHID"],
36
+ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
37
+ )
@@ -0,0 +1,15 @@
1
+ # SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <heliocastro@gmail.com>
2
+ # SPDX-License-Identifier: MIT
3
+
4
+
5
+ from pydantic import BaseModel, ConfigDict
6
+
7
+ from .package_curation_data import PackageCurationData
8
+
9
+
10
+ class PackageCuration(BaseModel):
11
+ model_config = ConfigDict(
12
+ extra="forbid",
13
+ )
14
+ id: str
15
+ curations: PackageCurationData
@@ -0,0 +1,36 @@
1
+ # SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <heliocastro@gmail.com>
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ from typing import Any
5
+
6
+ from pydantic import AnyUrl, BaseModel, ConfigDict, Field
7
+
8
+ from .hash import Hash
9
+ from .source_code_origin import SourceCodeOrigin
10
+ from .vcsinfo_curation_data import VcsInfoCurationData
11
+
12
+
13
+ class CurationArtifact(BaseModel):
14
+ url: AnyUrl
15
+ hash: Hash
16
+
17
+
18
+ class PackageCurationData(BaseModel):
19
+ model_config = ConfigDict(
20
+ extra="forbid",
21
+ )
22
+ comment: str | None = None
23
+ purl: str | None = None
24
+ cpe: str | None = None
25
+ authors: list[str] | None = None
26
+ concluded_license: str | None = None
27
+ description: str | None = None
28
+ homepage_url: str | None = None
29
+ binary_artifact: CurationArtifact | None = None
30
+ source_artifact: CurationArtifact | None = None
31
+ vcs: VcsInfoCurationData | None = None
32
+ is_metadata_only: bool | None = None
33
+ is_modified: bool | None = None
34
+ declared_license_mapping: dict[str, Any] = Field(default_factory=dict)
35
+ source_code_origins: list[SourceCodeOrigin] | None = None
36
+ labels: dict[str, str] = Field(default_factory=dict)
@@ -7,9 +7,9 @@ from typing import Any
7
7
 
8
8
  from pydantic import BaseModel, Field, RootModel
9
9
 
10
- from .analyzer_configurations import OrtAnalyzerConfigurations
11
- from .package_managers import OrtPackageManagerConfigurations, PackageManagerConfigs
12
- from .source_code_origin import SourceCodeOrigin
10
+ from ort.models.analyzer_configurations import OrtAnalyzerConfigurations
11
+ from ort.models.config.curations import Curations
12
+ from ort.models.package_managers import OrtPackageManagerConfigurations, PackageManagerConfigs
13
13
 
14
14
 
15
15
  class OrtRepositoryConfigurationLicenseChoicesPackageLicenseChoiceLicenseChoice(BaseModel):
@@ -66,45 +66,6 @@ class VulnerabilityResolutionReason(Enum):
66
66
  workaround_for_vulnerability = "WORKAROUND_FOR_VULNERABILITY"
67
67
 
68
68
 
69
- class VcsMatcherVcsMatcher(BaseModel):
70
- path: str | None = None
71
- revision: str | None = None
72
- type: str
73
- url: str | None = None
74
-
75
-
76
- class VcsMatcherVcsMatcher1(BaseModel):
77
- path: str | None = None
78
- revision: str | None = None
79
- type: str | None = None
80
- url: str
81
-
82
-
83
- class VcsMatcherVcsMatcher2(BaseModel):
84
- path: str | None = None
85
- revision: str
86
- type: str | None = None
87
- url: str | None = None
88
-
89
-
90
- class VcsMatcherVcsMatcher3(BaseModel):
91
- path: str
92
- revision: str | None = None
93
- type: str | None = None
94
- url: str | None = None
95
-
96
-
97
- class VcsMatcher(
98
- RootModel[VcsMatcherVcsMatcher | VcsMatcherVcsMatcher1 | VcsMatcherVcsMatcher2 | VcsMatcherVcsMatcher3]
99
- ):
100
- root: VcsMatcherVcsMatcher | VcsMatcherVcsMatcher1 | VcsMatcherVcsMatcher2 | VcsMatcherVcsMatcher3
101
-
102
-
103
- class Hash(BaseModel):
104
- value: str
105
- algorithm: str
106
-
107
-
108
69
  class PackageConfigurationSchemaSourceCodeOrigin(Enum):
109
70
  vcs = "VCS"
110
71
  artifact = "ARTIFACT"
@@ -141,24 +102,6 @@ class PathExcludeReason(Enum):
141
102
  test_tool_of = "TEST_TOOL_OF"
142
103
 
143
104
 
144
- VcsMatcherVcsMatcher4 = VcsMatcherVcsMatcher
145
-
146
-
147
- VcsMatcherVcsMatcher5 = VcsMatcherVcsMatcher1
148
-
149
-
150
- VcsMatcherVcsMatcher6 = VcsMatcherVcsMatcher2
151
-
152
-
153
- VcsMatcherVcsMatcher7 = VcsMatcherVcsMatcher3
154
-
155
-
156
- class VcsMatcherModel(
157
- RootModel[VcsMatcherVcsMatcher4 | VcsMatcherVcsMatcher5 | VcsMatcherVcsMatcher6 | VcsMatcherVcsMatcher7]
158
- ):
159
- root: VcsMatcherVcsMatcher4 | VcsMatcherVcsMatcher5 | VcsMatcherVcsMatcher6 | VcsMatcherVcsMatcher7
160
-
161
-
162
105
  class PathIncludeReason(Enum):
163
106
  source_of = "SOURCE_OF"
164
107
 
@@ -301,47 +244,6 @@ class ResolutionsSchema(
301
244
  )
302
245
 
303
246
 
304
- class CurationsSchemaCurationsSchemaItemCurationsBinaryArtifact(BaseModel):
305
- url: str
306
- hash: Hash
307
-
308
-
309
- CurationsSchemaCurationsSchemaItemCurationsSourceArtifact = CurationsSchemaCurationsSchemaItemCurationsBinaryArtifact
310
-
311
-
312
- class CurationsSchemaCurationsSchemaItemCurations(BaseModel):
313
- comment: str | None = None
314
- purl: str | None = None
315
- cpe: str | None = None
316
- authors: list[str] | None = None
317
- concluded_license: str | None = None
318
- description: str | None = None
319
- homepage_url: str | None = None
320
- binary_artifact: CurationsSchemaCurationsSchemaItemCurationsBinaryArtifact | None = None
321
- source_artifact: CurationsSchemaCurationsSchemaItemCurationsSourceArtifact | None = None
322
- vcs: VcsMatcher | None = None
323
- is_metadata_only: bool | None = None
324
- is_modified: bool | None = None
325
- declared_license_mapping: dict[str, Any] = Field(default_factory=dict)
326
- source_code_origins: list[SourceCodeOrigin] | None = None
327
- labels: dict[str, str] = Field(default_factory=dict)
328
-
329
-
330
- class CurationsSchemaCurationsSchemaItem(BaseModel):
331
- id: str
332
- curations: CurationsSchemaCurationsSchemaItemCurations
333
-
334
-
335
- class CurationsSchema(RootModel[list[CurationsSchemaCurationsSchemaItem]]):
336
- root: list[CurationsSchemaCurationsSchemaItem] = Field(
337
- ...,
338
- description="The OSS-Review-Toolkit (ORT) provides a possibility to correct metadata and set "
339
- "the concluded license for specific packages (dependencies) in curation files. A full list of all available "
340
- "options can be found at https://oss-review-toolkit.org/ort/docs/configuration/package-curations.",
341
- title="ORT curations",
342
- )
343
-
344
-
345
247
  class LicenseFindingCurationsModel(BaseModel):
346
248
  path: str
347
249
  start_lines: int | str | None = None
@@ -352,14 +254,14 @@ class LicenseFindingCurationsModel(BaseModel):
352
254
  comment: str | None = None
353
255
 
354
256
 
355
- class OrtRepositoryConfigurationCurations(BaseModel):
257
+ class OrtRepositoryConfigurationH(BaseModel):
356
258
  license_findings: list[LicenseFindingCurationsModel]
357
- packages: CurationsSchema | None = None
259
+ packages: Curations | None = None
358
260
 
359
261
 
360
262
  class OrtRepositoryConfigurationCurations1(BaseModel):
361
263
  license_findings: list[LicenseFindingCurationsModel] | None = None
362
- packages: CurationsSchema
264
+ packages: Curations
363
265
 
364
266
 
365
267
  class OrtRepositoryConfiguration(BaseModel):
@@ -388,9 +290,10 @@ class OrtRepositoryConfiguration(BaseModel):
388
290
  description="Defines which parts of a repository should be excluded.",
389
291
  )
390
292
  resolutions: ResolutionsSchema | None = None
391
- curations: OrtRepositoryConfigurationCurations | OrtRepositoryConfigurationCurations1 | None = Field(
293
+ curations: Curations | None = Field(
392
294
  None,
393
- description="Curations for artifacts in a repository.",
295
+ description="Defines curations for packages used as dependencies by projects in this repository,"
296
+ " or curations for license findings in the source code of a project in this repository.",
394
297
  )
395
298
  package_configurations: list[OrtPackageManagerConfigurations] | None = Field(
396
299
  None,
@@ -0,0 +1,33 @@
1
+ # SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <heliocastro@gmail.com>
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ from pydantic import AnyUrl, BaseModel, Field
5
+
6
+ from .vcstype import VcsType
7
+
8
+
9
+ class VcsInfo(BaseModel):
10
+ """
11
+ Bundles general Version Control System information.
12
+
13
+ Attributes:
14
+ type(VcsType): The type of the VCS, for example Git, GitRepo, Mercurial, etc.
15
+ url(AnyUrl): The URL to the VCS repository.
16
+ revision(str): The VCS-specific revision (tag, branch, SHA1) that the version of the package maps to.
17
+ path(str): The path inside the VCS to take into account.
18
+ If the VCS supports checking out only a subdirectory, only this path is checked out.
19
+ """
20
+
21
+ type: VcsType = Field(
22
+ default_factory=VcsType,
23
+ description="The type of the VCS, for example Git, GitRepo, Mercurial, etc.",
24
+ )
25
+ url: AnyUrl = Field(description="The URL to the VCS repository.")
26
+ revision: str = Field(
27
+ description="The VCS-specific revision (tag, branch, SHA1) that the version of the package maps to."
28
+ )
29
+ path: str = Field(
30
+ default="",
31
+ description="The path inside the VCS to take into account."
32
+ "If the VCS supports checking out only a subdirectory, only this path is checked out.",
33
+ )
@@ -0,0 +1,37 @@
1
+ # SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <heliocastro@gmail.com>
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ from pydantic import AnyUrl, BaseModel, Field
5
+
6
+ from .vcstype import VcsType
7
+
8
+
9
+ class VcsInfoCurationData(BaseModel):
10
+ """
11
+ Bundles general Version Control System information.
12
+
13
+ Attributes:
14
+ type(VcsType): The type of the VCS, for example Git, GitRepo, Mercurial, etc.
15
+ url(AnyUrl): The URL to the VCS repository.
16
+ revision(str): The VCS-specific revision (tag, branch, SHA1) that the version of the package maps to.
17
+ path(str): The path inside the VCS to take into account.
18
+ If the VCS supports checking out only a subdirectory, only this path is checked out.
19
+ """
20
+
21
+ type: VcsType | None = Field(
22
+ default=None,
23
+ description="The type of the VCS, for example Git, GitRepo, Mercurial, etc.",
24
+ )
25
+ url: AnyUrl | None = Field(
26
+ default=None,
27
+ description="The URL to the VCS repository.",
28
+ )
29
+ revision: str | None = Field(
30
+ default=None,
31
+ description="The VCS-specific revision (tag, branch, SHA1) that the version of the package maps to.",
32
+ )
33
+ path: str | None = Field(
34
+ default=None,
35
+ description="The path inside the VCS to take into account."
36
+ "If the VCS supports checking out only a subdirectory, only this path is checked out.",
37
+ )
@@ -0,0 +1,45 @@
1
+ # SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <heliocastro@gmail.com>
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ from pydantic import BaseModel, Field, model_validator
5
+
6
+ # Define known VCS types as constants
7
+ GIT = ["Git", "GitHub", "GitLab"]
8
+ GIT_REPO = ["GitRepo", "git-repo", "repo"]
9
+ MERCURIAL = ["Mercurial", "hg"]
10
+ SUBVERSION = ["Subversion", "svn"]
11
+
12
+ KNOWN_TYPES = GIT + GIT_REPO + MERCURIAL + SUBVERSION
13
+
14
+
15
+ class VcsType(BaseModel):
16
+ """
17
+ A class for Version Control System types. Each type has one or more [aliases] associated to it,
18
+ where the first alias is the definite name. This class is not implemented as an enum as
19
+ constructing from an unknown type should be supported while maintaining that type as the primary
20
+ alias for the string representation.
21
+
22
+ Attributes:
23
+ name(str): Primary name and aliases
24
+ """
25
+
26
+ name: str = Field(default_factory=str)
27
+
28
+ @model_validator(mode="before")
29
+ @classmethod
30
+ def _forName(cls, value):
31
+ # Allow direct string input (e.g., "Git" or "gitlab")
32
+ if isinstance(value, str):
33
+ if any(item.lower() == value.lower() for item in KNOWN_TYPES):
34
+ return {"name": value}
35
+ else:
36
+ # Not a known type → default to empty string
37
+ return {"name": ""}
38
+ # Allow dict input or existing model
39
+ elif isinstance(value, dict):
40
+ name = value.get("name", "")
41
+ if any(item.lower() == name.lower() for item in KNOWN_TYPES):
42
+ return value
43
+ else:
44
+ return {"name": ""}
45
+ return {"name": ""}
File without changes
File without changes