Skip to content

python

dev_tool.services.python

__all__ = ['ContainerPackageManager', 'DependencyResolver', 'DependencySource', 'PackageManager', 'PackageManagerFactory', 'PythonService', 'UnixPipPackageManager', 'UnixUvPackageManager', 'WindowsPipPackageManager', 'WindowsUvPackageManager'] module-attribute

ContainerPackageManager

Bases: BaseService

A class for managing Python packages in a containerized environment.

This class provides methods for installing, uninstalling, and listing packages within Docker containers using uv pip.

install_dependencies

A method that installs dependencies in the container.

Parameters:

Source code in dev_tool/services/python/package/container.py
def install_dependencies(self, sources: list[DependencySource]) -> None:
    """
    A method that installs dependencies in the container.

    :param sources: The dependency sources to install from.
    """

    strategy = ExecutionStrategyProvider.get()

    for source in sources:
        if source.source == SourceType.PYPROJECT:
            extra = source.extra

            target = f'-e .[{extra}]' if extra else '-e .'

            message = f'Installing from pyproject.toml ({source.name})...'
            self.notification.normal_text(message)

            strategy.run_pip_command(['install', '--system', target], tty=False)

        elif source.source == SourceType.REQUIREMENTS:
            if source.path is None:
                continue

            message = f'Installing from {source.path.name}...'
            self.notification.normal_text(message)

            container_path = f'/app/{source.path.name}'
            strategy.run_pip_command(['install', '--system', '-r', container_path], tty=False)

install_package

A method that installs a package in the container.

Parameters:

  • package (str) –

    The name of the package to install.

Returns:

  • bool

    True if successful, False otherwise.

Source code in dev_tool/services/python/package/container.py
def install_package(self, package: str) -> bool:
    """
    A method that installs a package in the container.

    :param package: The name of the package to install.
    :return: True if successful, False otherwise.
    """

    result = ExecutionStrategyProvider.get().run_pip_command(
        ['install', '--system', package],
        tty=False
    )

    return result.returncode == 0

list_packages

A method that lists installed packages in the container.

Returns:

  • list[str]

    A list of installed package names.

Source code in dev_tool/services/python/package/container.py
def list_packages(self) -> list[str]:
    """
    A method that lists installed packages in the container.

    :return: A list of installed package names.
    """

    result = ExecutionStrategyProvider.get().run_pip_command(
        ['list', '--format=freeze'],
        tty=False
    )

    if result.returncode != 0:
        return []

    output = result.stdout.decode() if result.stdout else ''

    return [
        line.split('==')[0].lower()
        for line in output.strip().split('\n')
        if '==' in line
    ]

uninstall_package

A method that uninstalls a package from the container.

Parameters:

  • package (str) –

    The name of the package to uninstall.

Returns:

  • bool

    True if successful, False otherwise.

Source code in dev_tool/services/python/package/container.py
def uninstall_package(self, package: str) -> bool:
    """
    A method that uninstalls a package from the container.

    :param package: The name of the package to uninstall.
    :return: True if successful, False otherwise.
    """

    if self._is_editable_from_mount(package):
        message = (
            f'The "{package}" package is installed in editable mode from a mounted path. '
            f'Remove it from PYTHONPATH_APPEND in development.env to stop using it.'
        )

        self.notification.warning_text(message)

        log.debug(message)

        normalized = package.replace('-', '_')

        script = (
            f'import shutil, glob; '
            f'[shutil.rmtree(p) for p in glob.glob("/usr/local/lib/python3.11/site-packages/{normalized}*.dist-info")]'
        )

        result = ExecutionStrategyProvider.get().run_python_command(
            ['-c', script],
            tty=False
        )

        return result.returncode == 0

    result = ExecutionStrategyProvider.get().run_pip_command(
        ['uninstall', '--system', package],
        tty=False
    )

    return result.returncode == 0

DependencyResolver

A class for discovering and resolving dependency sources.

This class provides methods for finding all available dependency sources and determining the best installation strategy.

The constructor for the DependencyResolver class.

This method initializes the resolver with a config manager and sets up the patterns for discovering dependency sources.

Source code in dev_tool/services/python/package/dependencies.py
def __init__(self) -> None:
    """
    The constructor for the DependencyResolver class.

    This method initializes the resolver with a config manager and
    sets up the patterns for discovering dependency sources.
    """

    self._requirements = [
        'requirements.txt',
        'development_requirements.txt',
        'production_requirements.txt',
        'mkdocs_requirements.txt',
        'test_requirements.txt'
    ]

clean_content

A method that returns requirements file content with -r references removed.

This method reads a requirements file and filters out any -r directives to prevent redundant installations while keeping the file's own dependencies.

Parameters:

  • requirements (Path) –

    The path to the requirements file.

Returns:

  • str

    The cleaned requirements content as a string.

Source code in dev_tool/services/python/package/dependencies.py
def clean_content(self, requirements: Path) -> str:
    """
    A method that returns requirements file content with `-r` references removed.

    This method reads a requirements file and filters out any `-r` directives
    to prevent redundant installations while keeping the file's own dependencies.

    :param requirements: The path to the requirements file.
    :return: The cleaned requirements content as a string.
    """

    if not requirements.exists():
        return ''

    try:
        with open(requirements, 'r', encoding='utf-8') as handle:
            lines = handle.readlines()

        cleaned = [
            line for line in lines
            if not line.strip().startswith('-r ')
        ]

        return ''.join(cleaned)
    except Exception:
        return ''

discover_sources

A method that discovers all available dependency sources.

This method finds both requirements files and pyproject.toml sources and returns them sorted by priority.

Returns:

Source code in dev_tool/services/python/package/dependencies.py
def discover_sources(self) -> list[DependencySource]:
    """
    A method that discovers all available dependency sources.

    This method finds both requirements files and pyproject.toml sources
    and returns them sorted by priority.

    :return: A list of all discovered dependency sources.
    """

    sources = []

    requirements = self._discover_requirements_sources()
    sources.extend(requirements)

    pyproject = self._discover_pyproject_sources()
    sources.extend(pyproject)

    return sorted(sources, key=lambda x: x.priority)

get_available_sources

A method that gets formatted descriptions of available dependency sources.

