plesty.server.model.device_manager ================================== .. py:module:: plesty.server.model.device_manager .. autoapi-nested-parse:: What is installed on this bench: device modules, several versions side by side. A fleet file says which package an instance *wants*; the installer puts a version of it on disk; this module remembers the outcome. Every ``(package, version)`` pair has its own environment under ``/packages///`` and a record next to it, so two instances pinned to the same release share one environment, a newer release is installed beside the old one, and rolling back is pointing the instance at the version that is still there. The manager only keeps the books — creating or deleting the environments is the installer's job, which calls :meth:`DeviceManager.record` when an install finished and :meth:`DeviceManager.forget` when it removed one. Attributes ---------- .. autoapisummary:: plesty.server.model.device_manager.SOURCE_PYPI plesty.server.model.device_manager.SOURCE_GIT Exceptions ---------- .. autoapisummary:: plesty.server.model.device_manager.DeviceManagerError Classes ------- .. autoapisummary:: plesty.server.model.device_manager.InstalledVersion plesty.server.model.device_manager.PackageInfo plesty.server.model.device_manager.InstalledPackage plesty.server.model.device_manager.DeviceManager Functions --------- .. autoapisummary:: plesty.server.model.device_manager.version_order plesty.server.model.device_manager.install_order plesty.server.model.device_manager._now Module Contents --------------- .. py:data:: SOURCE_PYPI :value: 'pypi' .. py:data:: SOURCE_GIT :value: 'git' .. py:exception:: DeviceManagerError Bases: :py:obj:`ValueError` An installed-version record is missing or inconsistent. Initialize self. See help(type(self)) for accurate signature. .. py:class:: InstalledVersion One version of one device module present on the bench. :ivar package: PyPI distribution name, e.g. ``plesty-pm100d``. :ivar version: The installed release as reported by the environment. :ivar source: :data:`SOURCE_PYPI` or :data:`SOURCE_GIT`. :ivar git: Repository URL for a git source, else ``None``. :ivar ref: Branch, tag or commit that was requested for a git source. :ivar commit: The commit actually checked out for a git source. :ivar installed_utc: ISO timestamp of the install. :ivar python: Version of the interpreter in the environment. :ivar job_id: The install job that produced it, when known. :ivar path: Where the environment lives when it is not the default ``/packages///`` — a git checkout, whose ``.venv`` is the environment. .. py:attribute:: package :type: str .. py:attribute:: version :type: str .. py:attribute:: source :type: str :value: 'pypi' .. py:attribute:: git :type: str | None :value: None .. py:attribute:: ref :type: str | None :value: None .. py:attribute:: commit :type: str | None :value: None .. py:attribute:: installed_utc :type: str :value: '' .. py:attribute:: python :type: str :value: '' .. py:attribute:: job_id :type: str | None :value: None .. py:attribute:: path :type: str :value: '' .. py:method:: __post_init__() -> None Validate the record. .. py:property:: slot :type: str the version for a release, ``git-`` for a checkout. A checkout moves — its version changes with every pull — so it is kept by the ref it tracks, and two checkouts at the same commit (two refs) never share a record. :type: What identifies the environment within the package .. py:property:: key :type: tuple[str, str] ``(package, slot)`` — what identifies the environment. .. py:method:: satisfies(spec: plesty.server.model.device.DeviceSpec) -> bool Whether this install is what *spec* asks for. A PyPI spec is satisfied by the pinned version (or any PyPI version when unpinned); a git spec by an install from the same repository at the same ref (or ``v``), a commit hash matching by prefix. .. py:method:: to_dict() -> dict[str, Any] JSON form. .. py:method:: from_dict(data: collections.abc.Mapping[str, Any]) -> InstalledVersion :classmethod: Rebuild a record from :meth:`to_dict` output (extra keys ignored). .. py:class:: PackageInfo What the bench knows about a module as a project — independent of any install. Learned from the catalogue (``adopt``) or from a git install, kept in ``/packages//package.json`` and never asked again: the repository a module comes from, its project page, its latest release. :ivar package: Distribution name. :ivar repo_url: Clone URL of the module's repository. :ivar web_url: Project page (GitLab), ``""`` when unknown. :ivar latest_tag: Latest release tag seen (``v0.2.1``), ``""`` when none. :ivar version: Latest release version seen, ``""`` when none. :ivar vendor: Hub vendor group, ``""`` when unknown. :ivar description: One line, ``""`` when unknown. .. py:attribute:: package :type: str .. py:attribute:: repo_url :type: str :value: '' .. py:attribute:: web_url :type: str :value: '' .. py:attribute:: latest_tag :type: str :value: '' .. py:attribute:: version :type: str :value: '' .. py:attribute:: vendor :type: str :value: '' .. py:attribute:: description :type: str :value: '' .. py:method:: to_dict() -> dict[str, Any] JSON form. .. py:method:: from_dict(data: collections.abc.Mapping[str, Any]) -> PackageInfo :classmethod: Rebuild from :meth:`to_dict` output (extra keys ignored). .. py:method:: merged(**fields: str) -> PackageInfo A copy with the non-empty *fields* replacing the current values. .. py:class:: InstalledPackage All installed versions of one device module. :ivar package: Distribution name. :ivar versions: Records keyed by slot (version, or ``git-``), oldest install first. .. py:attribute:: package :type: str .. py:attribute:: versions :type: collections.abc.Mapping[str, InstalledVersion] .. py:method:: __iter__() -> collections.abc.Iterator[InstalledVersion] Iterate over the versions, oldest install first. .. py:method:: __len__() -> int Number of installed versions. .. py:method:: __contains__(version: object) -> bool Whether *version* (a slot, or a release version) is installed. .. py:property:: latest :type: InstalledVersion | None The most recently installed version, or ``None`` when empty. .. py:function:: version_order(version: str) -> tuple[int, Ellipsis] *version* as numbers, so ``0.10.0`` sorts above ``0.9.0``. .. py:function:: install_order(installed: InstalledVersion) -> tuple[str, tuple[int, Ellipsis]] Order installs by when they happened, then by version. ``installed_utc`` is stamped to the second, so two installs of the same package in one second tie — and a bare ``max``/``sorted`` then falls back to the order the records happened to be read in. That order is the filesystem's, so "the latest version" was whichever the host listed last and differed between a Windows bench and a POSIX machine. The version breaks the tie. .. py:class:: DeviceManager(home: plesty.server.model.home.Home) The installed-module inventory under a :class:`Home`. Bind to a home. :param home: The bench home. .. py:attribute:: home .. py:method:: record(package: str, version: str, source: str = SOURCE_PYPI, git: str | None = None, ref: str | None = None, commit: str | None = None, python: str = '', job_id: str | None = None, path: str | os.PathLike[str] | None = None) -> InstalledVersion Write down that *package* *version* is installed; returns the record. :param package: Distribution name. :param version: Installed release. :param source: :data:`SOURCE_PYPI` or :data:`SOURCE_GIT`. :param git: Repository URL for a git source. :param ref: Requested ref for a git source. :param commit: Checked-out commit for a git source. :param python: Interpreter version of the environment. :param job_id: The install job. :param path: Environment location when not the default package dir. .. py:method:: save(installed: InstalledVersion) -> pathlib.Path Write *installed* to its record file; returns the path. .. py:method:: get(package: str, slot: str) -> InstalledVersion | None The record of *package* at *slot* (a version, or ``git-``), or ``None``. .. py:method:: require(package: str, slot: str) -> InstalledVersion Like :meth:`get` but raises :class:`DeviceManagerError` when absent. .. py:method:: package(package: str) -> InstalledPackage Every installed version of *package* (empty when none). .. py:method:: list() -> list[InstalledPackage] Every package with at least one installed version, by name. .. py:method:: info(package: str) -> PackageInfo The package-level record of *package* (empty fields when nothing is known). .. py:method:: remember(package: str, **fields: str) -> PackageInfo Merge non-empty *fields* into the package-level record; returns it. .. py:method:: env_dir(installed: InstalledVersion) -> pathlib.Path The environment directory of *installed* (its ``path``, else the package dir). .. py:method:: resolve(spec: plesty.server.model.device.DeviceSpec) -> InstalledVersion | None The installed version that serves *spec*, or ``None`` when one must be installed. The most recent install among those that :meth:`InstalledVersion.satisfies` the spec wins — for an unpinned PyPI spec that is the newest install, for a git branch the last pull. .. py:method:: forget(package: str, slot: str, remove_env: bool = False) -> bool Drop the record of *package* at *slot*; ``True`` when it existed. :param package: Distribution name. :param slot: Version (release) or ``git-`` (checkout). :param remove_env: Also delete a release's environment directory. .. py:function:: _now() -> str