Source code for boto3_dataclass.structures.pyproject
# -*- coding: utf-8 -*-"""Python Project Structure Management.This module provides the :class:`PyProjectStructure` class that manages the file system structure,build operations, and distribution management for Python packages in the boto3-dataclass ecosystem."""importshutilimportsubprocessimportdataclassesfrompathlibimportPathfromfunctoolsimportcached_propertyimportrequests.exceptionsimporttwine.commands.uploadfromrichimportprintasrprintfrom..vendor.better_pathlibimporttemp_cwdfrom..pathsimportpath_enumfrom..configimportconfig
[docs]@dataclasses.dataclassclassPyProjectStructure:""" Manages the file system structure and operations for Python projects. This class provides a complete abstraction for Python project management, including directory structure, build operations, and distribution handling. It's designed specifically for boto3-dataclass packages but can be used for any Python project following standard conventions. The class uses cached properties to efficiently manage file paths and provides methods for common development operations like building, uploading, and installing packages. :param package_name: The Python package name (with underscores) Properties: - ``package_name_slug``: Package name in slug format (with hyphens) - ``dir_repo``: Root directory for the project repository - ``dir_package``: Directory containing the Python package - ``path_*``: Various file paths within the project structure - ``dist_files``: List of built distribution files Example: >>> project = PyProjectStructure(package_name="my_awesome_package") >>> project.poetry_build() # Build distributions >>> project.twine_upload() # Upload to PyPI """package_name:str=dataclasses.field()@cached_propertydefpackage_name_slug(self)->str:""" Get the package name in slug format (with hyphens instead of underscores). Example: - ``boto3-dataclass`` - ``boto3-dataclass-ec2`` """returnself.package_name.replace("_","-")@cached_propertydefdir_repo(self)->Path:""" Get the build directory path for the boto3_dataclass package repository. We use this directory to publish the package to PyPI. Example: - ``build/repos/boto3_dataclass-project`` - ``build/repos/boto3_dataclass_ec2-project`` """return(path_enum.dir_project_root/"build"/"repos"/f"{self.package_name}-project")
[docs]defremove_dir(self):""" Remove the entire project repository directory. This method safely removes the project's build directory and all its contents. It's typically used for cleaning up before a fresh build. """shutil.rmtree(self.dir_repo,ignore_errors=True)# Safely remove directory tree
@cached_propertydefdir_package(self)->Path:""" Get the directory path for the boto3_dataclass package. Example: ``build/repos/boto3_dataclass_ec2-project/boto3_dataclass_ec2`` """returnself.dir_repo/self.package_name@cached_propertydefpath_init_py(self)->Path:""" Example: ``build/repos/boto3_dataclass_ec2-project/boto3_dataclass_ec2/__init__.py`` """returnself.dir_package/"__init__.py"@cached_propertydefpath_pyproject_toml(self)->Path:""" Example: ``build/repos/boto3_dataclass_ec2-project/pyproject.toml`` """returnself.dir_repo/"pyproject.toml"@cached_propertydefpath_README_rst(self)->Path:""" Example: ``build/repos/boto3_dataclass_ec2-project/README.rst`` """returnself.dir_repo/"README.rst"@cached_propertydefpath_LICENSE_txt(self)->Path:""" Example: ``build/repos/boto3_dataclass_ec2-project/LICENSE.txt`` """returnself.dir_repo/"LICENSE.txt"@cached_propertydefdir_dist(self)->Path:""" Get the distribution directory path for built packages. Example: ``build/repos/boto3_dataclass_ec2-project/dist`` """returnself.dir_repo/"dist"@cached_propertydefdist_files(self)->list[str]:""" Get the list of distribution files in the dist directory. Scans the project's dist/ directory for built distribution files (both wheel and source distributions) that belong to this package. Returns: List of absolute paths to distribution files as strings Example:: [ "build/repos/boto3_dataclass_ec2-project/dist/boto3_dataclass_ec2-0.1.1.tar.gz", "build/repos/boto3_dataclass_ec2-project/dist/boto3_dataclass_ec2-0.1.1-py3-none-any.whl" ] """dists=list()# Iterate through all files in the dist directoryforpinself.dir_dist.iterdir():# Only include files that match our package name and are valid distribution typesifp.name.startswith(self.package_name)andp.suffixin{".whl",".tar.gz"}:dists.append(str(p))# Convert Path to string for Twine compatibilityreturndists
[docs]defpoetry_build(self):""" Build the package using Poetry. Creates both source distribution (.tar.gz) and wheel (.whl) files in the project's dist/ directory using Poetry's build command. Raises: subprocess.CalledProcessError: If the Poetry build command fails """args=["poetry","build"]# Change to project directory for build operationwithtemp_cwd(self.dir_repo):subprocess.run(args,cwd=self.dir_repo,check=True)# Execute poetry build with error checking
[docs]deftwine_upload(self):""" Upload distribution files to PyPI using Twine. Uploads all distribution files (both source and wheel) found in the dist/ directory to the configured PyPI repository using Twine. :raises: twine.exceptions.TwineException: If upload fails requests.exceptions.RequestException: If network error occurs """# Change to project directory for upload operationwithtemp_cwd(self.dir_repo):try:twine.commands.upload.upload(upload_settings=config.twine_upload_settings,# Use configured credentials/settingsdists=self.dist_files,# Upload all built distribution files)exceptrequests.exceptions.HTTPErrorase:print(f"response.headers:")fork,vine.response.headers.items():print(f"{k} = {v}")print(f"response.text:")print(e.response.text)raiseexceptExceptionase:print(f"{type(e)= }")raise
[docs]defpip_install_editable(self):""" Install the package in editable mode for development. Installs the package in development mode (editable install) using pip. This allows changes to the source code to be immediately reflected without reinstalling the package. Raises: subprocess.CalledProcessError: If the pip install command fails """# Use pip from project's virtual environmentpath_bin_pip=path_enum.dir_venv_bin/"pip"args=[f"{path_bin_pip}","install","-e",# Editable/development mode flag".",# Install current directory]# Change to project directory for installationwithtemp_cwd(self.dir_repo):subprocess.run(args,cwd=self.dir_repo,check=True)# Execute pip install with error checking