This method discovers sources and returns formatted descriptions organized by source type.

Returns:

  • dict[str, list[str]]

    A dictionary mapping source types to formatted source descriptions.

Source code in dev_tool/services/python/package/dependencies.py
def get_available_sources(self) -> dict[str, list[str]]:
    """
    A method that gets formatted descriptions of available dependency sources.

    This method discovers sources and returns formatted descriptions
    organized by source type.

    :return: A dictionary mapping source types to formatted source descriptions.
    """

    sources = self.discover_sources()

    result = {
        'requirements': [],
        'pyproject': []
    }

    for source in sources:
        if source.available:
            formatted = source.formatted()

            if source.source == SourceType.REQUIREMENTS:
                result['requirements'].append(formatted)
            else:
                result['pyproject'].append(formatted)

    return result

get_fallback_strategy

A method that gets the fallback installation strategy.

This method returns the opposite type of sources for fallback installation.

Parameters:

Returns:

Source code in dev_tool/services/python/package/dependencies.py
def get_fallback_strategy(self, sources: list[DependencySource]) -> list[DependencySource]:
    """
    A method that gets the fallback installation strategy.

    This method returns the opposite type of sources for fallback installation.

    :param sources: The primary sources that failed.
    :return: The fallback sources to try.
    """

    primary_types = {source.source for source in sources}

    if SourceType.PYPROJECT in primary_types:
        return [
            source
            for source in self.discover_sources()
            if source.source == SourceType.REQUIREMENTS
        ]

    return [
        source
        for source in self.discover_sources()
        if source.source == SourceType.PYPROJECT
    ]

get_strategy

A method that gets the installation strategy for dependencies.

This method returns either all sources for automatic detection or filters sources based on requested dependency types.

Parameters:

  • requested (list[str] | None, default: None ) –

    Optional list of specific dependency types to install.

Returns:

Source code in dev_tool/services/python/package/dependencies.py
def get_strategy(self, requested: list[str] | None = None) -> list[DependencySource]:
    """
    A method that gets the installation strategy for dependencies.

    This method returns either all sources for automatic detection
    or filters sources based on requested dependency types.

    :param requested: Optional list of specific dependency types to install.
    :return: The dependency sources to install based on the strategy.
    """

    sources = self.discover_sources()

    if not sources:
        return []

    if requested is None:
        return self._get_automatic_strategy(sources)

    return [
        source
        for source in sources
        if source.name in requested
    ]

DependencySource dataclass

A class for representing a source of dependencies.

This class holds information about where dependencies can be installed from, either requirements files or pyproject.toml extras.

name instance-attribute

source instance-attribute

path = None class-attribute instance-attribute

extra = None class-attribute instance-attribute

priority = 0 class-attribute instance-attribute

available property

A method that checks if this dependency source is available.

This method determines if the source exists and contains content.

Returns:

  • bool

    True if the source is available, False otherwise.

formatted

A method that returns a formatted string representation of the source.

This method creates a human-readable description of the dependency source.

Returns:

  • str

    A formatted string describing the dependency source.

Source code in dev_tool/services/python/package/dependencies.py
def formatted(self) -> str:
    """
    A method that returns a formatted string representation of the source.

    This method creates a human-readable description of the dependency source.

    :return: A formatted string describing the dependency source.
    """

    if self.source == SourceType.REQUIREMENTS:
        if self.path is None:
            return self.name

        return f'{self.name} ({self.path.name})'

    extra = f' [extra: {self.extra}]' if self.extra else ' [base]'
    return f'{self.name}{extra}'

PackageManagerFactory

A factory class for creating package manager instances.

This class provides methods for creating platform-specific package managers.

create_package_manager staticmethod

A method that creates platform-specific package manager instances.

Returns:

Source code in dev_tool/services/python/package/factory.py
@staticmethod
def create_package_manager() -> tuple[PackageManager, PackageManager]:
    """
    A method that creates platform-specific package manager instances.

    :return: A tuple containing the primary and fallback package manager instances.
    """

    if sys.platform == OperatingSystem.WINDOWS:
        return WindowsUvPackageManager(), WindowsPipPackageManager()

    return UnixUvPackageManager(), UnixPipPackageManager()

PackageManager

Bases: Protocol

A protocol for package managers.

This class defines the interface for package management operations.

is_available

A method that checks if the package manager is available on the system.

Returns:

  • bool

    True if the package manager is available, False otherwise.

Source code in dev_tool/services/python/package/manager.py
def is_available(self) -> bool:
    """
    A method that checks if the package manager is available on the system.

    :return: True if the package manager is available, False otherwise.
    """

    ...

install_package

A method that installs a package using the default package manager.

Source code in dev_tool/services/python/package/manager.py
def install_package(self, package: str) -> bool:
    """A method that installs a package using the default package manager."""

    ...

install_package_manager

A method that installs the package manager if it is not already installed.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/manager.py
def install_package_manager(self) -> bool:
    """
    A method that installs the package manager if it is not already installed.

    :return: True if the installation was successful, False otherwise.
    """

    ...

create_virtual_environment

A method that creates a virtual environment.

Returns:

  • bool

    True if the creation was successful, False otherwise.

Source code in dev_tool/services/python/package/manager.py
def create_virtual_environment(self) -> bool:
    """
    A method that creates a virtual environment.

    :return: True if the creation was successful, False otherwise.
    """

    ...

install_from_requirements

A method that installs dependencies from a requirements file.

Parameters:

  • requirements (Path) –

    The path to the requirements file.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/manager.py
def install_from_requirements(self, requirements: Path) -> bool:
    """
    A method that installs dependencies from a requirements file.

    :param requirements: The path to the requirements file.
    :return: True if the installation was successful, False otherwise.
    """

    ...

install_from_pyproject

A method that installs dependencies from pyproject.toml.

Parameters:

  • extras (list[str] | None, default: None ) –

    Optional list of extra dependency groups to install.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/manager.py
def install_from_pyproject(self, extras: list[str] | None = None) -> bool:
    """
    A method that installs dependencies from pyproject.toml.

    :param extras: Optional list of extra dependency groups to install.
    :return: True if the installation was successful, False otherwise.
    """

    ...

uninstall_package

A method that uninstalls a package.

Parameters:

  • package (str) –

    The name of the package to uninstall.

