+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Part 196 of 343

๐Ÿ“˜ Package Publishing: Advanced PyPI

Master package publishing: advanced pypi in Python with practical examples, best practices, and real-world applications ๐Ÿš€

๐Ÿ’ŽAdvanced
35 min read

Prerequisites

  • Basic understanding of programming concepts ๐Ÿ“
  • Python installation (3.8+) ๐Ÿ
  • VS Code or preferred IDE ๐Ÿ’ป

What you'll learn

  • Understand the concept fundamentals ๐ŸŽฏ
  • Apply the concept in real projects ๐Ÿ—๏ธ
  • Debug common issues ๐Ÿ›
  • Write clean, Pythonic code โœจ

๐ŸŽฏ Introduction

Welcome to this exciting tutorial on advanced PyPI package publishing! ๐ŸŽ‰ In this guide, weโ€™ll explore how to professionally publish and maintain Python packages on the Python Package Index.

Youโ€™ll discover how to create high-quality packages that thousands of developers can use. Whether youโ€™re sharing a utility library ๐Ÿ“š, a framework ๐Ÿ—๏ธ, or a tool ๐Ÿ› ๏ธ, understanding advanced PyPI publishing is essential for contributing to the Python ecosystem.

By the end of this tutorial, youโ€™ll feel confident publishing professional Python packages! Letโ€™s dive in! ๐ŸŠโ€โ™‚๏ธ

๐Ÿ“š Understanding Advanced PyPI Publishing

๐Ÿค” What is Advanced PyPI Publishing?

Advanced PyPI publishing is like running a professional software distribution center ๐Ÿญ. Think of it as not just shipping your code, but creating a complete product with documentation, versioning, and quality assurance.

In Python terms, advanced publishing means you can:

  • โœจ Create packages with multiple distribution formats
  • ๐Ÿš€ Automate releases with CI/CD pipelines
  • ๐Ÿ›ก๏ธ Sign packages for security verification
  • ๐Ÿ“Š Track download statistics and user analytics
  • ๐Ÿ”„ Manage complex dependencies and versions

๐Ÿ’ก Why Master Advanced Publishing?

Hereโ€™s why developers need advanced PyPI skills:

  1. Professional Presence ๐Ÿ†: Stand out with high-quality packages
  2. User Trust ๐Ÿ›ก๏ธ: Security and reliability build confidence
  3. Maintenance Efficiency ๐Ÿ”ง: Streamline updates and releases
  4. Community Growth ๐ŸŒŸ: Attract contributors and users

Real-world example: Imagine publishing a data analysis library ๐Ÿ“Š. With advanced techniques, you can ensure compatibility across Python versions, provide wheels for fast installation, and automate security updates.

๐Ÿ”ง Basic Syntax and Usage

๐Ÿ“ Advanced Project Structure

Letโ€™s start with a professional package structure:

# ๐Ÿ—๏ธ Professional package structure
my_awesome_package/
โ”œโ”€โ”€ src/
โ”‚   โ””โ”€โ”€ my_package/
โ”‚       โ”œโ”€โ”€ __init__.py      # ๐Ÿ“ฆ Package initialization
โ”‚       โ”œโ”€โ”€ core.py          # ๐ŸŽฏ Core functionality
โ”‚       โ””โ”€โ”€ utils.py         # ๐Ÿ› ๏ธ Utility functions
โ”œโ”€โ”€ tests/
โ”‚   โ”œโ”€โ”€ test_core.py         # ๐Ÿงช Core tests
โ”‚   โ””โ”€โ”€ test_utils.py        # ๐Ÿงช Utility tests
โ”œโ”€โ”€ docs/
โ”‚   โ”œโ”€โ”€ conf.py              # ๐Ÿ“– Sphinx configuration
โ”‚   โ””โ”€โ”€ index.rst            # ๐Ÿ“š Documentation index
โ”œโ”€โ”€ .github/
โ”‚   โ””โ”€โ”€ workflows/
โ”‚       โ””โ”€โ”€ publish.yml      # ๐Ÿš€ CI/CD pipeline
โ”œโ”€โ”€ setup.py                 # ๐Ÿ”ง Package configuration
โ”œโ”€โ”€ setup.cfg                # โš™๏ธ Configuration file
โ”œโ”€โ”€ pyproject.toml           # ๐ŸŽจ Modern build configuration
โ”œโ”€โ”€ MANIFEST.in              # ๐Ÿ“‹ File inclusion rules
โ”œโ”€โ”€ LICENSE                  # ๐Ÿ“œ License file
โ”œโ”€โ”€ README.md                # ๐Ÿ“– Project documentation
โ””โ”€โ”€ .gitignore              # ๐Ÿšซ Git ignore rules

