def test_get_extra_package_names( packages: List[Package], extras: Dict[str, List[str]], extra_names: List[str], expected_extra_package_names: List[str], ): assert expected_extra_package_names == list( get_extra_package_names(packages, extras, extra_names))
def test_get_extra_package_names( packages: list[Package], extras: dict[str, list[str]], extra_names: list[str], expected_extra_package_names: list[str], ): assert ( list(get_extra_package_names(packages, extras, extra_names)) == expected_extra_package_names )
def _get_extra_packages(self, repo: Repository) -> list[str]: """ Returns all package names required by extras. Maybe we just let the solver handle it? """ if self._update: extras = {k: [d.name for d in v] for k, v in self._package.extras.items()} else: extras = self._locker.lock_data.get("extras", {}) return list(get_extra_package_names(repo.packages, extras, self._extras))
def get_project_dependency_packages( self, project_requires: list[Dependency], project_python_marker: BaseMarker | None = None, extras: bool | Sequence[str] | None = None, ) -> Iterator[DependencyPackage]: # Apply the project python marker to all requirements. if project_python_marker is not None: marked_requires: list[Dependency] = [] for require in project_requires: require = deepcopy(require) require.marker = require.marker.intersect( project_python_marker) marked_requires.append(require) project_requires = marked_requires repository = self.locked_repository() # Build a set of all packages required by our selected extras extra_package_names: set[str] | None = None if extras is not True: extra_package_names = set( get_extra_package_names( repository.packages, self.lock_data.get("extras", {}), extras or (), )) # If a package is optional and we haven't opted in to it, do not select selected = [] for dependency in project_requires: try: package = repository.find_packages(dependency=dependency)[0] except IndexError: continue if extra_package_names is not None and ( package.optional and package.name not in extra_package_names): # a package is locked as optional, but is not activated via extras continue selected.append(dependency) for package, dependency in self.get_project_dependencies( project_requires=selected, locked_packages=repository.packages, ): for extra in dependency.extras: package.requires_extras.append(extra) yield DependencyPackage(dependency=dependency, package=package)
def get_project_dependency_packages( self, project_requires: List[Dependency], dev: bool = False, extras: Optional[Union[bool, Sequence[str]]] = None, ) -> Iterator[DependencyPackage]: repository = self.locked_repository(with_dev_reqs=dev) # Build a set of all packages required by our selected extras extra_package_names = ( None if (isinstance(extras, bool) and extras is True) else () ) if extra_package_names is not None: extra_package_names = set( get_extra_package_names( repository.packages, self.lock_data.get("extras", {}), extras or (), ) ) # If a package is optional and we haven't opted in to it, do not select selected = [] for dependency in project_requires: try: package = repository.find_packages(dependency=dependency)[0] except IndexError: continue if extra_package_names is not None and ( package.optional and package.name not in extra_package_names ): # a package is locked as optional, but is not activated via extras continue selected.append(dependency) for dependency in self.get_project_dependencies( project_requires=selected, locked_packages=repository.packages, with_nested=True, ): try: package = repository.find_packages(dependency=dependency)[0] except IndexError: continue for extra in dependency.extras: package.requires_extras.append(extra) yield DependencyPackage(dependency=dependency, package=package)
def test_get_extra_package_names(packages, extras, extra_names, expected_extra_package_names): assert expected_extra_package_names == list( get_extra_package_names(packages, extras, extra_names))
def _export_requirements_txt( self, cwd, output, with_hashes=True, dev=False, extras=None, with_credentials=False, ): # type: (Path, Union[IO, str], bool, bool, bool) -> None indexes = set() content = "" packages = self._poetry.locker.locked_repository(dev).packages # Build a set of all packages required by our selected extras extra_package_names = set( get_extra_package_names( packages, self._poetry.locker.lock_data.get("extras", {}), extras or ())) for package in sorted(packages, key=lambda p: p.name): # If a package is optional and we haven't opted in to it, continue if package.optional and package.name not in extra_package_names: continue if package.source_type == "git": dependency = VCSDependency( package.name, package.source_type, package.source_url, package.source_reference, ) dependency.marker = package.marker line = "-e git+{}@{}#egg={}".format(package.source_url, package.source_reference, package.name) elif package.source_type in ["directory", "file", "url"]: url = package.source_url if package.source_type == "file": dependency = FileDependency( package.name, Path(package.source_url), base=self._poetry.locker.lock.path.parent, ) url = Path( os.path.relpath( url, self._poetry.locker.lock.path.parent.as_posix( ))).as_posix() elif package.source_type == "directory": dependency = DirectoryDependency( package.name, Path(package.source_url), base=self._poetry.locker.lock.path.parent, ) url = Path( os.path.relpath( url, self._poetry.locker.lock.path.parent.as_posix( ))).as_posix() else: dependency = URLDependency(package.name, package.source_url) dependency.marker = package.marker line = "{}".format(url) if package.develop and package.source_type == "directory": line = "-e " + line else: dependency = package.to_dependency() line = "{}=={}".format(package.name, package.version) requirement = dependency.to_pep_508() if ";" in requirement: line += "; {}".format(requirement.split(";")[1].strip()) if (package.source_type not in {"git", "directory", "file", "url"} and package.source_url): indexes.add(package.source_url) if package.files and with_hashes: hashes = [] for f in package.files: h = f["hash"] algorithm = "sha256" if ":" in h: algorithm, h = h.split(":") if algorithm not in self.ALLOWED_HASH_ALGORITHMS: continue hashes.append("{}:{}".format(algorithm, h)) if hashes: line += " \\\n" for i, h in enumerate(hashes): line += " --hash={}{}".format( h, " \\\n" if i < len(hashes) - 1 else "") line += "\n" content += line if indexes: # If we have extra indexes, we add them to the beginning of the output indexes_header = "" for index in sorted(indexes): repository = [ r for r in self._poetry.pool.repositories if r.url == index.rstrip("/") ][0] if (self._poetry.pool.has_default() and repository is self._poetry.pool.repositories[0]): url = (repository.authenticated_url if with_credentials else repository.url) indexes_header = "--index-url {}\n".format(url) continue url = (repository.authenticated_url if with_credentials else repository.url) indexes_header += "--extra-index-url {}\n".format(url) content = indexes_header + "\n" + content self._output(content, cwd, output)
def _export_requirements_txt( self, cwd, output, with_hashes=True, dev=False, extras=None, with_credentials=False, ): # type: (Path, Union[IO, str], bool, bool, bool) -> None indexes = set() content = "" repository = self._poetry.locker.locked_repository(dev) # Build a set of all packages required by our selected extras extra_package_names = set( get_extra_package_names( repository.packages, self._poetry.locker.lock_data.get("extras", {}), extras or (), ) ) dependency_lines = set() for dependency in self._poetry.locker.get_project_dependencies( project_requires=self._poetry.package.all_requires, with_nested=True, with_dev=dev, ): try: package = repository.find_packages(dependency=dependency)[0] except IndexError: continue # If a package is optional and we haven't opted in to it, continue if package.optional and package.name not in extra_package_names: continue line = "" if package.develop: line += "-e " requirement = dependency.to_pep_508(with_extras=False) is_direct_reference = ( dependency.is_vcs() or dependency.is_url() or dependency.is_file() or dependency.is_directory() ) if is_direct_reference: line = requirement else: line = "{}=={}".format(package.name, package.version) if ";" in requirement: markers = requirement.split(";", 1)[1].strip() if markers: line += "; {}".format(markers) if not is_direct_reference and package.source_url: indexes.add(package.source_url) if package.files and with_hashes: hashes = [] for f in package.files: h = f["hash"] algorithm = "sha256" if ":" in h: algorithm, h = h.split(":") if algorithm not in self.ALLOWED_HASH_ALGORITHMS: continue hashes.append("{}:{}".format(algorithm, h)) if hashes: line += " \\\n" for i, h in enumerate(hashes): line += " --hash={}{}".format( h, " \\\n" if i < len(hashes) - 1 else "" ) dependency_lines.add(line) content += "\n".join(sorted(dependency_lines)) content += "\n" if indexes: # If we have extra indexes, we add them to the beginning of the output indexes_header = "" for index in sorted(indexes): repositories = [ r for r in self._poetry.pool.repositories if r.url == index.rstrip("/") ] if not repositories: continue repository = repositories[0] if ( self._poetry.pool.has_default() and repository is self._poetry.pool.repositories[0] ): url = ( repository.authenticated_url if with_credentials else repository.url ) indexes_header = "--index-url {}\n".format(url) continue url = ( repository.authenticated_url if with_credentials else repository.url ) indexes_header += "--extra-index-url {}\n".format(url) content = indexes_header + "\n" + content self._output(content, cwd, output)