Returns:

  • bool

    True if the uninstallation was successful, False otherwise.

Source code in dev_tool/services/python/package/manager.py
def uninstall_package(self, package: str) -> bool:
    """
    A method that uninstalls a package.

    :param package: The name of the package to uninstall.
    :return: True if the uninstallation was successful, False otherwise.
    """

    ...

upgrade_package_manager

A method that upgrades the package manager to the latest version.

Returns:

  • bool

    True if the upgrade was successful, False otherwise.

Source code in dev_tool/services/python/package/manager.py
def upgrade_package_manager(self) -> bool:
    """
    A method that upgrades the package manager to the latest version.

    :return: True if the upgrade was successful, False otherwise.
    """

    ...

list_installed_packages

A method that lists all installed packages.

Returns:

  • list[str]

    A list of installed package names.

Source code in dev_tool/services/python/package/manager.py
def list_installed_packages(self) -> list[str]:
    """
    A method that lists all installed packages.

    :return: A list of installed package names.
    """

    ...

UnixPipPackageManager

Bases: PackageManager

A Unix-specific implementation of the Pip package manager.

This class provides methods for managing Python packages using pip on Unix-like systems.

is_available

A method that checks if pip3 is available on the system.

Returns:

  • bool

    True if pip3 is available, False otherwise.

Source code in dev_tool/services/python/package/pip.py
def is_available(self) -> bool:
    """
    A method that checks if pip3 is available on the system.

    :return: True if pip3 is available, False otherwise.
    """

    command = ['which', 'pip3']

    result = subprocess.run(
        command,
        capture_output=True,
        check=False
    )

    return result.returncode == 0

install_package

A method that installs a package using pip.

Parameters:

  • package (str) –

    The name of the package to install.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/pip.py
def install_package(self, package: str) -> bool:
    """
    A method that installs a package using pip.

    :param package: The name of the package to install.
    :return: True if the installation was successful, False otherwise.
    """

    message = f'Installing {package}...'
    emit_normal(message)

    log.debug(message)

    command = [
        VENV_PYTHON,
        '-m',
        'pip',
        'install',
        package
    ]

    result = subprocess.run(command, check=False)
    return result.returncode == 0

install_package_manager

A method that ensures pip3 is installed.

Returns:

  • bool

    True if pip3 is available, False otherwise.

Source code in dev_tool/services/python/package/pip.py
def install_package_manager(self) -> bool:
    """
    A method that ensures pip3 is installed.

    :return: True if pip3 is available, False otherwise.
    """

    return self.is_available()

create_virtual_environment

A method that creates a virtual environment using venv.

Returns:

  • bool

    True if the creation was successful, False otherwise.

Source code in dev_tool/services/python/package/pip.py
def create_virtual_environment(self) -> bool:
    """
    A method that creates a virtual environment using venv.

    :return: True if the creation was successful, False otherwise.
    """

    message = 'Setting up virtual environment using venv...'
    emit_normal(message)

    log.debug(message)

    command = [
        'python3',
        '-m',
        'venv',
        VENV
    ]

    result = subprocess.run(command, check=False)
    return result.returncode == 0

install_from_requirements

A method that installs dependencies from a requirements file using pip.

Parameters:

  • requirements (Path) –

    The path to the requirements file.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/pip.py
def install_from_requirements(self, requirements: Path) -> bool:
    """
    A method that installs dependencies from a requirements file using pip.

    :param requirements: The path to the requirements file.
    :return: True if the installation was successful, False otherwise.
    """

    message = f'Installing dependencies from {requirements.name}...'
    emit_normal(message)

    log.debug(message)

    command = [
        VENV_PYTHON,
        '-m',
        'pip',
        'install',
        '-U',
        '-r',
        requirements
    ]

    result = subprocess.run(command, check=False)
    return result.returncode == 0

install_from_pyproject

A method that installs dependencies from pyproject.toml using pip.

Parameters:

  • extras (list[str] | None, default: None ) –

    Optional list of extra dependency groups to install.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/pip.py
def install_from_pyproject(self, extras: list[str] | None = None) -> bool:
    """
    A method that installs dependencies from pyproject.toml using pip.

    :param extras: Optional list of extra dependency groups to install.
    :return: True if the installation was successful, False otherwise.
    """

    extras = extras or []

    if extras:
        string = ','.join(extras)
        target = f'.[{string}]'

        message = f'Installing project dependencies with extras: {string}...'
        emit_normal(message)

        log.debug(message)
    else:
        target = '.'

        message = 'Installing project dependencies...'
        emit_normal(message)

        log.debug(message)

    command = [
        VENV_PYTHON,
        '-m',
        'pip',
        'install',
        '-e',
        target
    ]

    result = subprocess.run(command, check=False)
    return result.returncode == 0

uninstall_package

A method that uninstalls a package using pip.

Parameters:

  • package (str) –

    The name of the package to uninstall.

Returns:

  • bool

    True if the uninstallation was successful, False otherwise.

Source code in dev_tool/services/python/package/pip.py
def uninstall_package(self, package: str) -> bool:
    """
    A method that uninstalls a package using pip.

    :param package: The name of the package to uninstall.
    :return: True if the uninstallation was successful, False otherwise.
    """

    message = f'Uninstalling {package}...'
    emit_normal(message)

    log.debug(message)

    command = [
        VENV_PYTHON,
        '-m',
        'pip',
        'uninstall',
        '-y',
        package
    ]

    result = subprocess.run(command, check=False)
    return result.returncode == 0

upgrade_package_manager

A method that upgrades pip to the latest version.

Returns:

  • bool

    True if the upgrade was successful, False otherwise.

Source code in dev_tool/services/python/package/pip.py
def upgrade_package_manager(self) -> bool:
    """
    A method that upgrades pip to the latest version.

    :return: True if the upgrade was successful, False otherwise.
    """

    message = 'Upgrading pip...'
    emit_normal(message)

    log.debug(message)

    command = [
        VENV_PYTHON,
        '-m',
        'pip',
        'install',
        '--upgrade',
        'pip'
    ]

    result = subprocess.run(command, check=False)
    return result.returncode == 0

list_installed_packages

A method that lists all installed packages using pip.

Returns:

  • list[str]

    A list of installed package names.

