Module continuous_delivery_scripts.utils.package_helpers
Shared package metadata used by language plugins and licence reports.
Classes
class CurrentProjectMetadataFetcher-
Expand source code
class CurrentProjectMetadataFetcher(ProjectMetadataFetcher): """Fetches the current project metadata.""" def __init__(self) -> None: """Constructor.""" super().__init__(configuration.get_value(ConfigurationVariable.PACKAGE_NAME))Fetches the current project metadata.
Constructor.
Ancestors
- ProjectMetadataFetcher
- abc.ABC
Inherited members
class LicenceSource (*values)-
Expand source code
class LicenceSource(Enum): """Where a package's declared licence was obtained.""" EXPRESSION = "License-Expression" LEGACY = "License" CLASSIFIER = "License-Classifier" CONFIGURATION = "configuration" TOOL = "tool" UNKNOWN = "unknown"Where a package's declared licence was obtained.
Ancestors
- enum.Enum
Class variables
var CLASSIFIER-
The type of the None singleton.
var CONFIGURATION-
The type of the None singleton.
var EXPRESSION-
The type of the None singleton.
var LEGACY-
The type of the None singleton.
var TOOL-
The type of the None singleton.
var UNKNOWN-
The type of the None singleton.
class PackageMetadata (data: Mapping[str, Any] | continuous_delivery_scripts.utils.package_helpers._PackageFields,
licence_evidence: List[Dict[str, str]] | None = None)-
Expand source code
class PackageMetadata: """Language-neutral package metadata supplied by a project plugin. Metadata keys follow Python Core Metadata where possible so that other languages can use the same SPDX and licence-reporting pipeline. It is based on https://www.python.org/dev/peps/pep-0314/ https://packaging.python.org/specifications/core-metadata/ """ def __init__( self, data: Union[Mapping[str, Any], _PackageFields], licence_evidence: Optional[List[Dict[str, str]]] = None ) -> None: """Accept named fields or adapt Python Core Metadata at the input boundary.""" if isinstance(data, _PackageFields): self._fields = data return expression = str(data.get("License-Expression") or "").strip() legacy = str(data.get("License") or "").strip() classifier = str(data.get("License-Classifier") or "").strip() if expression: licence, source = expression, LicenceSource.EXPRESSION elif ( legacy and not legacy.lower().startswith("copyright") and legacy.lower() not in ("unknown", "none") and ("\n" not in legacy or not classifier) ): licence, source = legacy, LicenceSource.LEGACY elif classifier: licence, source = classifier, LicenceSource.CLASSIFIER else: licence, source = UNKNOWN, LicenceSource.UNKNOWN project_url = str(data.get("Project-URL") or "") url = str(data.get("Home-page") or project_url.partition(",")[2].strip() or UNKNOWN) self._fields = _PackageFields( name=str(data.get("Name", UNKNOWN)), version=str(data.get("Version", UNKNOWN)), author=str(data.get("Author", UNKNOWN)), author_email=str(data.get("Author-email", UNKNOWN)), licence=licence, licence_source=source, declared_licence=str(expression or legacy or "; ".join(data.get("License-Classifiers", []))), description=str(data.get("Summary", UNKNOWN)), url=url, licence_classifiers=list(data.get("License-Classifiers", [])), licence_candidates=list(data.get("Licence-Candidates", [])), licence_evidence=licence_evidence or [], ) @classmethod def from_fields( cls, *, name: str, licence: str, licence_source: LicenceSource, version: str = UNKNOWN, url: str = UNKNOWN, declared_licence: Optional[str] = None, licence_classifiers: Optional[List[str]] = None, licence_candidates: Optional[List[str]] = None, licence_evidence: Optional[List[Dict[str, str]]] = None, author: str = UNKNOWN, author_email: str = UNKNOWN, description: str = UNKNOWN, ) -> "PackageMetadata": """Build metadata from named fields without relying on Python header keys.""" return cls( _PackageFields( name=name, version=version, author=author, author_email=author_email, licence=licence, licence_source=licence_source, declared_licence=licence if declared_licence is None else declared_licence, description=description, url=url, licence_classifiers=list(licence_classifiers or []), licence_candidates=list(licence_candidates or []), licence_evidence=list(licence_evidence or []), ) ) @property def name(self) -> str: """Gets package's name.""" return self._fields.name @property def version(self) -> str: """Gets package's version.""" return self._fields.version @property def author(self) -> str: """Gets package's author.""" return self._fields.author @property def author_email(self) -> str: """Gets package's author email.""" return self._fields.author_email @property def licence(self) -> str: """Gets package's licence.""" return self._fields.licence @property def licence_source(self) -> str: """Gets the metadata field used to determine the licence.""" return self._fields.licence_source.value @property def has_unknown_licence(self) -> bool: """Whether no usable licence declaration was found.""" return self._fields.licence_source is LicenceSource.UNKNOWN @property def declared_licence(self) -> str: """Gets the licence declaration as provided by the package.""" return self._fields.declared_licence @property def licence_classifiers(self) -> List[str]: """Gets all licence classifiers as declared by the package.""" return list(self._fields.licence_classifiers) @property def licence_candidates(self) -> List[str]: """Gets normalised SPDX licence candidates that require review.""" return list(self._fields.licence_candidates) @property def licence_evidence(self) -> List[Dict[str, str]]: """Gets the packaged licence and notice file evidence.""" return self._fields.licence_evidence @property def description(self) -> str: """Gets the package description.""" return self._fields.description @property def url(self) -> str: """Gets package's URL.""" return self._fields.url def __str__(self) -> str: """String representation.""" relevant_data = [ f"{getter}: {getattr(self, getter, None)}" for getter in dir(self) if not getter.startswith("_") and not callable(getattr(self, getter, None)) ] return ", ".join(relevant_data)Language-neutral package metadata supplied by a project plugin.
Metadata keys follow Python Core Metadata where possible so that other languages can use the same SPDX and licence-reporting pipeline. It is based on https://www.python.org/dev/peps/pep-0314/ https://packaging.python.org/specifications/core-metadata/
Accept named fields or adapt Python Core Metadata at the input boundary.
Static methods
def from_fields(*,
name: str,
licence: str,
licence_source: LicenceSource,
version: str = 'unknown',
url: str = 'unknown',
declared_licence: str | None = None,
licence_classifiers: List[str] | None = None,
licence_candidates: List[str] | None = None,
licence_evidence: List[Dict[str, str]] | None = None,
author: str = 'unknown',
author_email: str = 'unknown',
description: str = 'unknown') ‑> PackageMetadata-
Build metadata from named fields without relying on Python header keys.
Instance variables
-
Expand source code
@property def author(self) -> str: """Gets package's author.""" return self._fields.authorGets package's author.
-
Expand source code
@property def author_email(self) -> str: """Gets package's author email.""" return self._fields.author_emailGets package's author email.
prop declared_licence : str-
Expand source code
@property def declared_licence(self) -> str: """Gets the licence declaration as provided by the package.""" return self._fields.declared_licenceGets the licence declaration as provided by the package.
prop description : str-
Expand source code
@property def description(self) -> str: """Gets the package description.""" return self._fields.descriptionGets the package description.
prop has_unknown_licence : bool-
Expand source code
@property def has_unknown_licence(self) -> bool: """Whether no usable licence declaration was found.""" return self._fields.licence_source is LicenceSource.UNKNOWNWhether no usable licence declaration was found.
prop licence : str-
Expand source code
@property def licence(self) -> str: """Gets package's licence.""" return self._fields.licenceGets package's licence.
prop licence_candidates : List[str]-
Expand source code
@property def licence_candidates(self) -> List[str]: """Gets normalised SPDX licence candidates that require review.""" return list(self._fields.licence_candidates)Gets normalised SPDX licence candidates that require review.
prop licence_classifiers : List[str]-
Expand source code
@property def licence_classifiers(self) -> List[str]: """Gets all licence classifiers as declared by the package.""" return list(self._fields.licence_classifiers)Gets all licence classifiers as declared by the package.
prop licence_evidence : List[Dict[str, str]]-
Expand source code
@property def licence_evidence(self) -> List[Dict[str, str]]: """Gets the packaged licence and notice file evidence.""" return self._fields.licence_evidenceGets the packaged licence and notice file evidence.
prop licence_source : str-
Expand source code
@property def licence_source(self) -> str: """Gets the metadata field used to determine the licence.""" return self._fields.licence_source.valueGets the metadata field used to determine the licence.
prop name : str-
Expand source code
@property def name(self) -> str: """Gets package's name.""" return self._fields.nameGets package's name.
prop url : str-
Expand source code
@property def url(self) -> str: """Gets package's URL.""" return self._fields.urlGets package's URL.
prop version : str-
Expand source code
@property def version(self) -> str: """Gets package's version.""" return self._fields.versionGets package's version.
class ProjectMetadata (package_name: str)-
Expand source code
class ProjectMetadata: """Metadata for a project.""" def __init__(self, package_name: str) -> None: """Constructor.""" self._package_metadata: PackageMetadata = PackageMetadata(dict()) self._dependency_packages_metadata: List[PackageMetadata] = list() self._package_name: str = package_name self.missing_dependencies: List[str] = [] @property def dependencies_metadata(self) -> List[PackageMetadata]: """Gets all package's dependencies metadata.""" return self._dependency_packages_metadata def add_dependency_metadata(self, dependency_metadata: PackageMetadata) -> None: """Adds metadata about a dependency.""" self._dependency_packages_metadata.append(dependency_metadata) @property def project_metadata(self) -> PackageMetadata: """Gets project metadata.""" return self._package_metadata @project_metadata.setter def project_metadata(self, package_metadata: PackageMetadata) -> None: """Sets project metadata.""" self._package_metadata = package_metadata @property def package_name(self) -> str: """Gets project's package name.""" return self._package_name def __str__(self) -> str: """String representation. Prints the project name and its dependencies. """ dependencies_str = " | ".join([str(t) for t in self._dependency_packages_metadata]) project_str = f"Project [{self.package_name}]" metadata_str = str(self._package_metadata) other_str = f"Dependencies: [{dependencies_str}]" return f"{project_str}: {metadata_str}; {other_str}"Metadata for a project.
Constructor.
Instance variables
prop dependencies_metadata : List[PackageMetadata]-
Expand source code
@property def dependencies_metadata(self) -> List[PackageMetadata]: """Gets all package's dependencies metadata.""" return self._dependency_packages_metadataGets all package's dependencies metadata.
prop package_name : str-
Expand source code
@property def package_name(self) -> str: """Gets project's package name.""" return self._package_nameGets project's package name.
prop project_metadata : PackageMetadata-
Expand source code
@property def project_metadata(self) -> PackageMetadata: """Gets project metadata.""" return self._package_metadataGets project metadata.
Methods
def add_dependency_metadata(self,
dependency_metadata: PackageMetadata) ‑> None-
Expand source code
def add_dependency_metadata(self, dependency_metadata: PackageMetadata) -> None: """Adds metadata about a dependency.""" self._dependency_packages_metadata.append(dependency_metadata)Adds metadata about a dependency.
class ProjectMetadataFetcher (package_name: str)-
Expand source code
class ProjectMetadataFetcher(ABC): """Fetches package metadata e.g. dependencies.""" def __init__(self, package_name: str) -> None: """Constructor.""" self._project_metadata: Optional[ProjectMetadata] = None self._package_name = package_name @property def project_metadata(self) -> ProjectMetadata: """Gets project metadata.""" if not self._project_metadata: self._project_metadata = self.fetch_project_metadata() return self._project_metadata @abstractmethod def fetch_project_metadata(self) -> ProjectMetadata: """Fetches the project metadata.""" passFetches package metadata e.g. dependencies.
Constructor.
Ancestors
- abc.ABC
Subclasses
- GoProjectMetadataFetcher
- NoOpProjectMetadataFetcher
- CurrentProjectMetadataFetcher
- PythonProjectMetadataFetcher
Instance variables
prop project_metadata : ProjectMetadata-
Expand source code
@property def project_metadata(self) -> ProjectMetadata: """Gets project metadata.""" if not self._project_metadata: self._project_metadata = self.fetch_project_metadata() return self._project_metadataGets project metadata.
Methods
def fetch_project_metadata(self) ‑> ProjectMetadata-
Expand source code
@abstractmethod def fetch_project_metadata(self) -> ProjectMetadata: """Fetches the project metadata.""" passFetches the project metadata.