Publishing Guide¶
This guide covers how to package, distribute, and publish your content pack for others to use.
Preparing for Publication¶
Project Structure¶
Ensure your project follows the standard structure:
my-content-pack/
src/
my_content_pack/
__init__.py
pack.py
components/
systems/
commands/
events/
py.typed # Type hint marker
tests/
__init__.py
conftest.py
test_*.py
pyproject.toml
README.md
LICENSE
CHANGELOG.md
Complete pyproject.toml¶
[project]
name = "maid-my-content-pack"
version = "1.0.0"
description = "My custom content pack for MAID"
readme = "README.md"
license = {text = "MIT"}
requires-python = ">=3.12"
authors = [
{name = "Your Name", email = "you@example.com"},
]
keywords = ["maid", "mud", "game", "plugin"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3.12",
"Topic :: Games/Entertainment :: Multi-User Dungeons (MUD)",
]
dependencies = [
"maid-engine>=0.1.0",
"maid-stdlib>=0.1.0",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0",
"pytest-asyncio>=0.23",
"pytest-cov>=4.0",
"ruff>=0.3",
"mypy>=1.9",
]
[project.urls]
Homepage = "https://github.com/user/maid-my-content-pack"
Documentation = "https://github.com/user/maid-my-content-pack#readme"
Repository = "https://github.com/user/maid-my-content-pack"
Issues = "https://github.com/user/maid-my-content-pack/issues"
[project.entry-points."maid.content_packs"]
my-content-pack = "my_content_pack:MyContentPack"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/my_content_pack"]
[tool.ruff]
line-length = 100
target-version = "py312"
[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B", "C4", "SIM"]
[tool.mypy]
python_version = "3.12"
strict = true
README.md¶
Write a comprehensive README:
# My Content Pack for MAID
A content pack that adds [feature description] to MAID.
## Features
- Feature 1: Description
- Feature 2: Description
- Feature 3: Description
## Installation
```bash
pip install maid-my-content-pack
Quick Start¶
from maid_engine.core.engine import GameEngine
from maid_stdlib.pack import StdlibContentPack
from my_content_pack import MyContentPack
engine = GameEngine(settings)
engine.load_content_pack(StdlibContentPack())
engine.load_content_pack(MyContentPack())
await engine.start()
Commands¶
| Command | Description | Usage |
|---|---|---|
mycommand |
Does something | mycommand <arg> |
Configuration¶
Set these environment variables:
Requirements¶
- MAID Engine >= 0.1.0
- MAID Stdlib >= 0.1.0
- Python >= 3.12
License¶
MIT License - see LICENSE file
### CHANGELOG.md
Maintain a changelog:
```markdown
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [1.0.0] - 2024-01-15
### Added
- Initial release
- Feature A with commands X, Y, Z
- System for handling ...
- Events: EventA, EventB
### Changed
- N/A
### Fixed
- N/A
LICENSE¶
Include a license file. MIT is common for open source:
MIT License
Copyright (c) 2024 Your Name
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Quality Checks¶
Run Tests¶
Run Linting¶
Run Type Checking¶
Pre-commit Checks¶
Consider using pre-commit hooks:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.3.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.9.0
hooks:
- id: mypy
additional_dependencies: [maid-engine, maid-stdlib]
Building the Package¶
Using Hatch¶
# Build wheel and source distribution
hatch build
# Output in dist/
# - maid_my_content_pack-1.0.0-py3-none-any.whl
# - maid_my_content_pack-1.0.0.tar.gz
Using Build¶
Publishing to PyPI¶
Test PyPI First¶
Test your package on TestPyPI before publishing to PyPI:
# Create account on https://test.pypi.org/
# Upload to TestPyPI
pip install twine
twine upload --repository testpypi dist/*
# Test installation
pip install --index-url https://test.pypi.org/simple/ maid-my-content-pack
Publish to PyPI¶
# Create account on https://pypi.org/
# Create API token at https://pypi.org/manage/account/
# Upload
twine upload dist/*
# Or configure token in ~/.pypirc
# [pypi]
# username = __token__
# password = pypi-...
Using GitHub Actions¶
Automate publishing with GitHub Actions:
# .github/workflows/publish.yml
name: Publish to PyPI
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: |
pip install hatch twine
- name: Build package
run: hatch build
- name: Publish to PyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: twine upload dist/*
Entry Point Discovery¶
MAID discovers content packs through Python entry points:
After installation, MAID can auto-discover your pack:
from maid_engine.plugins.loader import discover_content_packs
# Automatically finds installed packs
packs = discover_content_packs(use_entry_points=True)
Versioning¶
Follow semantic versioning:
- MAJOR (1.0.0 -> 2.0.0): Breaking changes
- Removed commands or events
- Changed API signatures
-
Incompatible data format changes
-
MINOR (1.0.0 -> 1.1.0): New features, backward compatible
- New commands, systems, events
- New optional parameters
-
New components
-
PATCH (1.0.0 -> 1.0.1): Bug fixes, backward compatible
- Bug fixes
- Performance improvements
- Documentation updates
Version Bumping¶
Update version in pyproject.toml:
And in your manifest:
@property
def manifest(self) -> ContentPackManifest:
return ContentPackManifest(
name="my-content-pack",
version="1.1.0", # Keep in sync
...
)
Documentation¶
API Documentation¶
Document your public API:
class MyContentPack(BaseContentPack):
"""My content pack for MAID.
This pack provides:
- Combat enhancements with tactical positioning
- New magic spells and effects
- Quest system integration
Example:
>>> from my_content_pack import MyContentPack
>>> engine.load_content_pack(MyContentPack())
Attributes:
None (uses BaseContentPack defaults)
Environment Variables:
MAID_MY_PACK__ENABLED: Enable/disable the pack (default: true)
MAID_MY_PACK__DEBUG: Enable debug logging (default: false)
"""
Generate API Docs¶
Use tools like mkdocs with mkdocstrings:
Distribution Channels¶
PyPI¶
The primary distribution channel for Python packages.
GitHub Releases¶
Create releases with: - Pre-built wheels - Source archives - Release notes
Direct Installation¶
Users can install directly from GitHub:
Maintenance¶
Responding to Issues¶
- Triage issues promptly
- Use labels for organization
- Link related issues
Accepting Contributions¶
Add a CONTRIBUTING.md:
# Contributing
## Development Setup
1. Clone the repository
2. Install with dev dependencies: `uv sync --all-extras`
3. Run tests: `uv run pytest`
## Pull Request Process
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests
5. Update documentation
6. Submit PR
## Code Style
- Follow existing code style
- Use type hints
- Write docstrings
- Keep tests passing
Deprecation Policy¶
When deprecating features:
import warnings
def old_function():
"""Deprecated: Use new_function instead."""
warnings.warn(
"old_function is deprecated, use new_function instead",
DeprecationWarning,
stacklevel=2,
)
return new_function()
Checklist¶
Before publishing:
- [ ] All tests pass
- [ ] Code is linted and formatted
- [ ] Type hints are complete
- [ ] Documentation is up to date
- [ ] README is comprehensive
- [ ] CHANGELOG is updated
- [ ] Version is bumped appropriately
- [ ] LICENSE file is present
- [ ] Entry points are configured
- [ ] Package builds successfully
- [ ] Test installation works
Next Steps¶
- Content Pack Overview - Review best practices
- Testing Guide - Ensure thorough testing
- MAID Documentation - Main documentation