Source code in dev_tool/services/python/package/pip.py
def list_installed_packages(self) -> list[str]:
    """
    A method that lists all installed packages using pip.

    :return: A list of installed package names.
    """

    command = [VENV_PYTHON, '-m', 'pip', 'freeze']

    result = subprocess.run(
        command,
        capture_output=True,
        text=True,
        check=False
    )

    if result.returncode != 0:
        return []

    return [
        package.split('==')[0]
        for package in result.stdout.splitlines()
    ]

WindowsPipPackageManager

Bases: PackageManager

A Windows-specific implementation of the Pip package manager.

This class provides methods for managing Python packages using pip on Windows.

is_available

A method that checks if pip is available on the system.

Returns:

  • bool

    True if pip is available, False otherwise.

Source code in dev_tool/services/python/package/pip.py
def is_available(self) -> bool:
    """
    A method that checks if pip is available on the system.

    :return: True if pip is available, False otherwise.
    """

    command = ['where', 'pip']

    result = subprocess.run(
        command,
        capture_output=True,
        check=False
    )

    return result.returncode == 0

install_package

A method that installs a package using pip.

Parameters:

  • package (str) –

    The name of the package to install.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/pip.py
def install_package(self, package: str) -> bool:
    """
    A method that installs a package using pip.

    :param package: The name of the package to install.
    :return: True if the installation was successful, False otherwise.
    """

    message = f'Installing {package}...'
    emit_normal(message)

    log.debug(message)

    command = [
        VENV_PYTHON,
        '-m',
        'pip',
        'install',
        package
    ]

    result = subprocess.run(command, check=False)
    return result.returncode == 0

install_package_manager

A method that ensures pip is installed.

Returns:

  • bool

    True if pip is available, False otherwise.

Source code in dev_tool/services/python/package/pip.py
def install_package_manager(self) -> bool:
    """
    A method that ensures pip is installed.

    :return: True if pip is available, False otherwise.
    """

    return self.is_available()

create_virtual_environment

A method that creates a virtual environment using venv.

Returns:

  • bool

    True if the creation was successful, False otherwise.

Source code in dev_tool/services/python/package/pip.py
def create_virtual_environment(self) -> bool:
    """
    A method that creates a virtual environment using venv.

    :return: True if the creation was successful, False otherwise.
    """

    message = 'Setting up virtual environment using venv...'
    emit_normal(message)

    log.debug(message)

    python = Path('python')

    command = [
        python,
        '-m',
        'venv',
        VENV
    ]

    result = subprocess.run(command, check=False, shell=True)
    return result.returncode == 0

install_from_requirements

A method that installs dependencies from a requirements file using pip.

Parameters:

  • requirements (Path) –

    The path to the requirements file.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/pip.py
def install_from_requirements(self, requirements: Path) -> bool:
    """
    A method that installs dependencies from a requirements file using pip.

    :param requirements: The path to the requirements file.
    :return: True if the installation was successful, False otherwise.
    """

    message = f'Installing dependencies from {requirements.name}...'
    emit_normal(message)

    log.debug(message)

    command = [
        VENV_PYTHON,
        '-m',
        'pip',
        'install',
        '-U',
        '-r',
        requirements
    ]

    result = subprocess.run(command, check=False)
    return result.returncode == 0

install_from_pyproject

A method that installs dependencies from pyproject.toml using pip.

Parameters:

  • extras (list[str] | None, default: None ) –

    Optional list of extra dependency groups to install.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/pip.py
def install_from_pyproject(self, extras: list[str] | None = None) -> bool:
    """
    A method that installs dependencies from pyproject.toml using pip.

    :param extras: Optional list of extra dependency groups to install.
    :return: True if the installation was successful, False otherwise.
    """

    if not VENV_PYTHON.exists():
        message = f'Python executable not found at {VENV_PYTHON}'
        emit_warning(message)

        log.debug(message)
        return False

    if not self._validate_pyproject():
        message = 'pyproject.toml is not configured for installation'
        emit_warning(message)

        log.debug(message)
        return False

    extras = extras or []

    if extras:
        string = ','.join(extras)
        target = f'.[{string}]'

        message = f'Installing project dependencies with extras: {string}...'
        emit_normal(message)

        log.debug(message)
    else:
        target = '.'

        message = 'Installing project dependencies...'
        emit_normal(message)

        log.debug(message)

    command = [
        VENV_PYTHON,
        '-m',
        'pip',
        'install',
        '-e',
        target
    ]

    result = subprocess.run(command, check=False)
    return result.returncode == 0

uninstall_package

A method that uninstalls a package using pip.

Parameters:

  • package (str) –

    The name of the package to uninstall.

Returns:

  • bool

    True if the uninstallation was successful, False otherwise.

Source code in dev_tool/services/python/package/pip.py
def uninstall_package(self, package: str) -> bool:
    """
    A method that uninstalls a package using pip.

    :param package: The name of the package to uninstall.
    :return: True if the uninstallation was successful, False otherwise.
    """

    message = f'Uninstalling {package}...'
    emit_normal(message)

    log.debug(message)

    command = [
        VENV_PYTHON,
        '-m',
        'pip',
        'uninstall',
        '-y',
        package
    ]

    result = subprocess.run(command, check=False)
    return result.returncode == 0

upgrade_package_manager

A method that upgrades pip to the latest version.

Returns:

  • bool

    True if the upgrade was successful, False otherwise.

Source code in dev_tool/services/python/package/pip.py
def upgrade_package_manager(self) -> bool:
    """
    A method that upgrades pip to the latest version.

    :return: True if the upgrade was successful, False otherwise.
    """

    message = 'Upgrading pip...'
    emit_normal(message)

    log.debug(message)

    command = [
        VENV_PYTHON,
        '-m',
        'pip',
        'install',
        '--upgrade',
        'pip'
    ]

    result = subprocess.run(command, check=False)
    return result.returncode == 0

list_installed_packages

A method that lists all installed packages using pip.

Returns:

  • list[str]

    A list of installed package names.