๐Ÿ’ก Explanation: This structure separates source code, tests, and documentation while providing modern build configurations!

๐ŸŽฏ Modern pyproject.toml Configuration

Hereโ€™s a professional configuration:

# ๐ŸŽจ pyproject.toml - Modern Python packaging
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "awesome-package"
version = "2.0.0"
description = "An awesome package that does amazing things! โœจ"
readme = "README.md"
license = {text = "MIT"}
authors = [
    {name = "Your Name", email = "[email protected]"},
]
maintainers = [
    {name = "Maintainer Team", email = "[email protected]"},
]
classifiers = [
    "Development Status :: 5 - Production/Stable",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: MIT License",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.8",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Operating System :: OS Independent",
    "Topic :: Software Development :: Libraries",
]
keywords = ["awesome", "package", "python"]
requires-python = ">=3.8"
dependencies = [
    "requests>=2.28.0",
    "click>=8.0.0",
    "pydantic>=2.0.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.0.0",
    "pytest-cov>=4.0.0",
    "black>=23.0.0",
    "mypy>=1.0.0",
    "ruff>=0.0.270",
]
docs = [
    "sphinx>=5.0.0",
    "sphinx-rtd-theme>=1.0.0",
    "sphinx-autodoc-typehints>=1.0.0",
]

[project.urls]
Homepage = "https://github.com/you/awesome-package"
Documentation = "https://awesome-package.readthedocs.io"
Repository = "https://github.com/you/awesome-package.git"
"Bug Tracker" = "https://github.com/you/awesome-package/issues"
Changelog = "https://github.com/you/awesome-package/blob/main/CHANGELOG.md"

[project.scripts]
awesome-cli = "my_package.cli:main"

[tool.setuptools.packages.find]
where = ["src"]

[tool.setuptools.package-data]
my_package = ["py.typed", "data/*.json"]

๐Ÿ’ก Practical Examples

๐Ÿ›’ Example 1: Multi-Format Distribution

Letโ€™s create distributions for different platforms:

# ๐Ÿญ build_distributions.py - Build multiple formats
import subprocess
import shutil
from pathlib import Path

class PackageBuilder:
    def __init__(self, package_name: str):
        self.package_name = package_name
        self.dist_dir = Path("dist")
        
    def clean_build(self):
        """๐Ÿงน Clean previous builds"""
        print("๐Ÿงน Cleaning previous builds...")
        for dir_name in ["build", "dist", "*.egg-info"]:
            for path in Path(".").glob(dir_name):
                if path.is_dir():
                    shutil.rmtree(path)
                else:
                    path.unlink()
        print("โœจ Clean complete!")
    
    def build_sdist(self):
        """๐Ÿ“ฆ Build source distribution"""
        print("๐Ÿ“ฆ Building source distribution...")
        subprocess.run([
            "python", "-m", "build", "--sdist"
        ], check=True)
        print("โœ… Source distribution built!")
    
    def build_wheel(self):
        """๐ŸŽก Build wheel distribution"""
        print("๐ŸŽก Building wheel distribution...")
        subprocess.run([
            "python", "-m", "build", "--wheel"
        ], check=True)
        print("โœ… Wheel distribution built!")
    
    def build_platform_wheels(self):
        """๐ŸŒ Build platform-specific wheels"""
        print("๐ŸŒ Building platform wheels...")
        # ๐ŸŽฏ Use cibuildwheel for multi-platform support
        subprocess.run([
            "cibuildwheel", "--output-dir", str(self.dist_dir)
        ], check=True)
        print("โœ… Platform wheels built!")
    
    def verify_distributions(self):
        """๐Ÿ” Verify built distributions"""
        print("๐Ÿ” Verifying distributions...")
        for dist_file in self.dist_dir.glob("*"):
            print(f"  ๐Ÿ“‹ {dist_file.name} ({dist_file.stat().st_size:,} bytes)")
        
        # ๐Ÿงช Check with twine
        subprocess.run([
            "twine", "check", "dist/*"
        ], check=True)
        print("โœ… All distributions verified!")

