[docs]classPoetryExportFailedError(RunwayError):"""Poetry export failed to produce a ``requirements.txt`` file."""
[docs]def__init__(self,output:str,*args:Any,**kwargs:Any)->None:"""Instantiate class. All args/kwargs are passed to parent method. Args: output: The output from running ``poetry export``. *args: Variable length argument list. **kwargs: Arbitrary keyword arguments. """self.message=f"poetry export failed with the following output:\n{output}"super().__init__(*args,**kwargs)
[docs]classPoetryNotFoundError(RunwayError):"""Poetry not installed or found in $PATH."""
[docs]def__init__(self,*args:Any,**kwargs:Any)->None:"""Instantiate class. All args/kwargs are passed to parent method."""self.message=("poetry not installed or not in PATH! ""Install it according to poetry docs (https://python-poetry.org/) ""and ensure it is available in PATH.")super().__init__(*args,**kwargs)
[docs]classPoetry(DependencyManager):"""Poetry dependency manager."""CONFIG_FILES:ClassVar[tuple[str,...]]=("poetry.lock","pyproject.toml",)"""Configuration files used by poetry."""EXECUTABLE:ClassVar[str]="poetry""""CLI executable."""@cached_propertydefversion(self)->Version:"""poetry version."""cmd_output=self._run_command([self.EXECUTABLE,"--version"])match=re.search(r"^Poetry version (?P<version>\S*)",cmd_output)ifnotmatch:LOGGER.warning("unable to parse poetry version from output:\n%s",cmd_output)returnVersion("0.0.0")returnVersion(match.group("version"))
[docs]@classmethoddefdir_is_project(cls,directory:StrPath,**__kwargs:Any)->bool:"""Determine if the directory contains a project for this dependency manager. Args: directory: Directory to check. """pyproject_path=Path(directory)/Poetry.CONFIG_FILES[1]ifnotpyproject_path.is_file():returnFalse# check for PEP-517 definitionpyproject=tomli.loads(pyproject_path.read_text())build_system_requires:list[str]|None=pyproject.get("build-system",{}).get("requires")ifbuild_system_requires:forreqinbuild_system_requires:ifreq.startswith("poetry"):LOGGER.debug("poetry project detected")returnTruereturnFalse
[docs]defexport(self,*,dev:bool=False,extras:list[str]|None=None,output:StrPath,output_format:str="requirements.txt",with_credentials:bool=True,without_hashes:bool=True,)->Path:"""Export the lock file to other formats. Args: dev: Include development dependencies. extras: Extra sets of dependencies to include. output: Path to the output file. output_format: The format to export to. with_credentials: Include credentials for extra indices. without_hashes: Exclude hashes from the exported file. Returns: Path to the output file. """output=Path(output)try:result=self._run_command(self.generate_command("export",dev=dev,extras=extras,format=output_format,output=output.name,with_credentials=with_credentials,without_hashes=without_hashes,))requirements_txt=self.cwd/output.nameifrequirements_txt.is_file():output.parent.mkdir(exist_ok=True,parents=True)requirements_txt.rename(output)# python3.7 doesn't return the new pathreturnoutputexceptsubprocess.CalledProcessErrorasexc:raisePoetryExportFailedError(exc.stderr)fromexcraisePoetryExportFailedError(result)