Source code in dev_tool/services/python/package/pip.py
def list_installed_packages(self) -> list[str]:
    """
    A method that lists all installed packages using pip.

    :return: A list of installed package names.
    """

    command = [VENV_PYTHON, '-m', 'pip', 'freeze']

    result = subprocess.run(
        command,
        capture_output=True,
        text=True,
        check=False
    )

    if result.returncode != 0:
        return []

    return [
        package.split('==')[0]
        for package in result.stdout.splitlines()
    ]

UnixUvPackageManager

Bases: PackageManager

A Unix-specific implementation of the uv package manager.

This class provides methods for managing Python packages using uv on Unix-like systems.

is_available

A method that checks if uv is available on the system.

Returns:

  • bool

    True if uv is available, False otherwise.

Source code in dev_tool/services/python/package/uv.py
def is_available(self) -> bool:
    """
    A method that checks if uv is available on the system.

    :return: True if uv is available, False otherwise.
    """

    command = ['which', 'uv']

    result = subprocess.run(
        command,
        capture_output=True,
        check=False
    )

    return result.returncode == 0

install_package

A method that installs a package using uv.

Parameters:

  • package (str) –

    The name of the package to install.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/uv.py
def install_package(self, package: str) -> bool:
    """
    A method that installs a package using uv.

    :param package: The name of the package to install.
    :return: True if the installation was successful, False otherwise.
    """

    message = f'Installing {package}...'
    emit_normal(message)

    log.debug(message)

    if not VENV_PYTHON.exists():
        message = f'Python executable not found at {VENV_PYTHON}'
        emit_warning(message)

        log.debug(message)

        return False

    command = [
        'uv',
        'pip',
        'install',
        '--python',
        str(VENV_PYTHON),
        package
    ]

    result = subprocess.run(command, check=False)
    return result.returncode == 0

install_package_manager

A method that installs uv if it is not already installed.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/uv.py
def install_package_manager(self) -> bool:
    """
    A method that installs uv if it is not already installed.

    :return: True if the installation was successful, False otherwise.
    """

    if self.is_available():
        message = 'uv is already installed.'
        log.debug(message)

        return True

    message = 'Installing uv package manager...'
    emit_normal(message)

    log.debug(message)

    command = 'curl -sSf https://astral.sh/uv/install.sh | sh'

    result = subprocess.run(command, check=False, shell=True)

    if result.returncode == 0:
        local = str(Path.home() / '.local' / 'bin')
        path = os.environ['PATH']

        os.environ['PATH'] = f'{local}:{path}'

        message = 'Verifying uv installation...'
        emit_normal(message)

        log.debug(message)

        command = ['uv', '--version']
        is_installed = subprocess.run(command, check=False)
        return is_installed.returncode == 0

    return False

create_virtual_environment

A method that creates a virtual environment using uv.

Returns:

  • bool

    True if the creation was successful, False otherwise.

Source code in dev_tool/services/python/package/uv.py
def create_virtual_environment(self) -> bool:
    """
    A method that creates a virtual environment using uv.

    :return: True if the creation was successful, False otherwise.
    """

    message = 'Setting up virtual environment using uv...'
    emit_normal(message)

    log.debug(message)

    command = ['uv', 'venv', '--seed', str(VENV)]
    result = subprocess.run(command, check=False)
    return result.returncode == 0

install_from_pyproject

A method that installs dependencies from pyproject.toml using uv.

Parameters:

  • extras (list[str] | None, default: None ) –

    Optional list of extra dependency groups to install.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/uv.py
def install_from_pyproject(self, extras: list[str] | None = None) -> bool:
    """
    A method that installs dependencies from pyproject.toml using uv.

    :param extras: Optional list of extra dependency groups to install.
    :return: True if the installation was successful, False otherwise.
    """

    if not VENV_PYTHON.exists():
        message = f'Python executable not found at {VENV_PYTHON}'
        emit_warning(message)

        log.debug(message)
        return False

    extras = extras or []

    if extras:
        extras_string = ','.join(extras)
        target = f'.[{extras_string}]'

        message = f'Installing project dependencies with extras: {extras_string}...'
        emit_normal(message)

        log.debug(message)
    else:
        target = '.'

        message = 'Installing project dependencies...'
        emit_normal(message)

        log.debug(message)

    command = [
        'uv',
        'pip',
        'install',
        '--python',
        str(VENV_PYTHON),
        '-e',
        target
    ]

    result = subprocess.run(command, check=False)
    return result.returncode == 0

install_from_requirements

A method that installs dependencies from a requirements file using uv.

Parameters:

  • requirements (Path) –

    The path to the requirements file.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/uv.py
def install_from_requirements(self, requirements: Path) -> bool:
    """
    A method that installs dependencies from a requirements file using uv.

    :param requirements: The path to the requirements file.
    :return: True if the installation was successful, False otherwise.
    """

    message = f'Installing dependencies from {requirements.name}...'
    emit_normal(message)

    log.debug(message)

    if not VENV_PYTHON.exists():
        message = f'Python executable not found at {VENV_PYTHON}'
        emit_warning(message)

        log.debug(message)

        return False

    command = [
        'uv',
        'pip',
        'install',
        '--python',
        str(VENV_PYTHON),
        '-r',
        str(requirements)
    ]

    result = subprocess.run(command, check=False)
    return result.returncode == 0

uninstall_package

A method that uninstalls a package using uv.

Parameters:

  • package (str) –

    The name of the package to uninstall.

Returns:

  • bool

    True if the uninstallation was successful, False otherwise.

Source code in dev_tool/services/python/package/uv.py
def uninstall_package(self, package: str) -> bool:
    """
    A method that uninstalls a package using uv.

    :param package: The name of the package to uninstall.
    :return: True if the uninstallation was successful, False otherwise.
    """

    message = f'Uninstalling {package}...'
    emit_normal(message)

    log.debug(message)

    if not VENV_PYTHON.exists():
        message = f'Python executable not found at {VENV_PYTHON}'
        emit_warning(message)

        log.debug(message)

        return False

    command = [
        'uv',
        'pip',
        'uninstall',
        '--python',
        str(VENV_PYTHON),
        package
    ]

    result = subprocess.run(command, check=False)
    return result.returncode == 0

upgrade_package_manager

A method that upgrades the uv package manager.

Returns:

  • bool

    True if the upgrade was successful, False otherwise.

