# Building and Distributing Elytra PIM Client This guide explains how to build wheel distributions and upload them to PyPI or other package repositories. ## Project Version Current version: **0.1.0** (Development Release) The version is defined in `pyproject.toml` under `[project]` section. ## Build Tools ### Requirements - Python 3.9 or higher - pip with setuptools and wheel ### Build Dependencies Install build requirements: ```bash pip install -r build_requirements.txt ``` Or manually: ```bash pip install "setuptools>=65.0" "wheel>=0.38.0" "build>=0.10.0" ``` ## Building Wheels ### Option 1: Using Python Script (Recommended for All Platforms) ```bash # Activate virtual environment first .venv\Scripts\activate # Windows source .venv/bin/activate # macOS/Linux # Run the build script python build_wheel.py ``` This script will: - Clean previous build artifacts - Build wheel (`.whl`) and source (`.tar.gz`) distributions - Display the build results with file sizes - Show installation instructions ### Option 2: Using PowerShell Script (Windows) ```powershell # Activate virtual environment .\.venv\Scripts\Activate.ps1 # Run the build script .\build_wheel.ps1 # Clean and rebuild .\build_wheel.ps1 -Clean # Build and upload to PyPI .\build_wheel.ps1 -Upload ``` ### Option 3: Using Shell Script (macOS/Linux) ```bash # Activate virtual environment source .venv/bin/activate # Run the build script chmod +x build_wheel.sh # Make executable (first time only) ./build_wheel.sh # Clean and rebuild ./build_wheel.sh --clean # Build and upload to PyPI ./build_wheel.sh --upload ``` ### Option 4: Using Modern Build Tool Directly ```bash # Install build tool pip install build # Build wheel and sdist in one command python -m build # Build only wheel python -m build --wheel # Build only source distribution python -m build --sdist ``` ### Option 5: Using setuptools Directly ```bash # Create wheel only python setup.py bdist_wheel # Create both wheel and source distribution python setup.py sdist bdist_wheel ``` ## Build Output Distributions are created in the `dist/` directory: ``` dist/ ├── elytra_pim_client-0.1.0-py3-none-any.whl # Wheel distribution └── elytra_pim_client-0.1.0.tar.gz # Source distribution ``` ### Understanding the Wheel Filename `elytra_pim_client-0.1.0-py3-none-any.whl` - `elytra_pim_client` - Package name - `0.1.0` - Version - `py3` - Python version (3.x only) - `none` - No C extensions (pure Python) - `any` - Platform independent ## Installation from Built Wheel ### From Local File After building, install the wheel locally: ```bash pip install dist/elytra_pim_client-0.1.0-py3-none-any.whl ``` ### Editable Install During Development During development, use editable install so changes are reflected immediately: ```bash pip install -e . ``` Or with dev dependencies: ```bash pip install -e ".[dev]" ``` ## Uploading to Forgejo PyPI This project uses **Forgejo PyPI** for package distribution, not the public PyPI. Forgejo is a self-hosted Git service with integrated package registry support. ### Setup Forgejo PyPI #### Step 1: Create .pypirc Configuration Copy the example configuration: ```bash cp .pypirc.example .pypirc ``` Edit `.pypirc` with your Forgejo details: ```ini [distutils] index-servers = forgejo [forgejo] repository = https://your-forgejo-instance.com/api/packages/YOUR_USERNAME/pypi username = __token__ password = YOUR_ACCESS_TOKEN ``` #### Step 2: Generate Forgejo Personal Access Token 1. Visit your Forgejo instance: `https://your-forgejo-instance.com` 2. Go to: **User Settings** → **Applications** 3. Click **Create New Token** 4. Name it: `PyPI Upload` 5. Grant scope: **write:packages** 6. Copy the generated token 7. Paste into `.pypirc` as `password` #### Step 3: Secure .pypirc **IMPORTANT:** Add `.pypirc` to `.gitignore` to prevent committing credentials! ```bash echo ".pypirc" >> .gitignore git add .gitignore git commit -m "chore: add .pypirc to gitignore" ``` ### Uploading to Forgejo PyPI **Requirement:** twine must be installed (see Prerequisites section above) #### Option 1: Using PowerShell Script (Windows - Recommended) ```powershell # Activate virtual environment first .\.venv\Scripts\Activate.ps1 # Upload existing wheel .\upload_wheel_to_forgejo_pypi.ps1 # Rebuild and upload .\upload_wheel_to_forgejo_pypi.ps1 -Build # Show help .\upload_wheel_to_forgejo_pypi.ps1 -Help ``` #### Option 2: Using Batch Script (Windows) ```batch upload_wheel_to_forgejo_pypi.bat REM Rebuild and upload upload_wheel_to_forgejo_pypi.bat --build ``` #### Option 3: Using Shell Script (Unix/Linux) ```bash # Make script executable (first time only) chmod +x upload_wheel_to_forgejo_pypi.sh # Upload existing wheel ./upload_wheel_to_forgejo_pypi.sh # Rebuild and upload ./upload_wheel_to_forgejo_pypi.sh --build # Show help ./upload_wheel_to_forgejo_pypi.sh --help ``` #### Option 4: Using twine Directly ```bash # Activate virtual environment .venv\Scripts\activate # Windows source .venv/bin/activate # macOS/Linux # Upload wheel to Forgejo (twine is already in requirements.txt) twine upload -r forgejo dist/*.whl ``` ### What the Upload Scripts Do 1. **Load credentials** - Reads .pypirc configuration 2. **Setup environment** - Copies .pypirc to user home directory temporarily 3. **Activate venv** - Sets up Python virtual environment 4. **Build wheel** - Builds wheel if not present (or with --build flag) 5. **Upload** - Uploads wheel to Forgejo PyPI repository using twine 6. **Cleanup** - Removes temporary credentials from home directory 7. **Deactivate** - Deactivates virtual environment ### Accessing Your Package After upload, your package is available in the Forgejo PyPI repository: ```bash # Install from Forgejo PyPI pip install --index-url https://your-forgejo-instance.com/api/packages/YOUR_USERNAME/pypi/simple/ elytra-pim-client # Or add to requirements.txt -i https://your-forgejo-instance.com/api/packages/YOUR_USERNAME/pypi/simple/ elytra-pim-client ``` ### Troubleshooting Upload Issues #### "Upload failed" Error **Check:** Verify .pypirc configuration ```ini [forgejo] repository = https://correct-url.com/api/packages/USERNAME/pypi username = __token__ password = VALID_TOKEN ``` **Verify:** Token has correct permissions - Token must have `write:packages` scope - Visit: `https://your-forgejo-instance.com/user/settings/applications` **Network:** Ensure Forgejo instance is reachable ```bash curl https://your-forgejo-instance.com/api/v1/user ``` #### ".pypirc not found" Error Create it from template: ```bash cp .pypirc.example .pypirc # Then edit with your credentials ``` #### "twine: command not found" Error **Solution:** twine is included in `requirements.txt` as a development dependency. Install all dependencies: ```bash pip install -r requirements.txt ``` ### Example Workflow ```bash # 1. Setup Forgejo PyPI (first time only) cp .pypirc.example .pypirc # Edit .pypirc with your Forgejo repository URL and credentials echo ".pypirc" >> .gitignore git add .gitignore git commit -m "chore: add .pypirc to gitignore" # 2. Make code changes git commit -am "feat: add new feature" # 3. Update version in pyproject.toml # version = "0.2.0" # 4. Build and upload to Forgejo PyPI .\upload_wheel_to_forgejo_pypi.ps1 # PowerShell # or ./upload_wheel_to_forgejo_pypi.sh # Bash/Shell # or ./upload_wheel_to_forgejo_pypi.bat # Batch # 5. Tag and push release git tag v0.2.0 git push origin v0.2.0 ``` ## Uploading to Public PyPI (Future) To upload to public PyPI instead of Forgejo: 1. Install twine: `pip install twine` 2. Create account at https://pypi.org/ 3. Generate token at https://pypi.org/manage/account/tokens/ 4. Create `.pypirc`: ```ini [distutils] index-servers = pypi [pypi] repository = https://upload.pypi.org/legacy/ username = __token__ password = pypi_your_token_here ``` 5. Upload: `twine upload -r pypi dist/*.whl` ## Versioning ### Version Format Follow PEP 440 versioning: ``` Major.Minor.Patch (e.g., 0.1.0) Major.Minor.Patch.preN (e.g., 0.1.0.pre1) Major.Minor.Patch.postN (e.g., 0.1.0.post1) Major.Minor.Patch.devN (e.g., 0.1.0.dev1) ``` ### Updating Version Edit `pyproject.toml`: ```toml [project] name = "elytra-pim-client" version = "0.2.0" # Update version here ``` ## Automatic Build Validation Before building, scripts automatically: 1. Remove old build artifacts 2. Clean `dist/`, `build/`, and `.egg-info` directories 3. Verify build dependencies 4. Validate Python version compatibility 5. Check that distributions were created ## Continuous Integration ### GitHub Actions Example ```yaml name: Build Distribution on: release: types: [created] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: '3.11' - run: pip install -r build_requirements.txt - run: python build_wheel.py - uses: actions/upload-artifact@v3 with: name: dist path: dist/ upload: needs: build runs-on: ubuntu-latest steps: - uses: actions/download-artifact@v3 with: name: dist path: dist/ - uses: pypa/gh-action-pypi-publish@release/v1 ``` ## Troubleshooting ### Build Fails with "No module named 'build'" ```bash pip install build python build_wheel.py ``` ### "setuptools not found" ```bash pip install setuptools>=65.0 ``` ### Permission Denied (Unix/Linux) Make build script executable: ```bash chmod +x build_wheel.sh ``` ### "twine: command not found" ```bash pip install twine python -m twine upload dist/* ``` ### Wheel not in dist/ Check that `pyproject.toml` exists and is valid: ```bash python -m build --verbose ``` ## File Structure ``` elytra_client/ ├── build_wheel.py # Python build script (all platforms) ├── build_wheel.ps1 # PowerShell build script (Windows) ├── build_wheel.sh # Shell build script (Unix/Linux) ├── upload_wheel_to_forgejo_pypi.bat # Batch upload script (Windows) ├── upload_wheel_to_forgejo_pypi.ps1 # PowerShell upload script (Windows) ├── upload_wheel_to_forgejo_pypi.sh # Shell upload script (Unix/Linux) ├── .pypirc.example # Forgejo PyPI configuration template ├── .pypirc # Forgejo PyPI credentials (in .gitignore!) ├── build_requirements.txt # Build dependencies ├── setup.py # Setup configuration (legacy compatibility) ├── pyproject.toml # Modern build configuration (PEP 517/518) └── dist/ # Output directory for distributions ├── elytra_pim_client-0.1.0-py3-none-any.whl └── elytra_pim_client-0.1.0.tar.gz ``` ## Best Practices 1. **Setup Forgejo PyPI (first time only)** ```bash cp .pypirc.example .pypirc # Edit .pypirc with your Forgejo credentials echo ".pypirc" >> .gitignore ``` 2. **Complete release workflow** ```bash # Update version in pyproject.toml # version = "0.2.0" # Build and upload .\upload_wheel_to_forgejo_pypi.ps1 # Tag and push git tag v0.2.0 git push origin v0.2.0 ``` 3. **Increment version for each release** - Patch: Bug fixes (0.1.1) - Minor: New features (0.2.0) - Major: Breaking changes (1.0.0) 4. **Clean before rebuilding** ```bash python build_wheel.py # Automatically cleans # Or manually rm -rf dist/ build/ *.egg-info/ ``` 5. **Keep dependencies minimal** - Only required packages in `dependencies` - Development tools in `[project.optional-dependencies]` 6. **Use .pypirc template** - Never commit `.pypirc` with real credentials - Always keep `.pypirc` in `.gitignore` - Share `.pypirc.example` with template values 7. **Secure credential handling** - Use Forgejo personal access tokens with limited scope - Rotate tokens regularly - Never share tokens or .pypirc files ## Resources - [Forgejo Documentation](https://docs.forgejo.org/) - [Forgejo PyPI Package Registry](https://docs.forgejo.org/en/latest/usage/packages/pypi/) - [Python Packaging Guide](https://packaging.python.org/) - [PEP 517 - Build System Interface](https://www.python.org/dev/peps/pep-0517/) - [PEP 518 - pyproject.toml](https://www.python.org/dev/peps/pep-0518/) - [PEP 440 - Version Identification](https://www.python.org/dev/peps/pep-0440/) - [setuptools Documentation](https://setuptools.pypa.io/) - [twine Documentation](https://twine.readthedocs.io/)