diff --git a/pipenv/environment.py b/pipenv/environment.py index 47cf66313e..077ea4c428 100644 --- a/pipenv/environment.py +++ b/pipenv/environment.py @@ -4,7 +4,6 @@ import importlib import importlib.metadata import importlib.util -import itertools import json import os import site @@ -21,6 +20,7 @@ from pipenv.patched.pip._internal.req.req_install import InstallRequirement from pipenv.patched.pip._vendor.packaging.specifiers import SpecifierSet from pipenv.patched.pip._vendor.packaging.utils import canonicalize_name +from pipenv.patched.pip._vendor.packaging.version import parse as parse_version from pipenv.utils import console from pipenv.utils.fileutils import normalize_path, temp_path from pipenv.utils.funktools import chunked, unnest @@ -557,7 +557,6 @@ def get_package_info( with self.get_finder() as finder: for dist in packages: - typ = "unknown" all_candidates = finder.find_all_candidates(dist.name) if not self.pipfile.get("pre", finder.allow_all_prereleases): # Remove prereleases @@ -575,22 +574,24 @@ def get_package_info( best_candidate_result = candidate_evaluator.compute_best_candidate( all_candidates ) - remote_version = best_candidate_result.best_candidate.version + remote_version = parse_version( + str(best_candidate_result.best_candidate.version) + ) if best_candidate_result.best_candidate.link.is_wheel: - typ = "wheel" + pass else: - typ = "sdist" + pass # This is dirty but makes the rest of the code much cleaner dist.latest_version = remote_version - dist.latest_filetype = typ yield dist + def get_outdated_packages( self, pre: bool = False ) -> list[importlib.metadata.Distribution]: return [ pkg for pkg in self.get_package_info(pre=pre) - if pkg.latest_version._key > pkg.parsed_version._key + if pkg.latest_version > parse_version(pkg.version) ] @classmethod @@ -619,7 +620,9 @@ def _get_requirements_for_package(cls, node, key_tree, parent=None, chain=None): def get_package_requirements(self, pkg=None): from itertools import chain - from pipenv.vendor.pipdeptree._models import PackageDAG + from pipenv.patched.pip._vendor.packaging.markers import UndefinedEnvironmentName + from pipenv.vendor.pipdeptree._models.dag import PackageDAG + from pipenv.vendor.pipdeptree._models.package import InvalidRequirementError flatten = chain.from_iterable @@ -627,7 +630,20 @@ def get_package_requirements(self, pkg=None): if pkg: packages = [p for p in packages if p.name == pkg] - tree = PackageDAG.from_pkgs(packages).sort() + try: + tree = PackageDAG.from_pkgs(packages) + except InvalidRequirementError as e: + console.print(f"Invalid requirement: {e}", style="yellow") + tree = PackageDAG({}) + except UndefinedEnvironmentName: + # Handle the case when 'extra' environment variable is not defined + tree = PackageDAG({}) + except Exception as e: + # Handle any other exceptions that may occur during PackageDAG initialization + console.print(f"Failed to create PackageDAG: {e}", style="yellow") + tree = PackageDAG({}) + + tree = tree.sort() branch_keys = {r.name for r in flatten(tree.values())} if pkg is None: nodes = [p for p in tree if p.name not in branch_keys] @@ -680,11 +696,7 @@ def reverse_dependencies(self): return rdeps def get_working_set(self): - """Retrieve the working set of installed packages for the environment. - - :return: The working set for the environment - :rtype: :class:`pkg_resources.WorkingSet` - """ + """Retrieve the working set of installed packages for the environment.""" return importlib.metadata.distributions(path=self.sys_path) @@ -703,8 +715,7 @@ def is_satisfied(self, req: InstallRequirement): iter( d for d in self.get_distributions() - if req.name - and canonicalize_name(d.name) == canonicalize_name(req.name) + if req.name and canonicalize_name(d.name) == canonicalize_name(req.name) ), None, ) diff --git a/pipenv/routines/outdated.py b/pipenv/routines/outdated.py index 0c3646d726..5340e74543 100644 --- a/pipenv/routines/outdated.py +++ b/pipenv/routines/outdated.py @@ -3,6 +3,7 @@ from collections.abc import Mapping from pipenv.patched.pip._vendor.packaging.utils import canonicalize_name +from pipenv.patched.pip._vendor.packaging.version import parse as parse_version from pipenv.routines.lock import do_lock from pipenv.utils.dependencies import ( as_pipfile, @@ -19,8 +20,8 @@ def do_outdated(project, pypi_mirror=None, pre=False, clear=False): installed_packages = project.environment.get_installed_packages() outdated_packages = { - canonicalize_name(pkg.project_name): package_info( - pkg.project_name, pkg.parsed_version, pkg.latest_version + canonicalize_name(pkg.name): package_info( + pkg.name, parse_version(pkg.version), pkg.latest_version ) for pkg in project.environment.get_outdated_packages() } @@ -29,9 +30,7 @@ def do_outdated(project, pypi_mirror=None, pre=False, clear=False): for name, deps in project.environment.reverse_dependencies().items() } for result in installed_packages: - dep, _ = expansive_install_req_from_line( - str(result.as_requirement()), expand_env=True - ) + dep, _ = expansive_install_req_from_line(f"{result.name}=={result.version}") packages.update(as_pipfile(dep)) updated_packages = {} @@ -41,7 +40,9 @@ def do_outdated(project, pypi_mirror=None, pre=False, clear=False): for category in project.get_package_categories(for_lockfile=True): for package in lockfile.get(category, []): try: - updated_packages[package] = lockfile[category][package]["version"] + updated_packages[package] = parse_version( + lockfile[category][package]["version"] + ) except KeyError: # noqa: PERF203 pass outdated = [] @@ -51,10 +52,12 @@ def do_outdated(project, pypi_mirror=None, pre=False, clear=False): if norm_name in updated_packages: version = packages[package] if isinstance(version, Mapping): - version = version.get("version") + version = parse_version(version.get("version")) + else: + version = parse_version(version) if updated_packages[norm_name] != version: outdated.append( - package_info(package, updated_packages[norm_name], packages[package]) + package_info(package, str(version), str(updated_packages[norm_name])) ) elif canonicalize_name(package) in outdated_packages: skipped.append(outdated_packages[canonicalize_name(package)])