Source code in dev_tool/services/python/package/uv.py
def upgrade_package_manager(self) -> bool:
    """
    A method that upgrades the uv package manager.

    :return: True if the upgrade was successful, False otherwise.
    """

    message = 'Upgrading uv...'
    emit_normal(message)

    log.debug(message)

    command = 'curl -sSf https://astral.sh/uv/install.sh | sh'

    result = subprocess.run(command, check=False, shell=True)
    return result.returncode == 0

list_installed_packages

A method that lists all installed packages using uv.

Returns:

  • list[str]

    A list of installed package names.

Source code in dev_tool/services/python/package/uv.py
def list_installed_packages(self) -> list[str]:
    """
    A method that lists all installed packages using uv.

    :return: A list of installed package names.
    """

    if not VENV_PYTHON.exists():
        message = f'Python executable not found at {VENV_PYTHON}'
        emit_warning(message)

        log.debug(message)

        return []

    command = [
        'uv',
        'pip',
        'freeze',
        '--python',
        str(VENV_PYTHON)
    ]

    result = subprocess.run(
        command,
        capture_output=True,
        check=False,
        text=True
    )

    if result.returncode != 0:
        return []

    return [
        package.split('==')[0]
        for package in result.stdout.splitlines()
    ]

WindowsUvPackageManager

Bases: PackageManager

A Windows-specific implementation of the uv package manager.

This class provides methods for managing Python packages using uv on Windows.

create_virtual_environment

A method that creates a virtual environment using uv.

Returns:

  • bool

    True if the creation was successful, False otherwise.

Source code in dev_tool/services/python/package/uv.py
def create_virtual_environment(self) -> bool:
    """
    A method that creates a virtual environment using uv.

    :return: True if the creation was successful, False otherwise.
    """

    message = 'Setting up virtual environment using uv...'
    emit_normal(message)

    log.debug(message)

    command = ['uv', 'venv', '--seed', str(VENV)]
    result = subprocess.run(command, check=False, shell=True)
    return result.returncode == 0

install_from_pyproject

A method that installs dependencies from pyproject.toml using uv.

Parameters:

  • extras (list[str] | None, default: None ) –

    Optional list of extra dependency groups to install.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/uv.py
def install_from_pyproject(self, extras: list[str] | None = None) -> bool:
    """
    A method that installs dependencies from pyproject.toml using uv.

    :param extras: Optional list of extra dependency groups to install.
    :return: True if the installation was successful, False otherwise.
    """

    if not VENV_PYTHON.exists():
        message = f'Python executable not found at {VENV_PYTHON}'
        emit_warning(message)

        log.debug(message)
        return False

    if not self._validate_pyproject():
        message = 'pyproject.toml is not configured for installation'
        emit_warning(message)

        log.debug(message)
        return False

    extras = extras or []

    if extras:
        string = ','.join(extras)
        target = f'.[{string}]'

        message = f'Installing project dependencies with extras: {string}...'
        emit_normal(message)

        log.debug(message)
    else:
        target = '.'

        message = 'Installing project dependencies...'
        emit_normal(message)

        log.debug(message)

    command = [
        'uv',
        'pip',
        'install',
        '--python',
        str(VENV_PYTHON),
        '-e',
        target
    ]

    result = subprocess.run(command, check=False, shell=True)
    return result.returncode == 0

install_from_requirements

A method that installs dependencies from a requirements file using uv.

Parameters:

  • requirements (Path) –

    The path to the requirements file.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/uv.py
def install_from_requirements(self, requirements: Path) -> bool:
    """
    A method that installs dependencies from a requirements file using uv.

    :param requirements: The path to the requirements file.
    :return: True if the installation was successful, False otherwise.
    """

    message = f'Installing dependencies from {requirements.name}...'
    emit_normal(message)

    log.debug(message)

    if not VENV_PYTHON.exists():
        message = f'Python executable not found at {VENV_PYTHON}'
        emit_warning(message)

        log.debug(message)

        return False

    command = [
        'uv',
        'pip',
        'install',
        '--python',
        str(VENV_PYTHON),
        '-r', str(requirements)
    ]

    result = subprocess.run(command, check=False, shell=True)
    return result.returncode == 0

install_package

A method that installs a package using uv.

Parameters:

  • package (str) –

    The name of the package to install.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/uv.py
def install_package(self, package: str) -> bool:
    """
    A method that installs a package using uv.

    :param package: The name of the package to install.
    :return: True if the installation was successful, False otherwise.
    """

    message = f'Installing {package}...'
    emit_normal(message)

    log.debug(message)

    if not VENV_PYTHON.exists():
        message = f'Python executable not found at {VENV_PYTHON}'
        emit_warning(message)

        log.debug(message)

        return False

    command = [
        'uv',
        'pip',
        'install',
        '--python',
        str(VENV_PYTHON),
        package
    ]

    result = subprocess.run(command, check=False, shell=True)
    return result.returncode == 0

install_package_manager

A method that installs uv if it is not already installed.

Returns:

  • bool

    True if the installation was successful, False otherwise.

Source code in dev_tool/services/python/package/uv.py
def install_package_manager(self) -> bool:
    """
    A method that installs uv if it is not already installed.

    :return: True if the installation was successful, False otherwise.
    """

    if self.is_available():
        message = 'uv is already installed.'
        log.debug(message)

        return True

    message ='Installing uv package manager...'
    emit_normal(message)

    log.debug(message)

    if self._is_special_username():
        destination = rf'{SYSTEM_DRIVE}\uv'
        os.environ['UV_INSTALL_DIR'] = destination

        message = f'Username contains special characters, installing to {destination}'
        emit_warning(message)

        log.debug(message)

    command = [
        'powershell',
        '-ExecutionPolicy',
        'ByPass',
        '-c',
        'irm https://astral.sh/uv/install.ps1 | iex'
    ]

    result = subprocess.run(command, check=False, shell=True)

    if result.returncode == 0:
        if self._is_special_username():
            destination = rf'{SYSTEM_DRIVE}\uv'
        else:
            destination = str(Path.home() / '.local' / 'bin')

        if self._is_special_username() or Path(destination).exists():
            path = os.environ['PATH']

            if destination not in path:
                os.environ['PATH'] = f'{destination};{path}'

        EnvironmentVariables.refresh_environment()

        message = 'Verifying uv installation...'
        emit_normal(message)

        log.debug(message)

        command = ['uv', '--version']
        verification = subprocess.run(command, check=False, shell=True)
        return verification.returncode == 0

    return False

