Module continuous_delivery_scripts.plugins.python
Plugin for Python projects.
Expand source code
#
# Copyright (C) 2020-2025 Arm Limited or its affiliates and Contributors. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
"""Plugin for Python projects."""
import logging
import shutil
import sys
from pathlib import Path
from subprocess import check_call
from typing import List, Optional
from continuous_delivery_scripts.spdx_report.spdx_project import SpdxProject
from continuous_delivery_scripts.utils.configuration import configuration, ConfigurationVariable
from continuous_delivery_scripts.utils.definitions import CommitType
from continuous_delivery_scripts.utils.filesystem_helpers import TemporaryDirectory
from continuous_delivery_scripts.utils.filesystem_helpers import cd
from continuous_delivery_scripts.utils.language_specifics_base import BaseLanguage, get_language_from_file_name
from continuous_delivery_scripts.utils.logging import log_exception
from continuous_delivery_scripts.utils.python.package_helpers import (
CurrentPythonProjectMetadataFetcher,
generate_package_info,
)
ENVVAR_TWINE_USERNAME = "TWINE_USERNAME"
ENVVAR_TWINE_PASSWORD = "TWINE_PASSWORD"
OUTPUT_DIRECTORY = "release-dist"
logger = logging.getLogger(__name__)
def _create_wheel() -> None:
root = configuration.get_value(ConfigurationVariable.PROJECT_ROOT)
with cd(root):
check_call(
[
sys.executable,
"setup.py",
"clean",
"--all",
"sdist",
"-d",
OUTPUT_DIRECTORY,
"--formats=gztar",
"bdist_wheel",
"-d",
OUTPUT_DIRECTORY,
]
)
def _release_to_pypi() -> None:
logger.info("Releasing to PyPI")
root = configuration.get_value(ConfigurationVariable.PROJECT_ROOT)
with cd(root):
_upload_to_test_pypi()
_upload_to_pypi()
def _upload_to_pypi() -> None:
logger.info("Uploading to PyPI")
check_call([sys.executable, "-m", "twine", "upload", f"{OUTPUT_DIRECTORY}/*"])
logger.info("Success đź‘Ť")
def _upload_to_test_pypi() -> None:
if configuration.get_value_or_default(ConfigurationVariable.IGNORE_REPOSITORY_TEST_UPLOAD, False):
logger.warning("Not testing package upload on PyPI test (https://test.pypi.org)")
return
logger.info("Uploading to test PyPI")
check_call(
[
sys.executable,
"-m",
"twine",
"upload",
"--repository-url",
"https://test.pypi.org/legacy/",
f"{OUTPUT_DIRECTORY}/*",
]
)
logger.info("Success đź‘Ť")
def _generate_pdoc_command_list(output_directory: Path, module: str) -> List[str]:
return [
"pdoc",
"--html",
f"{module}",
"--output-dir",
f"{str(output_directory)}",
"--force",
"--config",
"show_type_annotations=True",
]
def _call_pdoc(output_directory: Path, module: str) -> None:
"""Calls Pdoc for generating the docs."""
logger.info("Creating Pdoc documentation.")
command_list = _generate_pdoc_command_list(output_directory, module)
check_call(command_list)
def _generate_pdoc_in_correct_structure(module_to_document: str, output_directory: Path) -> None:
"""Ensures the documentation is in the correct location.
Pdoc nests its docs output in a folder with the module's name.
This process removes this unwanted folder.
"""
with TemporaryDirectory() as temp_dir:
_call_pdoc(temp_dir, module_to_document)
docs_contents_dir = temp_dir.joinpath(module_to_document)
if docs_contents_dir.exists() and docs_contents_dir.is_dir():
for element in docs_contents_dir.iterdir():
shutil.move(str(element), str(output_directory))
def _get_current_spdx_project() -> SpdxProject:
"""Gets information about the current project/package."""
logger.info("Generating package information.")
try:
# Trying to generate the egg for the package but this may fail. If so, continue.
generate_package_info()
except Exception as e:
log_exception(logger, e)
return SpdxProject(CurrentPythonProjectMetadataFetcher())
class Python(BaseLanguage):
"""Specific actions for a Python project."""
def get_related_language(self) -> str:
"""Gets related language."""
return get_language_from_file_name(__file__)
def package_software(self, mode: CommitType, version: str) -> None:
"""Packages the software into a wheel."""
super().package_software(mode, version)
_create_wheel()
def release_package_to_repository(self, mode: CommitType, version: str) -> None:
"""Releases to PyPI."""
super().release_package_to_repository(mode, version)
_release_to_pypi()
def check_credentials(self) -> None:
"""Checks Twine credentials."""
super().check_credentials()
# Checks that twine username is defined
configuration.get_value(ENVVAR_TWINE_USERNAME)
# Checks that twine password is defined
configuration.get_value(ENVVAR_TWINE_PASSWORD)
def generate_code_documentation(self, output_directory: Path, module_to_document: str) -> None:
"""Generates code documentation."""
super().generate_code_documentation(output_directory, module_to_document)
_generate_pdoc_in_correct_structure(module_to_document, output_directory)
def can_add_licence_headers(self) -> bool:
"""States that licence headers can be added."""
return True
def can_get_project_metadata(self) -> bool:
"""States whether project metadata can be retrieved."""
return True
def should_include_spdx_in_package(self) -> bool:
"""States whether the SPDX documents should be included in the package."""
return True
def get_current_spdx_project(self) -> Optional[SpdxProject]:
"""Gets the current SPDX description."""
return _get_current_spdx_project()
Classes
class Python
-
Specific actions for a Python project.
Expand source code
class Python(BaseLanguage): """Specific actions for a Python project.""" def get_related_language(self) -> str: """Gets related language.""" return get_language_from_file_name(__file__) def package_software(self, mode: CommitType, version: str) -> None: """Packages the software into a wheel.""" super().package_software(mode, version) _create_wheel() def release_package_to_repository(self, mode: CommitType, version: str) -> None: """Releases to PyPI.""" super().release_package_to_repository(mode, version) _release_to_pypi() def check_credentials(self) -> None: """Checks Twine credentials.""" super().check_credentials() # Checks that twine username is defined configuration.get_value(ENVVAR_TWINE_USERNAME) # Checks that twine password is defined configuration.get_value(ENVVAR_TWINE_PASSWORD) def generate_code_documentation(self, output_directory: Path, module_to_document: str) -> None: """Generates code documentation.""" super().generate_code_documentation(output_directory, module_to_document) _generate_pdoc_in_correct_structure(module_to_document, output_directory) def can_add_licence_headers(self) -> bool: """States that licence headers can be added.""" return True def can_get_project_metadata(self) -> bool: """States whether project metadata can be retrieved.""" return True def should_include_spdx_in_package(self) -> bool: """States whether the SPDX documents should be included in the package.""" return True def get_current_spdx_project(self) -> Optional[SpdxProject]: """Gets the current SPDX description.""" return _get_current_spdx_project()
Ancestors
- BaseLanguage
- abc.ABC
Methods
def can_add_licence_headers(self) ‑> bool
-
States that licence headers can be added.
Expand source code
def can_add_licence_headers(self) -> bool: """States that licence headers can be added.""" return True
def check_credentials(self) ‑> None
-
Checks Twine credentials.
Expand source code
def check_credentials(self) -> None: """Checks Twine credentials.""" super().check_credentials() # Checks that twine username is defined configuration.get_value(ENVVAR_TWINE_USERNAME) # Checks that twine password is defined configuration.get_value(ENVVAR_TWINE_PASSWORD)
def generate_code_documentation(self, output_directory: pathlib.Path, module_to_document: str) ‑> None
-
Generates code documentation.
Expand source code
def generate_code_documentation(self, output_directory: Path, module_to_document: str) -> None: """Generates code documentation.""" super().generate_code_documentation(output_directory, module_to_document) _generate_pdoc_in_correct_structure(module_to_document, output_directory)
def get_current_spdx_project(self) ‑> Optional[SpdxProject]
-
Gets the current SPDX description.
Expand source code
def get_current_spdx_project(self) -> Optional[SpdxProject]: """Gets the current SPDX description.""" return _get_current_spdx_project()
-
Gets related language.
Expand source code
def get_related_language(self) -> str: """Gets related language.""" return get_language_from_file_name(__file__)
def package_software(self, mode: CommitType, version: str) ‑> None
-
Packages the software into a wheel.
Expand source code
def package_software(self, mode: CommitType, version: str) -> None: """Packages the software into a wheel.""" super().package_software(mode, version) _create_wheel()
def release_package_to_repository(self, mode: CommitType, version: str) ‑> None
-
Releases to PyPI.
Expand source code
def release_package_to_repository(self, mode: CommitType, version: str) -> None: """Releases to PyPI.""" super().release_package_to_repository(mode, version) _release_to_pypi()
Inherited members