# ๐ŸŽฎ Let's use it!
builder = PackageBuilder("awesome-package")
builder.clean_build()
builder.build_sdist()
builder.build_wheel()
builder.verify_distributions()

๐ŸŽฏ Try it yourself: Add support for building conda packages!

๐ŸŽฎ Example 2: Automated Release Pipeline

Letโ€™s create a GitHub Actions workflow:

# ๐Ÿš€ .github/workflows/publish.yml
name: ๐Ÿ“ฆ Publish Python Package

on:
  release:
    types: [published]
  workflow_dispatch:
    inputs:
      test_pypi:
        description: 'Publish to Test PyPI first?'
        required: true
        default: 'true'

jobs:
  build-and-test:
    name: ๐Ÿ—๏ธ Build and Test
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.8', '3.9', '3.10', '3.11']
    
    steps:
    - name: ๐Ÿ“ฅ Checkout code
      uses: actions/checkout@v3
      with:
        fetch-depth: 0  # ๐Ÿ“Š Full history for versioning
    
    - name: ๐Ÿ Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}
    
    - name: ๐Ÿ“ฆ Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -e .[dev]
        pip install build twine
    
    - name: ๐Ÿงช Run tests
      run: |
        pytest --cov=my_package --cov-report=xml
        echo "โœ… Tests passed on Python ${{ matrix.python-version }}!"
    
    - name: ๐Ÿ“Š Upload coverage
      if: matrix.python-version == '3.11'
      uses: codecov/codecov-action@v3
      with:
        file: ./coverage.xml

  publish:
    name: ๐Ÿš€ Publish Package
    needs: build-and-test
    runs-on: ubuntu-latest
    
    steps:
    - name: ๐Ÿ“ฅ Checkout code
      uses: actions/checkout@v3
    
    - name: ๐Ÿ Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.11'
    
    - name: ๐Ÿ—๏ธ Build distributions
      run: |
        pip install build
        python -m build
        echo "๐Ÿ“ฆ Distributions built!"
    
    - name: ๐Ÿงช Publish to Test PyPI
      if: github.event.inputs.test_pypi == 'true'
      env:
        TWINE_USERNAME: __token__
        TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }}
      run: |
        twine upload --repository testpypi dist/*
        echo "โœ… Published to Test PyPI!"
    
    - name: ๐Ÿš€ Publish to PyPI
      if: github.event_name == 'release'
      env:
        TWINE_USERNAME: __token__
        TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
      run: |
        twine upload dist/*
        echo "๐ŸŽ‰ Published to PyPI!"

๐Ÿ“Š Example 3: Package Security and Signing

Letโ€™s implement package signing:

# ๐Ÿ” secure_publish.py - Secure package publishing
import subprocess
import hashlib
from pathlib import Path
import gnupg

class SecurePublisher:
    def __init__(self, gpg_key_id: str):
        self.gpg = gnupg.GPG()
        self.key_id = gpg_key_id
        self.dist_dir = Path("dist")
        
    def generate_checksums(self):
        """๐Ÿ” Generate checksums for distributions"""
        print("๐Ÿ” Generating checksums...")
        checksums = {}
        
        for dist_file in self.dist_dir.glob("*"):
            if dist_file.suffix in [".whl", ".tar.gz"]:
                # ๐Ÿ“Š Calculate multiple hash types
                sha256 = hashlib.sha256()
                sha512 = hashlib.sha512()
                
                with open(dist_file, "rb") as f:
                    while chunk := f.read(8192):
                        sha256.update(chunk)
                        sha512.update(chunk)
                
                checksums[dist_file.name] = {
                    "sha256": sha256.hexdigest(),
                    "sha512": sha512.hexdigest()
                }
                print(f"  โœ… {dist_file.name}")
        
        # ๐Ÿ“ Write checksums file
        with open(self.dist_dir / "CHECKSUMS.txt", "w") as f:
            for filename, hashes in checksums.items():
                f.write(f"# {filename}\n")
                f.write(f"SHA256: {hashes['sha256']}\n")
                f.write(f"SHA512: {hashes['sha512']}\n\n")
        
        print("โœจ Checksums generated!")
        return checksums
    
    def sign_distributions(self):
        """๐Ÿ” Sign distributions with GPG"""
        print("๐Ÿ” Signing distributions...")
        
        for dist_file in self.dist_dir.glob("*"):
            if dist_file.suffix in [".whl", ".tar.gz"]:
                # ๐Ÿ–Š๏ธ Create detached signature
                with open(dist_file, "rb") as f:
                    signed = self.gpg.sign_file(
                        f,
                        keyid=self.key_id,
                        detach=True,
                        output=f"{dist_file}.asc"
                    )
                
                if signed:
                    print(f"  โœ… Signed: {dist_file.name}")
                else:
                    print(f"  โŒ Failed to sign: {dist_file.name}")
    
    def verify_signatures(self):
        """๐Ÿ” Verify all signatures"""
        print("๐Ÿ” Verifying signatures...")
        
        for sig_file in self.dist_dir.glob("*.asc"):
            dist_file = sig_file.with_suffix("")
            
            with open(sig_file, "rb") as f:
                verified = self.gpg.verify_file(f, str(dist_file))
            
            if verified:
                print(f"  โœ… Valid: {dist_file.name}")
            else:
                print(f"  โŒ Invalid: {dist_file.name}")
    
    def secure_upload(self):
        """๐Ÿš€ Securely upload to PyPI"""
        print("๐Ÿš€ Uploading to PyPI...")
        
        # ๐Ÿ“‹ Upload with signatures
        subprocess.run([
            "twine", "upload",
            "--sign", "--identity", self.key_id,
            "dist/*"
        ], check=True)
        
        print("๐ŸŽ‰ Secure upload complete!")

# ๐ŸŽฎ Let's use it!
publisher = SecurePublisher("YOUR_GPG_KEY_ID")
publisher.generate_checksums()
publisher.sign_distributions()
publisher.verify_signatures()

๐Ÿš€ Advanced Concepts

๐Ÿง™โ€โ™‚๏ธ Dynamic Versioning with Git Tags

When youโ€™re ready to level up, try automatic versioning:

# ๐ŸŽฏ setup.py with dynamic versioning
from setuptools import setup, find_packages
import subprocess
import re

def get_version_from_git():
    """๐Ÿท๏ธ Get version from git tags"""
    try:
        # ๐Ÿ“Š Get the latest tag
        tag = subprocess.check_output(
            ["git", "describe", "--tags", "--abbrev=0"],
            stderr=subprocess.DEVNULL
        ).decode().strip()
        
        # ๐Ÿ”„ Check if we're on the tagged commit
        tag_commit = subprocess.check_output(
            ["git", "rev-list", "-n", "1", tag],
            stderr=subprocess.DEVNULL
        ).decode().strip()
        
        current_commit = subprocess.check_output(
            ["git", "rev-parse", "HEAD"],
            stderr=subprocess.DEVNULL
        ).decode().strip()
        
        if tag_commit == current_commit:
            # โœจ Clean tag version
            return tag.lstrip("v")
        else:
            # ๐Ÿš€ Development version
            commits_since = subprocess.check_output(
                ["git", "rev-list", f"{tag}..HEAD", "--count"],
                stderr=subprocess.DEVNULL
            ).decode().strip()
            
            short_hash = current_commit[:7]
            base_version = tag.lstrip("v")
            
            return f"{base_version}.dev{commits_since}+g{short_hash}"
            
    except subprocess.CalledProcessError:
        # ๐Ÿ›ก๏ธ Fallback version
        return "0.0.1.dev0"

# ๐ŸŽจ Use in setup
setup(
    name="awesome-package",
    version=get_version_from_git(),
    # ... rest of configuration
)

๐Ÿ—๏ธ Advanced Dependency Management

For complex dependency scenarios:

# ๐Ÿš€ smart_dependencies.py
import sys
import platform
from typing import List, Dict

class DependencyManager:
    """๐ŸŽฏ Smart dependency resolution"""
    
    @staticmethod
    def get_platform_deps() -> List[str]:
        """๐ŸŒ Platform-specific dependencies"""
        deps = []
        
        # ๐Ÿ–ฅ๏ธ Windows-specific
        if platform.system() == "Windows":
            deps.extend([
                "pywin32>=300",
                "windows-curses>=2.0",
            ])
        
        # ๐Ÿง Linux-specific
        elif platform.system() == "Linux":
            deps.extend([
                "python-daemon>=2.0",
            ])
        
        # ๐ŸŽ macOS-specific
        elif platform.system() == "Darwin":
            deps.extend([
                "pyobjc-core>=8.0",
            ])
        
        return deps
    
    @staticmethod
    def get_python_version_deps() -> List[str]:
        """๐Ÿ Python version-specific dependencies"""
        deps = []
        
        # ๐Ÿ“Š Python 3.8 needs backports
        if sys.version_info < (3, 9):
            deps.extend([
                "importlib-metadata>=4.0",
                "typing-extensions>=4.0",
            ])
        
        # ๐Ÿš€ Python 3.11+ optimizations
        if sys.version_info >= (3, 11):
            deps.extend([
                "speedups>=1.0",  # Hypothetical C extensions
            ])
        
        return deps
    
    @staticmethod
    def get_optional_deps() -> Dict[str, List[str]]:
        """โœจ Optional feature dependencies"""
        return {
            "async": [
                "aiohttp>=3.8",
                "asyncpg>=0.27",
                "aiofiles>=22.0",
            ],
            "ml": [
                "numpy>=1.20",
                "scikit-learn>=1.0",
                "pandas>=1.3",
            ],
            "viz": [
                "matplotlib>=3.5",
                "seaborn>=0.12",
                "plotly>=5.0",
            ],
            "all": [
                # ๐ŸŽ Everything!
                "aiohttp>=3.8",
                "numpy>=1.20",
                "matplotlib>=3.5",
            ],
        }

# ๐ŸŽฎ Use in pyproject.toml generation
manager = DependencyManager()
all_deps = (
    ["requests>=2.28", "click>=8.0"] +
    manager.get_platform_deps() +
    manager.get_python_version_deps()
)

โš ๏ธ Common Pitfalls and Solutions

๐Ÿ˜ฑ Pitfall 1: Broken Installation

# โŒ Wrong - Missing package data
setup(
    name="my-package",
    packages=find_packages(),
    # ๐Ÿ’ฅ Static files not included!
)

# โœ… Correct - Include all necessary files
setup(
    name="my-package",
    packages=find_packages(),
    package_data={
        "my_package": [
            "data/*.json",
            "templates/*.html",
            "static/**/*",
        ],
    },
    include_package_data=True,  # ๐Ÿ“ฆ Use MANIFEST.in
)

