PyPI Repository Guide
Artifact Keeper provides a PEP 503-compliant Simple Repository API for hosting Python packages.
Endpoint
PyPI operations use the /pypi endpoint:
http://localhost:8080/pypiThis endpoint implements the PEP 503 Simple Repository API.
Configuration
pip.conf
Configure pip to use Artifact Keeper as the package index.
Linux/macOS
Create or edit ~/.config/pip/pip.conf:
[global]index-url = http://localhost:8080/pypi/simpletrusted-host = localhostWindows
Create or edit %APPDATA%\pip\pip.ini:
[global]index-url = http://localhost:8080/pypi/simpletrusted-host = localhostProject-Level Configuration
Create pip.conf in your project root:
[global]index-url = http://localhost:8080/pypi/simpletrusted-host = localhostEnvironment Variable
Set index URL via environment variable:
export PIP_INDEX_URL=http://localhost:8080/pypi/simpleexport PIP_TRUSTED_HOST=localhostInstalling Packages
Install from Artifact Keeper
pip install my-packageInstall Specific Version
pip install my-package==1.0.0pip install my-package>=1.0.0pip install my-package~=1.0.0Install from Command Line
Override index URL for a single command:
pip install --index-url http://localhost:8080/pypi/simple my-packageInstall with Requirements File
pip install -r requirements.txtWith custom index in requirements.txt:
--index-url http://localhost:8080/pypi/simple--trusted-host localhost
my-package==1.0.0another-package>=2.0.0Publishing Packages
Prepare Your Package
Ensure you have a proper package structure:
my-package/├── pyproject.toml├── setup.py (or setup.cfg)├── README.md├── LICENSE└── my_package/ └── __init__.pypyproject.toml
[build-system]requires = ["setuptools>=61.0", "wheel"]build-backend = "setuptools.build_meta"
[project]name = "my-package"version = "1.0.0"description = "My awesome package"authors = [{name = "Your Name", email = "you@example.com"}]license = {text = "MIT"}readme = "README.md"requires-python = ">=3.8"dependencies = [ "requests>=2.28.0",]
[project.urls]Homepage = "https://github.com/yourusername/my-package"Repository = "https://github.com/yourusername/my-package"Build Distribution
# Install build toolspip install build
# Build wheel and source distributionpython -m buildThis creates files in dist/:
my_package-1.0.0-py3-none-any.whl(wheel)my-package-1.0.0.tar.gz(source distribution)
Upload with twine
Install twine:
pip install twineConfigure .pypirc
Create ~/.pypirc:
[distutils]index-servers = artifact-keeper
[artifact-keeper]repository = http://localhost:8080/pypiusername = your-usernamepassword = your-passwordUpload Package
twine upload --repository artifact-keeper dist/*Or specify repository URL directly:
twine upload \ --repository-url http://localhost:8080/pypi \ --username your-username \ --password your-password \ dist/*Upload Specific Files
twine upload --repository artifact-keeper dist/my_package-1.0.0-py3-none-any.whlMultiple Indexes
Fallback to PyPI
Use Artifact Keeper as primary, fallback to PyPI:
[global]index-url = http://localhost:8080/pypi/simpleextra-index-url = https://pypi.org/simpleOr via command line:
pip install \ --index-url http://localhost:8080/pypi/simple \ --extra-index-url https://pypi.org/simple \ my-packageMultiple Private Indexes
[global]index-url = http://localhost:8080/pypi/simpleextra-index-url = http://team-registry:8080/pypi/simple http://prod-registry:8080/pypi/simpleAuthentication
Basic Authentication
Include credentials in URL:
pip install --index-url http://username:password@localhost:8080/pypi/simple my-packageToken Authentication
Use API token instead of password:
[artifact-keeper]repository = http://localhost:8080/pypiusername = __token__password = your-api-tokenKeyring Support
Store credentials securely using keyring:
pip install keyring
keyring set http://localhost:8080/pypi usernamePoetry Support
Artifact Keeper works seamlessly with Poetry.
Configure Poetry
poetry config repositories.artifact-keeper http://localhost:8080/pypi
poetry config http-basic.artifact-keeper username passwordInstall with Poetry
poetry add my-package --source artifact-keeperPublish with Poetry
poetry publish --repository artifact-keeperpyproject.toml Configuration
[[tool.poetry.source]]name = "artifact-keeper"url = "http://localhost:8080/pypi/simple"priority = "primary"
[[tool.poetry.source]]name = "pypi"priority = "supplemental"PDM Support
Configure PDM
pdm config pypi.url http://localhost:8080/pypi/simpleInstall with PDM
pdm add my-packagePublish with PDM
pdm publish --repository http://localhost:8080/pypiIntegration with CI/CD
GitHub Actions
name: Publish Python Packageon: push: tags: - 'v*'
jobs: publish: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- uses: actions/setup-python@v5 with: python-version: '3.11'
- name: Install dependencies run: | pip install build twine
- name: Build package run: python -m build
- name: Publish to Artifact Keeper env: TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} TWINE_REPOSITORY_URL: http://registry.example.com/pypi run: twine upload dist/*GitLab CI
publish: image: python:3.11 stage: deploy script: - pip install build twine - python -m build - twine upload --repository-url $PYPI_REPOSITORY_URL -u $PYPI_USERNAME -p $PYPI_PASSWORD dist/* only: - tagsJenkins Pipeline
pipeline { agent any
stages { stage('Build and Publish') { steps { sh ''' python -m venv venv . venv/bin/activate pip install build twine python -m build twine upload \ --repository-url http://registry.example.com/pypi \ -u $PYPI_USERNAME \ -p $PYPI_PASSWORD \ dist/* ''' } } }}Package Versioning
Semantic Versioning
Follow PEP 440 version scheme:
"1.0.0"
# Pre-release versions"1.0.0a1" # Alpha"1.0.0b1" # Beta"1.0.0rc1" # Release Candidate
# Post-release"1.0.0.post1"
# Development release"1.0.0.dev1"Version Constraints
In requirements.txt or pyproject.toml:
# Exact versionmy-package==1.0.0
# Compatible release (>= 1.0.0, < 2.0.0)my-package~=1.0.0
# Minimum versionmy-package>=1.0.0
# Version rangemy-package>=1.0.0,<2.0.0
# Exclude specific versionsmy-package!=1.0.1Advanced Features
Source Distributions vs Wheels
Upload both for maximum compatibility:
# Build bothpython -m build
# Upload bothtwine upload dist/*Platform-Specific Wheels
Build platform-specific wheels:
# Build for specific platformpython -m build --wheel --config-setting="--plat-name=linux_x86_64"Hash Verification
pip automatically verifies package hashes from the repository.
Generate hashes for requirements:
pip hash my-package-1.0.0-py3-none-any.whlUse in requirements.txt:
my-package==1.0.0 \ --hash=sha256:abc123...Troubleshooting
SSL Certificate Errors
For HTTPS registries with self-signed certificates:
[global]trusted-host = localhostcert = /path/to/certificate.pemUpload Failures
Check package metadata:
twine check dist/*Enable verbose output:
twine upload --verbose dist/*Installation Issues
Clear pip cache:
pip cache purgeDebug installation:
pip install --verbose my-packageVersion Conflicts
List installed packages:
pip listpip show my-packageForce reinstall:
pip install --force-reinstall my-packageBest Practices
Package Metadata
Include comprehensive metadata in pyproject.toml:
[project]name = "my-package"version = "1.0.0"description = "Short description"readme = "README.md"license = {text = "MIT"}authors = [{name = "Your Name", email = "you@example.com"}]keywords = ["keyword1", "keyword2"]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",]MANIFEST.in
Control which files are included in source distributions:
include README.mdinclude LICENSErecursive-include my_package/data *exclude .gitignoreexclude .env.gitignore
dist/build/*.egg-info/__pycache__/.pytest_cache/.venv/See Also
- Security Scanning - Automatic vulnerability scanning for Python packages
- Security Policies - Configure policies to block vulnerable packages