[docs]classPythonProject(Project[PythonHookArgs]):"""Python project."""DEFAULT_CACHE_DIR_NAME:ClassVar[str]="pip_cache""""Name of the default cache directory."""@cached_propertydefdocker(self)->PythonDockerDependencyInstaller|None:"""Docker interface that can be used to build the project."""returnPythonDockerDependencyInstaller.from_project(self)@cached_propertydefmetadata_files(self)->tuple[Path,...]:"""Project metadata files. Files are only included in return value if they exist. """ifself.project_type=="poetry":config_files=[self.project_root/config_fileforconfig_fileinPoetry.CONFIG_FILES]elifself.project_type=="pipenv":config_files=[self.project_root/config_fileforconfig_fileinPipenv.CONFIG_FILES]else:config_files=[self.project_root/config_fileforconfig_fileinPip.CONFIG_FILES]returntuple(pathforpathinconfig_filesifpath.exists())@cached_propertydefruntime(self)->str:"""Runtime of the build system. Value should be a valid Lambda Function runtime (https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html). """ifself._runtime_from_docker:returnself._validate_runtime(self._runtime_from_docker)returnself._validate_runtime(f"python{self.pip.python_version.major}.{self.pip.python_version.minor}")@cached_propertydefpip(self)->Pip:"""Pip dependency manager."""returnPip(self.ctx,self.project_root)@cached_propertydefpipenv(self)->Pipenv|None:"""Pipenv dependency manager. Return: If the project uses pipenv and pipenv is not explicitly disabled, an object for interfacing with pipenv will be returned. Raises: PipenvNotFoundError: pipenv is not installed or not found in PATH. """ifself.project_type!="pipenv":returnNoneifPipenv.found_in_path():returnPipenv(self.ctx,self.project_root)raisePipenvNotFoundError@cached_propertydefpoetry(self)->Poetry|None:"""Poetry dependency manager. Return: If the project uses poetry and poetry is not explicitly disabled, an object for interfacing with poetry will be returned. Raises: PoetryNotFound: poetry is not installed or not found in PATH. """ifself.project_type!="poetry":returnNoneifPoetry.found_in_path():returnPoetry(self.ctx,self.project_root)raisePoetryNotFoundError@cached_propertydefproject_type(self)->Literal["pip","pipenv","poetry"]:"""Type of python project."""ifPoetry.dir_is_project(self.project_root):ifself.args.use_poetry:return"poetry"LOGGER.warning("poetry project detected but use of poetry is explicitly disabled")ifPipenv.dir_is_project(self.project_root):ifself.args.use_pipenv:return"pipenv"LOGGER.warning("pipenv project detected but use of pipenv is explicitly disabled")return"pip"@cached_propertydefrequirements_txt(self)->Path|None:"""Dependency file for the project."""ifself.poetry:# prioritize poetryreturnself.poetry.export(output=self.tmp_requirements_txt)ifself.pipenv:returnself.pipenv.export(output=self.tmp_requirements_txt)requirements_txt=self.project_root/"requirements.txt"ifPip.dir_is_project(self.project_root,file_name=requirements_txt.name):returnrequirements_txtreturnNone@cached_propertydefsupported_metadata_files(self)->set[str]:"""Names of all supported metadata files. Returns: Set of file names - not paths. """file_names={*Pip.CONFIG_FILES}ifself.args.use_poetry:file_names.update(Poetry.CONFIG_FILES)ifself.args.use_pipenv:file_names.update(Pipenv.CONFIG_FILES)returnfile_names@cached_propertydeftmp_requirements_txt(self)->Path:"""Temporary requirements.txt file. This path is only used when exporting from another format. """returnself.ctx.work_dir/f"{self.source_code.md5_hash}.requirements.txt"
[docs]defcleanup(self)->None:"""Cleanup temporary files after the build process has run."""if(self.poetryorself.pipenv)andself.tmp_requirements_txt.exists():self.tmp_requirements_txt.unlink()shutil.rmtree(self.dependency_directory,ignore_errors=True)ifnotany(self.build_directory.iterdir()):# remove build_directory if it's emptyshutil.rmtree(self.build_directory,ignore_errors=True)
[docs]definstall_dependencies(self)->None:"""Install project dependencies."""ifself.requirements_txt:LOGGER.debug("installing dependencies to %s...",self.dependency_directory)ifself.docker:self.docker.install()else:self.pip.install(cache_dir=self.args.cache_dir,extend_args=self.args.extend_pip_args,no_cache_dir=notself.args.use_cache,no_deps=bool(self.poetryorself.pipenv),requirements=self.requirements_txt,target=self.dependency_directory,)LOGGER.debug("dependencies successfully installed to %s",self.dependency_directory)else:LOGGER.info("skipped installing dependencies; none found")