๐Ÿคฏ Pitfall 2: Version Conflicts

# โŒ Dangerous - Too strict versioning
dependencies = [
    "requests==2.28.0",  # ๐Ÿ’ฅ Locks users to exact version
    "numpy==1.21.0",     # ๐Ÿ’ฅ Causes conflicts
]

# โœ… Safe - Flexible version ranges
dependencies = [
    "requests>=2.28.0,<3.0",  # โœ… Compatible range
    "numpy>=1.20,<2.0",       # โœ… Major version pin
]

๐Ÿ”’ Pitfall 3: Security Vulnerabilities

# โŒ Insecure - No verification
def download_dependency(url: str):
    response = requests.get(url)
    with open("dep.tar.gz", "wb") as f:
        f.write(response.content)  # ๐Ÿ’ฅ No verification!

# โœ… Secure - Verify checksums and signatures
def secure_download(url: str, expected_hash: str):
    response = requests.get(url)
    
    # ๐Ÿ” Verify checksum
    actual_hash = hashlib.sha256(response.content).hexdigest()
    if actual_hash != expected_hash:
        raise ValueError("โŒ Checksum mismatch!")
    
    # โœ… Safe to save
    with open("dep.tar.gz", "wb") as f:
        f.write(response.content)
    print("โœ… Download verified!")

