Source code for aws_lambda_python_packager.pip_analyzer

from __future__ import annotations

import tempfile
from importlib.metadata import distributions
from pathlib import Path
from typing import Iterable

from .dep_analyzer import DepAnalyzer, ExtraLine, PackageInfo
from .util import PathType


[docs]def get_packages(path): if not isinstance(path, list): path = [str(path)] dists = distributions(path=path) # noinspection PyProtectedMember return {b.metadata["Name"]: b.version for b in dists}
[docs]class PipAnalyzer(DepAnalyzer): analyzer_name = "pip" def __init__( self, project_root: PathType | None, python_version: str = "3.9", architecture: str = "x86_64", region: str = "us-east-1", ignore_packages=False, update_dependencies=False, additional_packages_to_ignore: dict | None = None, ): super().__init__( project_root, python_version, architecture, region, ignore_packages, update_dependencies, additional_packages_to_ignore, ) # try: # import pkg_resources # except ImportError: # self.log.error("pip is not installed") # raise self.copy_to_temp_dir(("requirements.txt",)) def _get_requirements(self) -> Iterable[PackageInfo | ExtraLine]: with tempfile.TemporaryDirectory() as tmpdir: self._install_pip( "--only-binary=:all:", "--target", tmpdir, "-r", Path(self._temp_proj_dir.name) / "requirements.txt", quiet=True, requirements_file=True, ) for pkg, version in get_packages(tmpdir).items(): yield PackageInfo(pkg, version, f"{pkg}=={version}") @property def extra_lines(self): self._extra_lines = [] req_file = self.project_root / "requirements.txt" with req_file.open() as f: for line in self.process_requirements(f): if not isinstance(line, ExtraLine): continue self._extra_lines.append(line) return self._extra_lines def _update_dependency_file(self, pkgs_to_add: dict[str, PackageInfo]): self.backup_files(["requirements.txt"]) self.log.debug( "Updating requirements.txt with %s", ", ".join(f"{k}=={v}" for k, v in pkgs_to_add.items()), ) new_lines = [] with open(Path(self._temp_proj_dir.name) / "requirements.txt", encoding="utf8") as f: for pkg in self.process_requirements(f): if isinstance(pkg, ExtraLine): new_lines.append(" ".join(pkg)) continue if pkg.name not in pkgs_to_add: new_lines.append(pkg.version_spec) for pkg in pkgs_to_add.values(): new_lines.append(pkg.version_spec) with open(Path(self._temp_proj_dir.name) / "requirements.txt", "w", encoding="utf8") as f: f.write("\n".join(new_lines)) f.write("\n") self.copy_from_temp_dir(["requirements.txt"])
[docs] def direct_dependencies(self) -> dict[str, str]: with (self.project_root / "requirements.txt").open() as f: ret = {} for pkg in self.process_requirements(f): if isinstance(pkg, ExtraLine): continue ret[pkg.name] = pkg.version return ret