Source code for friendly_dist_manager.pyproject.project_table

"""Primitives for manipulating the 'project' table in a pyproject.toml file"""
from pathlib import Path
from collections import namedtuple

# TODO: add support for dynamic metadata sub-table

Person = namedtuple("Person", ["name", "email"])
Entrypoint = namedtuple("Entrypoint", ["name", "ref"])
ProjectURL = namedtuple("ProjectURL", ["label", "url"])


[docs]class ProjectTable: # pylint: disable=too-many-public-methods """Abstraction around the 'project' table from a pyproject.toml file References: * https://www.python.org/dev/peps/pep-0621/ """ def __init__(self, data): """ Args: data (dict): TOML data parsed from a pyproject.toml config file """ self._data = data @property def name(self): """str: name of the distribution being built""" return self._data["name"] @property def version(self): """str: version of the distribution being built""" return self._data["version"] @property def description(self): """str: descriptive name summarizing the purpose of the distribution""" return self._data.get("description", "") @property def readme_file(self): """pathlib.Path: reference to the readme file associated with the project, or None if no readme file provided""" if "readme" not in self._data: return None return Path(self._data["readme"]) @property def readme(self): """str: text formatted data loaded from the mentioned readme file associated with the project""" if not self.readme_file: return "" if not self.readme_file.exists(): raise FileNotFoundError(f"Readme file {self.readme_file} does not exist") return self.readme_file.read_text(encoding="UTF-8") @property def python_requirement(self): """str: the Python runtime version identifier indicating the range of versions supported by this project""" return self._data.get("requires-python", "") @property def license(self): """str: text explaining the licensing details associated with the project""" if "license" not in self._data: return "" if "text" in self._data["license"]: return self._data["license"]["text"] lic_file = Path(self._data["license"]["file"]) if not lic_file.exists(): raise FileNotFoundError(f"License file not found: {lic_file}") return lic_file.read_text(encoding="UTF-8") @property def authors(self): """list(Person): list of people who are considered 'authors' of the project Note: each person may have a name and/or an email address, but either one may be omitted """ retval = list() for cur_per in self._data.get("authors", list()): retval.append(Person(cur_per.get("name"), cur_per.get("email"))) return retval @property def maintainers(self): """list(Person): list of people who are considered 'maintainers' of the project Note: each person may have a name and/or an email address, but either one may be omitted """ retval = list() for cur_per in self._data.get("maintainers", list()): retval.append(Person(cur_per.get("name"), cur_per.get("email"))) return retval @property def keywords(self): """list (str): descriptive keywords used when searching for project on pypi""" return self._data.get("keywords", list()) @property def classifiers(self): """list (str): trove classifiers describing properties of the project https://pypi.org/classifiers/ """ return self._data.get("classifiers", list()) @property def urls(self): """list (ProjectURL): URLs providing additional information about the distribution package""" retval = list() for proj_key, proj_url in self._data.get("urls", dict()).items(): retval.append(ProjectURL(proj_key, proj_url)) return retval @property def console_scripts(self): """list (Entrypoint): list of entry points for console / shell scripts exposed by the project""" retval = list() for ep_name, ep_ref in self._data.get("scripts", dict()).items(): retval.append(Entrypoint(ep_name, ep_ref)) return retval @property def gui_scripts(self): """list (Entrypoint): list of application entry points for GUI based projects""" retval = list() for ep_name, ep_ref in self._data.get("gui-scripts", dict()).items(): retval.append(Entrypoint(ep_name, ep_ref)) return retval @property def _entrypoints(self): """dict: mapping of custom entrypoint identifiers to the set of entrypoints associated with each ID""" return self._data.get("entry-point", dict()) @property def entrypoint_identifiers(self): """list (str): list of custom entrypoint identifiers associated with the project""" return list(self._entrypoints.keys())
[docs] def get_entrypoint(self, entrypoint_id): """Gets definition for a custom entrypoint associated with the project Args: entrypoint_id (str): ID of the entrypoint to retrieve. See :meth:`entrypoint_identifiers` for supported values Returns: list (Entrypoint): list of entrypoints associated with the entrypoint identifier """ retval = list() for ep_name, ep_ref in self._entrypoints.get(entrypoint_id, dict()).items(): retval.append(Entrypoint(ep_name, ep_ref)) return retval
@property def dependencies(self): """list (str): list of package dependencies associated with this project References: * https://www.python.org/dev/peps/pep-0508/ """ return self._data.get("dependencies", list()) @property def _optional_dependencies(self): """dict: mapping table linking IDs of sets of optional package dependencies, to the list of dependency definitions associated with them""" return self._data.get("optional-dependencies", dict()) @property def optional_dependency_identifiers(self): """list (str): list of IDs associated with groups of optional package dependencies associated with the project""" return list(self._optional_dependencies.keys())
[docs] def get_optional_dependencies(self, dependency_id): """Set of dependencies associated with a specific group ID References: * https://www.python.org/dev/peps/pep-0508/ Args: dependency_id (str): identifier for a specific group of optional dependencies associated with the project. See :meth:`optional_dependency_identifiers` for list of valid options Returns: list (str): list of dependency definitions for the optional dependencies associated with the specified ID """ return self._optional_dependencies.get(dependency_id, list())