๐Ÿ› ๏ธ Best Practices

  1. ๐Ÿ“ฆ Use Modern Tools: Embrace pyproject.toml and build
  2. ๐Ÿ”„ Automate Everything: CI/CD for testing and releases
  3. ๐Ÿ“Š Version Semantically: Follow SemVer principles
  4. ๐Ÿ›ก๏ธ Security First: Sign packages and verify dependencies
  5. ๐Ÿ“– Document Thoroughly: README, CHANGELOG, and API docs
  6. ๐Ÿงช Test Extensively: Multiple Python versions and platforms
  7. ๐ŸŒ Support Widely: Consider different OS and architectures

๐Ÿงช Hands-On Exercise

๐ŸŽฏ Challenge: Create a Professional Package

Build a complete Python package with:

๐Ÿ“‹ Requirements:

  • โœ… Modern pyproject.toml configuration
  • ๐Ÿ”„ Automated GitHub Actions workflow
  • ๐Ÿ“Š Dynamic versioning from git tags
  • ๐Ÿ›ก๏ธ Package signing with GPG
  • ๐Ÿ“– Sphinx documentation
  • ๐Ÿงช 90%+ test coverage
  • ๐ŸŽจ Pre-commit hooks for quality

๐Ÿš€ Bonus Points:

  • Add multi-platform wheel building
  • Implement automatic changelog generation
  • Create a documentation site with Read the Docs