is_available

A method that checks if uv is available on the system.

Returns:

  • bool

    True if uv is available, False otherwise.

Source code in dev_tool/services/python/package/uv.py
def is_available(self) -> bool:
    """
    A method that checks if uv is available on the system.

    :return: True if uv is available, False otherwise.
    """

    command = ['where', 'uv']

    result = subprocess.run(
        command,
        capture_output=True,
        check=False,
        shell=True
    )

    return result.returncode == 0

list_installed_packages

A method that lists all installed packages using uv.

Returns:

  • list[str]

    A list of installed package names.

Source code in dev_tool/services/python/package/uv.py
def list_installed_packages(self) -> list[str]:
    """
    A method that lists all installed packages using uv.

    :return: A list of installed package names.
    """

    if not VENV_PYTHON.exists():
        message = f'Python executable not found at {VENV_PYTHON}'
        emit_warning(message)

        log.debug(message)

        return []

    command = [
        'uv',
        'pip',
        'freeze',
        '--python',
        str(VENV_PYTHON)
    ]

    result = subprocess.run(
        command,
        capture_output=True,
        check=False,
        shell=True,
        text=True
    )

    if result.returncode != 0:
        return []

    return [
        package.split('==')[0]
        for package in result.stdout.splitlines()
    ]

uninstall_package

A method that uninstalls a package using uv.

Parameters:

  • package (str) –

    The name of the package to uninstall.

Returns:

  • bool

    True if the uninstallation was successful, False otherwise.

Source code in dev_tool/services/python/package/uv.py
def uninstall_package(self, package: str) -> bool:
    """
    A method that uninstalls a package using uv.

    :param package: The name of the package to uninstall.
    :return: True if the uninstallation was successful, False otherwise.
    """

    message = f'Uninstalling {package}...'
    emit_normal(message)

    log.debug(message)

    if not VENV_PYTHON.exists():
        message = f'Python executable not found at {VENV_PYTHON}'
        emit_warning(message)

        log.debug(message)

        return False

    command = [
        'uv',
        'pip',
        'uninstall',
        '--python',
        str(VENV_PYTHON),
        package
    ]

    result = subprocess.run(command, check=False, shell=True)
    return result.returncode == 0

upgrade_package_manager

Source code in dev_tool/services/python/package/uv.py
def upgrade_package_manager(self) -> bool:
    message = 'Checking for uv updates...'
    emit_normal(message)

    log.debug(message)

    command = ['uv', 'self', 'update']
    result = subprocess.run(command, capture_output=True, text=True, check=False)

    if result.returncode == 0:
        output = (result.stdout + result.stderr).lower()

        if 'you\'re on the latest version' in output or 'already up-to-date' in output:
            message = 'uv is already up-to-date'
            log.debug(message)
        else:
            message = 'uv updated successfully'
            emit_normal(message)

            log.debug(message)

        EnvironmentVariables.refresh_environment()
        return True

    return False

PythonService

Bases: BaseService

A service class for Python-related operations.

This class provides methods for managing Python virtual environments and dependencies.

The constructor for the PythonService class.

It initializes package managers for dependency management.

Source code in dev_tool/services/python/service.py
def __init__(self) -> None:
    """
    The constructor for the PythonService class.

    It initializes package managers for dependency management.
    """

    super().__init__()

    self.container_manager = ContainerPackageManager()
    self.resolver = DependencyResolver()
    self.manager, self.fallback = PackageManagerFactory.create_package_manager()

    if sys.platform == OperatingSystem.WINDOWS:
        EnvironmentVariables.refresh_environment()

container_manager = ContainerPackageManager() instance-attribute

resolver = DependencyResolver() instance-attribute

clean_virtual_environment

A method that removes an existing virtual environment.

Source code in dev_tool/services/python/service.py
def clean_virtual_environment(self) -> None:
    """A method that removes an existing virtual environment."""

    if self._is_containerized():
        message = 'Skipping virtual environment cleanup in containerized mode.'
        self.notification.normal_text(message)

        log.debug(message)
        return

    message = 'Cleaning virtual environment...'
    self.notification.normal_text(message)

    if VENV.exists():
        self._remove_directory(VENV)

        message = f'Removed virtual environment at {VENV}'
        self.notification.normal_text(message)
    else:
        message = f'No virtual environment found at {VENV}'
        self.notification.warning_banner(message)

        log.debug(message)

create_virtual_environment

A method that creates a Python virtual environment.

Source code in dev_tool/services/python/service.py
def create_virtual_environment(self) -> None:
    """A method that creates a Python virtual environment."""

    if self._is_containerized():
        message = 'Skipping virtual environment creation in containerized mode.'
        self.notification.normal_text(message)

        log.debug(message)
        return

    message = 'Setting up virtual environment...'
    self.notification.normal_text(message)

    self.install_package_manager()

    if not self.manager.create_virtual_environment():
        message = 'Failed to create virtual environment with preferred manager, falling back...'
        self.notification.warning_text(message)

        log.debug(message)

        if not self.fallback.create_virtual_environment():
            message = 'Failed to create virtual environment with any package manager'
            log.debug(message)

            raise VirtualEnvironmentError(message)

get_available_dependencies

A method that lists all available dependency sources.

This method discovers and returns information about all available dependency sources including requirements files and pyproject.toml extras.

Returns:

  • dict[str, list[str]]

    A dictionary mapping source types to available sources.

Source code in dev_tool/services/python/service.py
def get_available_dependencies(self) -> dict[str, list[str]]:
    """
    A method that lists all available dependency sources.

    This method discovers and returns information about all available
    dependency sources including requirements files and pyproject.toml extras.

    :return: A dictionary mapping source types to available sources.
    """

    sources = self.resolver.discover_sources()
    result: dict[str, list[str]] = {}

    for source in sources:
        source_type = source.source.value

        if source_type not in result:
            result[source_type] = []

        result[source_type].append(source.name)

    return result

install_dependencies

A method that installs dependencies based on selected sources.

Parameters:

  • types (list[str] | None, default: None ) –

    Optional list of dependency types to install.

