tests.fake_manager module¶
In-memory package manager for CLI plumbing tests.
Real-manager iteration leaks the host environment into the test suite: a
runner without apk skips it, a runner without brew skips it, and
assertions about package counts or table rendering become a function of which
binaries happen to be on PATH. The FakeManager below sidesteps
that by reporting as available on every platform and yielding a fixed catalog
of packages without ever invoking a subprocess.
Tests opt in via the fake_pool fixture in tests.conftest, which
monkeypatches meta_package_manager.pool.ManagerPool.select_managers()
to yield a single fake instead of the real-manager iteration.
- class tests.fake_manager.FakeManager[source]¶
Bases:
PackageManagerAlways-available manager with deterministic outputs.
Reports as supported on every platform and short-circuits the discovery properties (
cli_path,executable,fresh,version) so the pool never tries to introspect a real binary. Subcommand methods yield fixed package sets so tests can assert on counts and ordering.Initialize
cli_errorslist.- homepage_url: str | None = 'https://example.invalid/fake-manager'¶
Home page of the project, only used in documentation for reference.
Left unset when the home page is the project’s repository, which
repository_urlnames on its own, and when it is the project’s manual, whichdocumentation_urlnames. Never inherited, like the other links.
- platforms: frozenset[Platform] | Group | Platform | Iterable[Platform | Group] = frozenset({Platform(id='aix', name='IBM AIX'), Platform(id='almalinux', name='AlmaLinux'), Platform(id='alpine', name='Alpine Linux'), Platform(id='altlinux', name='ALT Linux'), Platform(id='amzn', name='Amazon Linux'), Platform(id='android', name='Android'), Platform(id='arch', name='Arch Linux'), Platform(id='buildroot', name='Buildroot'), Platform(id='cachyos', name='CachyOS'), Platform(id='centos', name='CentOS'), Platform(id='chromeos', name='ChromeOS'), Platform(id='clearlinux', name='Clear Linux OS'), Platform(id='cloudlinux', name='CloudLinux OS'), Platform(id='crux', name='CRUX'), Platform(id='cygwin', name='Cygwin'), Platform(id='debian', name='Debian'), Platform(id='dragonfly_bsd', name='DragonFly BSD'), Platform(id='endeavouros', name='EndeavourOS'), Platform(id='exherbo', name='Exherbo Linux'), Platform(id='fedora', name='Fedora'), Platform(id='freebsd', name='FreeBSD'), Platform(id='generic_linux', name='Generic Linux'), Platform(id='gentoo', name='Gentoo Linux'), Platform(id='guix', name='Guix System'), Platform(id='haiku', name='Haiku'), Platform(id='hurd', name='GNU/Hurd'), Platform(id='ibm_powerkvm', name='IBM PowerKVM'), Platform(id='illumos', name='illumos'), Platform(id='kali', name='Kali Linux'), Platform(id='kvmibm', name='KVM for IBM z Systems'), Platform(id='linuxmint', name='Linux Mint'), Platform(id='macos', name='macOS'), Platform(id='mageia', name='Mageia'), Platform(id='mandriva', name='Mandriva Linux'), Platform(id='manjaro', name='Manjaro Linux'), Platform(id='midnightbsd', name='MidnightBSD'), Platform(id='netbsd', name='NetBSD'), Platform(id='nixos', name='NixOS'), Platform(id='nobara', name='Nobara'), Platform(id='nutyx', name='NuTyX'), Platform(id='openbsd', name='OpenBSD'), Platform(id='opensuse', name='openSUSE'), Platform(id='openwrt', name='OpenWrt'), Platform(id='oracle', name='Oracle Linux'), Platform(id='os400', name='IBM i'), Platform(id='parallels', name='Parallels'), Platform(id='pidora', name='Pidora'), Platform(id='pikaos', name='PikaOS'), Platform(id='raspbian', name='Raspbian'), Platform(id='rhel', name='RedHat Enterprise Linux'), Platform(id='rocky', name='Rocky Linux'), Platform(id='scientific', name='Scientific Linux'), Platform(id='slackware', name='Slackware'), Platform(id='sles', name='SUSE Linux Enterprise Server'), Platform(id='slitaz', name='SliTaz GNU/Linux'), Platform(id='solaris', name='Solaris'), Platform(id='solus', name='Solus'), Platform(id='sourcemage', name='Source Mage GNU/Linux'), Platform(id='sunos', name='SunOS'), Platform(id='tuxedo', name='Tuxedo OS'), Platform(id='ubuntu', name='Ubuntu'), Platform(id='ultramarine', name='Ultramarine'), Platform(id='void', name='Void Linux'), Platform(id='windows', name='Windows'), Platform(id='wsl1', name='Windows Subsystem for Linux v1'), Platform(id='wsl2', name='Windows Subsystem for Linux v2'), Platform(id='xenserver', name='XenServer')})¶
List of platforms supported by the manager.
Allows for a mishmash of platforms and groups of platforms. Will be normalized into a
frozensetofPlatforminstances at instantiation.
- cli_names: tuple[str, ...] = ('fake-mpm',)¶
List of CLI names the package manager is known as.
This list of recognized CLI names is ordered by priority. That way we can influence the search of the right binary.
- ..hint::
This was helpful in the case of the Python transition from 2.x to 3.x, where multiple versions of the same executable were named
pythonorpython3.
By default, this property’s value is derived from the manager’s ID (see the
MetaPackageManager.__init__method above).
- requirement: str | None = '>=0'¶
Version requirement specifier.
Supports a comma-separated range of constraints (e.g.
">=1.20.0,<2.0.0"). A bare version string like"1.20.0"is treated as>=1.20.0.Parsed by
meta_package_manager.version.VersionRange.Defaults to
None, which deactivates version check entirely.
- property cli_path: Path[source]¶
Fully qualified path to the canonical package manager binary.
Try each CLI names provided by
cli_names, in each system path provided bycli_search_path. In that order. Then returns the first match.Executability of the CLI will be separately assessed later by the
meta_package_manager.execution.CLIExecutor.executableproperty below.
- property version: TokenizedString | None[source]¶
Invoke the manager and extract its own reported version string.
Returns a parsed and normalized version in the form of a
meta_package_manager.version.TokenizedStringinstance.Skipped on platforms where the manager is not supported, even if
cli_pathresolved to an executable: that binary almost certainly belongs to a different tool that happens to share the same name (e.g. GNUmakeon macOS getting matched by the FreeBSDportsmanager), so probing it would either misreport the version or surface confusing error output.
- property installed: Iterator[Package]¶
List packages currently installed on the system.
Optional. Will be simply skipped by mpm if not implemented.
- property outdated: Iterator[Package]¶
List installed packages with available upgrades.
Optional. Will be simply skipped by mpm if not implemented.
- property orphans: Iterator[Package]¶
List packages installed as dependencies that nothing requires anymore.
The read-only counterpart of the
--orphansaction flags: wherempm cleanup --orphansremoves the orphans, this query only reports them, through the manager’s native listing (pacman --query --deps --unrequired,brew autoremove --dry-run,dnf repoquery --unneeded, …). mpm builds no dependency graph: the manager decides what is orphaned.Optional. Will be simply skipped by mpm if not implemented.
- search(query, extended, exact)[source]¶
Search packages available for install.
There is no need for this method to be perfect and sensitive to
extendedandexactparameters. If the package manager is not supporting these kind of options out of the box, just returns the closest subset of matching package you can come up with. Finer refiltering will happens in themeta_package_manager.manager.PackageManager.refiltered_search()method below.Optional. Will be simply skipped by mpm if not implemented.
- upgrade_all_cli()[source]¶
Static upgrade CLIs declare the upgrade capabilities.
Never invoked by
meta_package_manager.bar_plugin_renderer.BarPluginRenderer.add_upgrade_cli(), which routes menu actions throughmpmitself, but their presence is what makesmeta_package_manager.capabilities.implements()report theupgradeandupgrade_alloperations as supported, so the fake manager’s menu lines carry an action.
- upgrade_one_cli(package_id, version=None)[source]¶
Returns the complete CLI to upgrade one package and one only.
Allows a specific
versionto be provided.
- documentation_url: str | None = None¶
Entry point of the project’s own documentation, or
Nonewhen it has none.The manual, the documentation site, or the man page of the CLI
mpmdrives: whichever page a user reads to learn the commands this manager wraps. Listed betweenhomepage_urlandrepository_urlin the links of the manager’s page, so a reader reaching for the tool’s reference finds it in the box of facts rather than in the prose below it.Left unset where a link would state a fact twice or invent one: a tool documenting itself in its repository alone, whose README
repository_urlalready reaches. A page about the ecosystem rather than the tool does not qualify either.Where a project’s only site is its manual, that address belongs here and
homepage_urlstays unset: the slot names what the page is, and a reader reaching for the reference looks under the documentation link.Never inherited, like every other link: the AUR helpers extending
pacmaneach document themselves.
- id: str = 'fakemanager'¶
Package manager’s ID.
Derived by defaults from the lower-cased class name in which underscores
_are replaced by dashes-.This ID must be unique among all package manager definitions and lower-case, as they’re used as feature flags for the mpm CLI.
- name: str = 'FakeManager'¶
Return package manager’s common name.
Default value is based on class name.
- repository_url: str | None = None¶
Repository holding the project’s code, or
Nonewhen it has no public one.Linked from the manager’s documentation page. Also what the weekly metrics sample reads:
docs/docs_update.pywrites it into the[tool.repomatic.metrics] subjectsofpyproject.tomlwhen its forge answers the sampler, through a mirror for a forge that does not.Never inherited, for the same reason as
wikipedia_url: the AUR helpers extendingpacmaneach live in a repository of their own.
- virtual: bool = False¶
Should we expose the package manager to the user?
Virtual package manager are just skeleton classes used to factorize code among managers of the same family.
- wikipedia_url: str | None = None¶
English Wikipedia article about the project, or
Nonewhen it has none.Listed last in the links of the manager’s documentation page. The article covers the project that home page names, or is a redirect Wikipedia keeps under the project’s name, landing on the part of a broader article that describes it:
Cargo_(software)opens the Cargo section of the Rust article. An article that merely mentions the project does not count, nor does one about a related subject:lazyis a Neovim plugin manager, and the Neovim article is not about it.Never inherited: the metaclass resets it to
Noneon any class not declaring its own. A subclass often wraps a distinct project, like the six AUR helpers extendingpacman, and would otherwise present pacman’s article as its own. Documentation-only, likehomepage_url.
- class tests.fake_manager.ChangingFakeManager[source]¶
Bases:
FakeManagerVariant whose inventory changes when a command acts on it.
Models what the change report reads on a real host. Every operation runs the interpreter on a no-op, so it spawns a real subprocess that exits
0, then applies its change toinventory, unless the run only simulates:a full upgrade moves one outdated package, leaves the pinned one behind, moves a third package back, pulls a dependency in and drops the orphan;
a single-package upgrade moves its package and pulls the same dependency in, and leaves the pinned one alone;
an install adds its package and that dependency, and fails on an ID that contains
broken;a removal drops its package, and its cascading variant drops the orphan too;
the orphan sweep drops the orphan.
A package no operation touches stays in
inventoryas it is.Initialize
cli_errorslist.- DEPENDENCY = ('fake-pkg-gamma', '0.1.0')¶
The dependency an install or an upgrade pulls in, with its version.
- LATEST: ClassVar = {'fake-pkg-alpha': '1.1.0', 'fake-pkg-beta': '2.6.0'}¶
The outdated packages, each with the version it can move to.
- ORPHAN = 'fake-pkg-epsilon'¶
The package nothing requires, which the orphan sweeps drop.
- PINNED = 'fake-pkg-beta'¶
The outdated package every upgrade leaves behind.
- inventory¶
The installed version of each package, keyed by package ID.
- property installed: Iterator[Package]¶
List packages currently installed on the system.
Optional. Will be simply skipped by mpm if not implemented.
- property outdated: Iterator[Package]¶
List installed packages with available upgrades.
Optional. Will be simply skipped by mpm if not implemented.
- property orphans: Iterator[Package]¶
List packages installed as dependencies that nothing requires anymore.
The read-only counterpart of the
--orphansaction flags: wherempm cleanup --orphansremoves the orphans, this query only reports them, through the manager’s native listing (pacman --query --deps --unrequired,brew autoremove --dry-run,dnf repoquery --unneeded, …). mpm builds no dependency graph: the manager decides what is orphaned.Optional. Will be simply skipped by mpm if not implemented.
- search(query, extended, exact)[source]¶
Find any package, so an install left untied reaches its attempt.
- install(package_id, version=None)[source]¶
Install one package and one only.
Allows a specific
versionto be provided.- Return type:
- upgrade_all_cli()[source]¶
Static upgrade CLIs declare the upgrade capabilities.
Never invoked by
meta_package_manager.bar_plugin_renderer.BarPluginRenderer.add_upgrade_cli(), which routes menu actions throughmpmitself, but their presence is what makesmeta_package_manager.capabilities.implements()report theupgradeandupgrade_alloperations as supported, so the fake manager’s menu lines carry an action.
- upgrade_one_cli(package_id, version=None)[source]¶
Returns the complete CLI to upgrade one package and one only.
Allows a specific
versionto be provided.
- upgrade(package_id=None, version=None, *, outdated_ids=None)[source]¶
Perform an upgrade of either all or one package.
Executes the CLI provided by either
meta_package_manager.manager.PackageManager.upgrade_all_cli()ormeta_package_manager.manager.PackageManager.upgrade_one_cli().If the manager doesn’t provides a full upgrade one-liner (i.e. if
meta_package_manager.manager.PackageManager.upgrade_all_cli()raisesNotImplementedError), then the list of all outdated packages will be fetched (viameta_package_manager.manager.PackageManager.outdated()) and each package will be updated one by one by callingmeta_package_manager.manager.PackageManager.upgrade_one_cli().See for example the case of
meta_package_manager.managers.pip.Pip.upgrade_one_cli().An active probe-backed cooldown (see
cooldown_hold()) routes through_upgrade_all_with_cooldowninstead of the plain one-shot command, so individual too-fresh releases can be held back while the rest of the upgrade proceeds.outdated_idshands over the outdated packages the caller already listed, so neither path enumerating them (the one-by-one fallback and the cooldown hold) lists a second time:mpm upgrade --allpasses theoutdated_inventory()its report took. A single-package upgrade and the native one-shot command ignore it, and a full upgrade left without it lists on its own.- Return type:
- cli_names: tuple[str, ...] = ('changingfakemanager',)¶
List of CLI names the package manager is known as.
This list of recognized CLI names is ordered by priority. That way we can influence the search of the right binary.
- ..hint::
This was helpful in the case of the Python transition from 2.x to 3.x, where multiple versions of the same executable were named
pythonorpython3.
By default, this property’s value is derived from the manager’s ID (see the
MetaPackageManager.__init__method above).
- documentation_url: str | None = None¶
Entry point of the project’s own documentation, or
Nonewhen it has none.The manual, the documentation site, or the man page of the CLI
mpmdrives: whichever page a user reads to learn the commands this manager wraps. Listed betweenhomepage_urlandrepository_urlin the links of the manager’s page, so a reader reaching for the tool’s reference finds it in the box of facts rather than in the prose below it.Left unset where a link would state a fact twice or invent one: a tool documenting itself in its repository alone, whose README
repository_urlalready reaches. A page about the ecosystem rather than the tool does not qualify either.Where a project’s only site is its manual, that address belongs here and
homepage_urlstays unset: the slot names what the page is, and a reader reaching for the reference looks under the documentation link.Never inherited, like every other link: the AUR helpers extending
pacmaneach document themselves.
- homepage_url: str | None = None¶
Home page of the project, only used in documentation for reference.
Left unset when the home page is the project’s repository, which
repository_urlnames on its own, and when it is the project’s manual, whichdocumentation_urlnames. Never inherited, like the other links.
- id: str = 'changingfakemanager'¶
Package manager’s ID.
Derived by defaults from the lower-cased class name in which underscores
_are replaced by dashes-.This ID must be unique among all package manager definitions and lower-case, as they’re used as feature flags for the mpm CLI.
- name: str = 'ChangingFakeManager'¶
Return package manager’s common name.
Default value is based on class name.
- remove(package_id)[source]¶
Remove one package and one only.
Optional. Will be simply skipped by mpm if not implemented.
- Return type:
- repository_url: str | None = None¶
Repository holding the project’s code, or
Nonewhen it has no public one.Linked from the manager’s documentation page. Also what the weekly metrics sample reads:
docs/docs_update.pywrites it into the[tool.repomatic.metrics] subjectsofpyproject.tomlwhen its forge answers the sampler, through a mirror for a forge that does not.Never inherited, for the same reason as
wikipedia_url: the AUR helpers extendingpacmaneach live in a repository of their own.
- virtual: bool = False¶
Should we expose the package manager to the user?
Virtual package manager are just skeleton classes used to factorize code among managers of the same family.
- wikipedia_url: str | None = None¶
English Wikipedia article about the project, or
Nonewhen it has none.Listed last in the links of the manager’s documentation page. The article covers the project that home page names, or is a redirect Wikipedia keeps under the project’s name, landing on the part of a broader article that describes it:
Cargo_(software)opens the Cargo section of the Rust article. An article that merely mentions the project does not count, nor does one about a related subject:lazyis a Neovim plugin manager, and the Neovim article is not about it.Never inherited: the metaclass resets it to
Noneon any class not declaring its own. A subclass often wraps a distinct project, like the six AUR helpers extendingpacman, and would otherwise present pacman’s article as its own. Documentation-only, likehomepage_url.
- remove_orphan(package_id)[source]¶
Remove one package together with the dependencies it alone pulled in.
The opt-in counterpart to
meta_package_manager.manager.PackageManager.remove(), surfaced asmpm remove --orphans. It maps to the manager’s native “remove and drop now-unneeded dependencies” verb (apt remove --auto-remove,pacman --remove --recursive,dnf autoremove, …), so mpm builds no dependency graph of its own.Optional. A manager with no such native verb leaves this
NotImplementedError;mpm remove --orphansthen falls back tometa_package_manager.manager.PackageManager.remove()and logs oneINFOcapability-skip.- Return type:
- cleanup_orphan()[source]¶
Remove every orphaned package on the system, sparing the caches.
The system-wide “remove all packages nothing depends on anymore” sweep (
apt autoremove,brew autoremove,flatpak uninstall --unused, …). The one cleanup category that removes packages, so it is deliberately kept out of the plaincleanup()composition and only runs on an explicitmpm cleanup --orphans.Distinct from
meta_package_manager.manager.PackageManager.remove_orphan(), which is scoped to one package’s own orphaned dependencies. As withcleanup(), mpm builds no dependency graph: the manager decides what is orphaned.A manager with no native sweep verb is backfilled by this base implementation when it supports both the
orphansquery and package removal: list the orphans, remove each one (withremove_orphan()when available, so every listed root takes its own now-orphaned subtree along), then re-query and repeat until the listing settles, since removing an orphan can orphan its own dependencies. The exact pattern of the synthesized fullupgrade --all, and the in-process equivalent of Arch’s classicpacman -Rns $(pacman -Qtdq)idiom. The re-query loop stops as soon as a round makes no progress, so removal failures cannot spin it forever.A manager implementing neither a native sweep nor the
orphansquery propagatesNotImplementedError, andmpm cleanup --orphanssimply skips it.- Return type:
- class tests.fake_manager.TimingOutFakeManager[source]¶
Bases:
FakeManagerVariant that runs a real subprocess long enough to trip
--timeout.Used by
tests.test_cli.test_timeout()to exercise thesubprocess.TimeoutExpiredbranch inmeta_package_manager.execution.CLIExecutor.run(). The Python interpreter is invoked as the manager’s CLI so the test stays cross-platform; the sleep duration is derived fromtimeoutso the call is guaranteed to overshoot.Initialize
cli_errorslist.- cli_names: tuple[str, ...] = ('timingoutfakemanager',)¶
List of CLI names the package manager is known as.
This list of recognized CLI names is ordered by priority. That way we can influence the search of the right binary.
- ..hint::
This was helpful in the case of the Python transition from 2.x to 3.x, where multiple versions of the same executable were named
pythonorpython3.
By default, this property’s value is derived from the manager’s ID (see the
MetaPackageManager.__init__method above).
- documentation_url: str | None = None¶
Entry point of the project’s own documentation, or
Nonewhen it has none.The manual, the documentation site, or the man page of the CLI
mpmdrives: whichever page a user reads to learn the commands this manager wraps. Listed betweenhomepage_urlandrepository_urlin the links of the manager’s page, so a reader reaching for the tool’s reference finds it in the box of facts rather than in the prose below it.Left unset where a link would state a fact twice or invent one: a tool documenting itself in its repository alone, whose README
repository_urlalready reaches. A page about the ecosystem rather than the tool does not qualify either.Where a project’s only site is its manual, that address belongs here and
homepage_urlstays unset: the slot names what the page is, and a reader reaching for the reference looks under the documentation link.Never inherited, like every other link: the AUR helpers extending
pacmaneach document themselves.
- homepage_url: str | None = None¶
Home page of the project, only used in documentation for reference.
Left unset when the home page is the project’s repository, which
repository_urlnames on its own, and when it is the project’s manual, whichdocumentation_urlnames. Never inherited, like the other links.
- id: str = 'timingoutfakemanager'¶
Package manager’s ID.
Derived by defaults from the lower-cased class name in which underscores
_are replaced by dashes-.This ID must be unique among all package manager definitions and lower-case, as they’re used as feature flags for the mpm CLI.
- name: str = 'TimingOutFakeManager'¶
Return package manager’s common name.
Default value is based on class name.
- repository_url: str | None = None¶
Repository holding the project’s code, or
Nonewhen it has no public one.Linked from the manager’s documentation page. Also what the weekly metrics sample reads:
docs/docs_update.pywrites it into the[tool.repomatic.metrics] subjectsofpyproject.tomlwhen its forge answers the sampler, through a mirror for a forge that does not.Never inherited, for the same reason as
wikipedia_url: the AUR helpers extendingpacmaneach live in a repository of their own.
- virtual: bool = False¶
Should we expose the package manager to the user?
Virtual package manager are just skeleton classes used to factorize code among managers of the same family.
- wikipedia_url: str | None = None¶
English Wikipedia article about the project, or
Nonewhen it has none.Listed last in the links of the manager’s documentation page. The article covers the project that home page names, or is a redirect Wikipedia keeps under the project’s name, landing on the part of a broader article that describes it:
Cargo_(software)opens the Cargo section of the Rust article. An article that merely mentions the project does not count, nor does one about a related subject:lazyis a Neovim plugin manager, and the Neovim article is not about it.Never inherited: the metaclass resets it to
Noneon any class not declaring its own. A subclass often wraps a distinct project, like the six AUR helpers extendingpacman, and would otherwise present pacman’s article as its own. Documentation-only, likehomepage_url.