๐Ÿ’ก Solution

๐Ÿ” Click to see solution
# ๐ŸŽฏ Complete professional package setup!

# ๐Ÿ“ Project structure
professional_package/
โ”œโ”€โ”€ src/
โ”‚   โ””โ”€โ”€ pro_package/
โ”‚       โ”œโ”€โ”€ __init__.py
โ”‚       โ”œโ”€โ”€ __main__.py      # ๐ŸŽฎ CLI entry point
โ”‚       โ”œโ”€โ”€ core.py
โ”‚       โ”œโ”€โ”€ utils.py
โ”‚       โ””โ”€โ”€ py.typed         # ๐ŸŽฏ Type hints marker
โ”œโ”€โ”€ tests/
โ”‚   โ”œโ”€โ”€ conftest.py          # ๐Ÿงช Pytest configuration
โ”‚   โ”œโ”€โ”€ test_core.py
โ”‚   โ””โ”€โ”€ test_integration.py
โ”œโ”€โ”€ docs/
โ”‚   โ”œโ”€โ”€ conf.py
โ”‚   โ”œโ”€โ”€ index.rst
โ”‚   โ””โ”€โ”€ api.rst
โ”œโ”€โ”€ .github/
โ”‚   โ”œโ”€โ”€ workflows/
โ”‚   โ”‚   โ”œโ”€โ”€ test.yml         # ๐Ÿงช Test workflow
โ”‚   โ”‚   โ”œโ”€โ”€ publish.yml      # ๐Ÿš€ Release workflow
โ”‚   โ”‚   โ””โ”€โ”€ docs.yml         # ๐Ÿ“– Documentation workflow
โ”‚   โ””โ”€โ”€ dependabot.yml       # ๐Ÿ”„ Dependency updates
โ”œโ”€โ”€ .pre-commit-config.yaml  # ๐ŸŽจ Code quality hooks
โ”œโ”€โ”€ pyproject.toml
โ”œโ”€โ”€ MANIFEST.in
โ”œโ”€โ”€ LICENSE
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ CHANGELOG.md
โ””โ”€โ”€ tox.ini                  # ๐Ÿงช Multi-env testing