Source code in dev_tool/services/python/service.py
@is_virtual_environment
def install_dependencies(self, types: list[str] | None = None) -> None:
    """
    A method that installs dependencies based on selected sources.

    :param types: Optional list of dependency types to install.
    """

    sources = self.resolver.discover_sources()

    if not sources:
        message = 'No dependency sources found'
        self.notification.warning_text(message)

        log.debug(message)
        return

    selected = self._select_sources(sources, types)

    if not selected:
        return

    if self._is_containerized():
        self.container_manager.install_dependencies(selected)
        return

    for source in selected:
        self._install_source(source)

install_package

A method that installs a Python package.

It requires a virtual environment to be active or containerized mode.

Source code in dev_tool/services/python/service.py
@is_virtual_environment
def install_package(self) -> None:
    """
    A method that installs a Python package.

    It requires a virtual environment to be active or containerized mode.
    """

    package = get_user_input('Which package do you want to install?')

    if not package:
        message = 'No package specified. Aborting...'
        self.notification.warning_text(message)

        log.debug(message)
        return

    if self._is_containerized():
        if not self.container_manager.install_package(package):
            message = f'Failed to install package "{package}"'
            log.debug(message)

            raise DependencyInstallationError(message)

        message = f'The {package} package installed successfully.'
        self.notification.normal_text(message)

        log.debug(message)
        return

    self.install_package_manager()

    if not self.manager.install_package(package):
        message = 'Failed to install package with preferred manager, falling back...'
        self.notification.warning_text(message)

        log.debug(message)

        if not self.fallback.install_package(package):
            message = f'Failed to install package "{package}" with any package manager'
            log.debug(message)

            raise DependencyInstallationError(message)

    message = f'The {package} package installed successfully.'
    self.notification.normal_text(message)

    log.debug(message)

install_package_manager

A method that installs the preferred package manager.

It falls back to an alternative if the preferred manager cannot be installed.

Source code in dev_tool/services/python/service.py
def install_package_manager(self) -> bool:
    """
    A method that installs the preferred package manager.

    It falls back to an alternative if the preferred manager cannot be installed.
    """

    if self._is_containerized():
        message = 'Package manager already available in container.'
        self.notification.normal_text(message)

        log.debug(message)
        return True

    if self.manager is None or self.fallback is None:
        message = 'Package managers not initialized'
        self.notification.error_banner(message)

        log.debug(message)
        return False

    if self.manager.is_available():
        message = 'uv is already installed.'
        self.notification.normal_text(message)

        log.debug(message)
        return True

    if not self.manager.install_package_manager():
        message = 'Failed to install preferred package manager, falling back...'
        self.notification.warning_text(message)

        log.debug(message)

        if not self.fallback.install_package_manager():
            message = 'Failed to install any package manager'
            log.debug(message)

            raise PackageManagerError(message)

    return False

setup_venv

A method that sets up a complete virtual environment.

Creates a virtual environment if needed, upgrades the package manager, and installs all dependencies.

Parameters:

  • types (list[str] | None, default: None ) –

    Optional list of dependency types to install.

Source code in dev_tool/services/python/service.py
def setup_venv(self, types: list[str] | None = None) -> None:
    """
    A method that sets up a complete virtual environment.

    Creates a virtual environment if needed, upgrades the package manager,
    and installs all dependencies.

    :param types: Optional list of dependency types to install.
    """

    if self._is_containerized():
        message = 'Skipping virtual environment setup in containerized mode.'
        self.notification.normal_text(message)

        log.debug(message)
        return

    if not VENV.exists():
        self.create_virtual_environment()

    self.upgrade_package_manager()
    self.install_dependencies(types=types)

uninstall_dependencies

A method that uninstalls a Python package.

It requires a virtual environment to be active or containerized mode.

Source code in dev_tool/services/python/service.py
@is_virtual_environment
def uninstall_dependencies(self) -> None:
    """
    A method that uninstalls a Python package.

    It requires a virtual environment to be active or containerized mode.
    """

    package = get_user_input('Which package do you want to uninstall?')

    if not package:
        message = 'No package specified. Aborting...'
        self.notification.warning_text(message)

        log.debug(message)
        return

    if self._is_containerized():
        installed = self.container_manager.list_packages()

        if package.lower() not in installed:
            message = f'The "{package}" package is not installed.'
            self.notification.warning_text(message)

            log.debug(message)
            return

        if not self.container_manager.uninstall_package(package):
            message = f'Failed to uninstall package "{package}"'
            log.debug(message)

            raise PackageUninstallationError(message)

        message = f'The {package} package uninstalled successfully.'
        self.notification.normal_text(message)

        log.debug(message)
        return

    self.install_package_manager()

    installed = self.manager.list_installed_packages()

    if not installed:
        installed = self.fallback.list_installed_packages()

    if package not in installed:
        message = f'The "{package}" package is not installed.'
        self.notification.warning_text(message)

        log.debug(message)
        return

    if not self.manager.uninstall_package(package):
        message = 'Failed to uninstall package with preferred manager, falling back...'
        self.notification.warning_text(message)

        log.debug(message)

        if not self.fallback.uninstall_package(package):
            message = f'Failed to uninstall package "{package}" with any package manager'
            log.debug(message)

            raise PackageUninstallationError(message)

    message = f'The {package} package uninstalled successfully.'
    self.notification.normal_text(message)

    log.debug(message)

upgrade_package_manager

A method that upgrades the package manager to the latest version.

It requires a virtual environment to be active or containerized mode.

Source code in dev_tool/services/python/service.py
@is_virtual_environment
def upgrade_package_manager(self) -> None:
    """
    A method that upgrades the package manager to the latest version.

    It requires a virtual environment to be active or containerized mode.
    """

    if self._is_containerized():
        message = 'Package manager is managed by container image.'
        self.notification.normal_text(message)

        log.debug(message)
        return

    if not self.manager.upgrade_package_manager():
        message = 'Failed to upgrade package manager with preferred manager, falling back...'
        self.notification.warning_text(message)

        log.debug(message)

        if not self.fallback.upgrade_package_manager():
            message = 'Failed to upgrade any package manager'
            log.debug(message)

            raise PackageManagerError(message)