# ๐ŸŽจ pyproject.toml
[build-system]
requires = ["setuptools>=61.0", "setuptools-scm[toml]>=7.0"]
build-backend = "setuptools.build_meta"

[project]
name = "professional-package"
dynamic = ["version"]  # ๐Ÿ”„ Version from git
description = "A professional Python package example ๐Ÿš€"
readme = "README.md"
license = {text = "MIT"}
authors = [{name = "Pro Dev", email = "[email protected]"}]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: MIT License",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.8",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Typing :: Typed",
]
requires-python = ">=3.8"
dependencies = [
    "click>=8.0",
    "rich>=12.0",
    "pydantic>=2.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.0",
    "pytest-cov>=4.0",
    "pytest-asyncio>=0.20",
    "black>=23.0",
    "ruff>=0.0.270",
    "mypy>=1.0",
    "pre-commit>=3.0",
    "tox>=4.0",
]
docs = [
    "sphinx>=5.0",
    "sphinx-rtd-theme>=1.0",
    "sphinx-click>=4.0",
    "myst-parser>=0.18",
]

[project.scripts]
pro-cli = "pro_package.__main__:cli"

[project.urls]
Homepage = "https://github.com/prodev/professional-package"
Documentation = "https://professional-package.readthedocs.io"
Changelog = "https://github.com/prodev/professional-package/blob/main/CHANGELOG.md"

[tool.setuptools-scm]
write_to = "src/pro_package/_version.py"

[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "--cov=pro_package --cov-report=term-missing"

[tool.mypy]
python_version = "3.8"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true

[tool.ruff]
target-version = "py38"
select = ["E", "F", "UP", "B", "SIM", "I"]

# ๐Ÿงช tox.ini for multi-environment testing
[tox]
envlist = py{38,39,310,311}, docs, lint
isolated_build = True

[testenv]
deps = .[dev]
commands = pytest {posargs}

[testenv:docs]
deps = .[docs]
commands = sphinx-build -W -b html docs docs/_build

[testenv:lint]
deps = .[dev]
commands = 
    black --check src tests
    ruff check src tests
    mypy src

# ๐ŸŽฏ Complete implementation!
print("๐ŸŽ‰ Professional package ready for PyPI!")

๐ŸŽ“ Key Takeaways

Youโ€™ve learned so much! Hereโ€™s what you can now do:

  • โœ… Create professional packages with modern tools ๐Ÿ’ช
  • โœ… Automate releases with CI/CD pipelines ๐Ÿ›ก๏ธ
  • โœ… Sign and secure your distributions ๐ŸŽฏ
  • โœ… Manage complex dependencies like a pro ๐Ÿ›
  • โœ… Build platform-specific wheels for better performance ๐Ÿš€

Remember: Publishing to PyPI is about sharing your work with the world. Make it professional, secure, and user-friendly! ๐Ÿค

๐Ÿค Next Steps

Congratulations! ๐ŸŽ‰ Youโ€™ve mastered advanced PyPI publishing!

Hereโ€™s what to do next:

  1. ๐Ÿ’ป Create your first professional package
  2. ๐Ÿ—๏ธ Set up automated workflows for your projects
  3. ๐Ÿ“š Explore package documentation with Sphinx
  4. ๐ŸŒŸ Contribute to open source Python packages!

Remember: Every popular Python package started with someone learning to publish. Your package could be the next big thing! ๐Ÿš€


Happy packaging! ๐ŸŽ‰๐Ÿš€โœจ