|
| 1 | +WordLoom Contributor Guide |
| 2 | + |
| 3 | +# Quick Reference |
| 4 | + |
| 5 | +## Daily Development |
| 6 | + |
| 7 | +```bash |
| 8 | +# Install in current virtualenv |
| 9 | +uv pip install -U . |
| 10 | + |
| 11 | +# Run tests |
| 12 | +pytest test/ -v |
| 13 | + |
| 14 | +# Run specific test file |
| 15 | +pytest test/test_basics.py -v |
| 16 | + |
| 17 | +# Run linting |
| 18 | +ruff check . |
| 19 | + |
| 20 | +# Auto-fix linting issues |
| 21 | +ruff check --fix . |
| 22 | + |
| 23 | +# Run tests with coverage |
| 24 | +pytest test/ --cov=wordloom --cov-report=html |
| 25 | +``` |
| 26 | + |
| 27 | +## Making Changes |
| 28 | + |
| 29 | +```bash |
| 30 | +# After editing any Python files in pylib/ |
| 31 | +uv pip install -U . |
| 32 | + |
| 33 | +# After editing resources/ |
| 34 | +uv pip install -U . |
| 35 | + |
| 36 | +# After editing tests only (no reinstall needed) |
| 37 | +pytest test/ -v |
| 38 | +``` |
| 39 | + |
| 40 | +## Useful Commands |
| 41 | + |
| 42 | +```bash |
| 43 | +# See package structure after install |
| 44 | +python -c "import wordloom, os; print(os.path.dirname(wordloom.__file__))" |
| 45 | +ls -la $(python -c "import wordloom, os; print(os.path.dirname(wordloom.__file__))") |
| 46 | + |
| 47 | +# Check what files are in the installed package |
| 48 | +pip show -f wordloom |
| 49 | + |
| 50 | +# Check installed version |
| 51 | +python -c "import wordloom; print(wordloom.__version__)" |
| 52 | + |
| 53 | +# Compare source version |
| 54 | +cat pylib/__about__.py |
| 55 | + |
| 56 | +# Uninstall completely |
| 57 | +pip uninstall wordloom -y |
| 58 | + |
| 59 | +# Clean build artifacts |
| 60 | +rm -rf build/ dist/ *.egg-info |
| 61 | +rm -rf .pytest_cache .ruff_cache |
| 62 | +find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true |
| 63 | +``` |
| 64 | + |
| 65 | +## Testing Package Build Locally |
| 66 | + |
| 67 | +```bash |
| 68 | +# Build locally |
| 69 | +python -m build |
| 70 | +python -m build -w # For some reason needs to need both, in this order. Probably an issue in how we're using hatch |
| 71 | + |
| 72 | +# Test the built wheel |
| 73 | +pip install dist/wordloom-0.X.Y-py3-none-any.whl --force-reinstall |
| 74 | + |
| 75 | +# Check package contents |
| 76 | +unzip -l dist/wordloom-0.X.Y-py3-none-any.whl |
| 77 | +``` |
| 78 | + |
| 79 | +# Project Structure |
| 80 | + |
| 81 | +``` |
| 82 | +WordLoom/ |
| 83 | +├── pylib/ # Source code (becomes 'wordloom' package) |
| 84 | +│ ├── __init__.py |
| 85 | +│ ├── __about__.py # Version info |
| 86 | +│ └── wordloom.py # Main implementation |
| 87 | +├── resources/ # Bundled resources |
| 88 | +│ └── wordloom/ |
| 89 | +│ └── sample.toml |
| 90 | +├── test/ # Tests |
| 91 | +│ ├── test_basics.py |
| 92 | +│ ├── test_i18n_integration.py |
| 93 | +│ └── test_openai_integration.py |
| 94 | +├── pyproject.toml # Project config |
| 95 | +└── README.md |
| 96 | +
|
| 97 | +When installed, becomes: |
| 98 | +site-packages/ |
| 99 | +└── wordloom/ |
| 100 | + ├── __init__.py |
| 101 | + ├── __about__.py |
| 102 | + ├── wordloom.py |
| 103 | + └── resources/ |
| 104 | + └── wordloom/ |
| 105 | + └── sample.toml |
| 106 | +``` |
| 107 | + |
| 108 | +When installed, becomes: |
| 109 | + |
| 110 | +``` |
| 111 | +site-packages/ |
| 112 | +└── wordloom/ |
| 113 | + ├── __init__.py |
| 114 | + ├── __about__.py |
| 115 | + ├── wordloom.py |
| 116 | + └── resources/ |
| 117 | + └── wordloom/ |
| 118 | + └── sample.toml |
| 119 | +``` |
| 120 | + |
| 121 | +## Key Files |
| 122 | + |
| 123 | +- `pylib/__about__.py` - Version number (update for releases) |
| 124 | +- `pyproject.toml` - Dependencies, metadata, build config |
| 125 | +- `resources/wordloom/sample.toml` - Sample file used by tests |
| 126 | +- `README.md` - Main documentation |
| 127 | +- `wordloom_spec.md` - Format specification (CC BY 4.0) |
| 128 | + |
| 129 | +# Publishing a Release |
| 130 | + |
| 131 | +Before creating a release: |
| 132 | + |
| 133 | +- [ ] Update version in `pylib/__about__.py` |
| 134 | +- [ ] Update CHANGELOG.md |
| 135 | +- [ ] Run tests locally: `pytest test/ -v` |
| 136 | +- [ ] Run linting: `ruff check .` |
| 137 | +- [ ] Commit and push all changes |
| 138 | +<!-- |
| 139 | +- [ ] Create git tag: `git tag v0.X.Y` |
| 140 | +- [ ] Push tag: `git push origin v0.X.Y` |
| 141 | + --> |
| 142 | +- [ ] [Create GitHub release](https://github.com/OoriData/WordLoom/releases/new) (triggers publish workflow) |
| 143 | +- [ ] Verify package update on PyPI: https://pypi.org/project/wordloom/ |
| 144 | + |
| 145 | +## Testing the Package |
| 146 | + |
| 147 | +After publishing, test the installation: |
| 148 | + |
| 149 | +```bash |
| 150 | +# Create a fresh virtual environment |
| 151 | +python -m venv test_env |
| 152 | +source test_env/bin/activate # On Windows: test_env\Scripts\activate |
| 153 | + |
| 154 | +# Install from PyPI |
| 155 | +pip install wordloom |
| 156 | + |
| 157 | +# Test import |
| 158 | +python -c "import wordloom; print(wordloom.__version__)" |
| 159 | + |
| 160 | +# Test basic functionality |
| 161 | +python -c " |
| 162 | +import wordloom |
| 163 | +import io |
| 164 | +
|
| 165 | +toml_data = b''' |
| 166 | +lang = 'en' |
| 167 | +[test] |
| 168 | +_ = 'Hello' |
| 169 | +''' |
| 170 | +
|
| 171 | +loom = wordloom.load(io.BytesIO(toml_data)) |
| 172 | +print(loom['test']) |
| 173 | +" |
| 174 | +``` |
| 175 | + |
| 176 | +# Initial Project Setup |
| 177 | + |
| 178 | +Historical, and to inform maintenance. GitHub Actions & PyPI publishing. |
| 179 | + |
| 180 | +## GitHub Actions Setup |
| 181 | + |
| 182 | +The repository includes two workflows: |
| 183 | + |
| 184 | +### 1. CI Workflow (`.github/workflows/main.yml`) |
| 185 | + |
| 186 | +Runs automatically on every push and pull request. It: |
| 187 | +- Tests on Python 3.12 and 3.13 |
| 188 | +- Runs ruff linting |
| 189 | +- Runs pytest test suite |
| 190 | + |
| 191 | +### 2. Publish Workflow (`.github/workflows/publish.yml`) |
| 192 | + |
| 193 | +Runs when you create a new GitHub release. It builds and publishes to PyPI. |
| 194 | + |
| 195 | +## PyPI Trusted Publishing Setup |
| 196 | + |
| 197 | +### PyPI Setup |
| 198 | + |
| 199 | +- Login your [PyPI](https://pypi.org) account |
| 200 | +- For new package: |
| 201 | + - Go to: https://pypi.org/manage/account/publishing/ |
| 202 | + - Click "Add a new pending publisher" |
| 203 | + - Fill in: |
| 204 | + - **PyPI Project Name**: `wordloom` (must match `name` in `pyproject.toml`, with case) |
| 205 | + - **Owner**: `OoriData` |
| 206 | + - **Repository name**: `WordLoom` |
| 207 | + - **Workflow name**: `publish.yml` |
| 208 | + - **Environment name**: `pypi` (PyPI's recommended name) |
| 209 | +- If the package already exists on PyPI: |
| 210 | + - Go to the project page: https://pypi.org/manage/project/wordloom/settings/publishing/ |
| 211 | + - Add the publisher configuration as above |
| 212 | + |
| 213 | +### GitHub Setup |
| 214 | +- Go to: https://github.com/OoriData/WordLoom/settings/environments |
| 215 | +- Click "New environment" |
| 216 | +- Name: `pypi` |
| 217 | +- Click "Configure environment" |
| 218 | +- (Optional) Add protection rules: |
| 219 | + - Required reviewers: Add yourself to require manual approval before publishing |
| 220 | + - Wait timer: Add a delay (e.g., 5 minutes) before publishing |
| 221 | +- Click "Save protection rules" |
| 222 | + |
| 223 | +### Note on using the environment name |
| 224 | + |
| 225 | +Using an environment name (`pypi`) adds an extra layer of protection, with rules such as required reviewers (manual approval before publishing), wait timers (delay before publishing) and branch restrictions. Without an environment stipulation the workflow runs automatically when a release is created. |
| 226 | + |
| 227 | +## First Time Publishing |
| 228 | + |
| 229 | +Option on the very first release to PyPI: may want to do a manual publish to ensure everything is set up correctly: |
| 230 | + |
| 231 | +```bash |
| 232 | +# Install build tools |
| 233 | +pip install build twine |
| 234 | + |
| 235 | +# Build the package |
| 236 | +python -m build |
| 237 | + |
| 238 | +# For some reason, the wheel only seems to work if you build first without then with `-w` |
| 239 | +python -m build -w |
| 240 | + |
| 241 | +# Basic build check |
| 242 | +twine check dist/* |
| 243 | + |
| 244 | +# Extra checking |
| 245 | +VERSION=0.10.0 pip install --force-reinstall -U dist/wordloom-$VERSION-py3-none-any.whl |
| 246 | +python -c "from wordloom import load" |
| 247 | + |
| 248 | +# Upload to Test PyPI first (optional but recommended) |
| 249 | +twine upload --repository testpypi dist/* |
| 250 | +# Username: __token__ |
| 251 | +# Password: your-test-pypi-token |
| 252 | + |
| 253 | +# If test looks good, upload to real PyPI |
| 254 | +twine upload dist/* |
| 255 | +# Username: __token__ |
| 256 | +# Password: your-pypi-token |
| 257 | +``` |
| 258 | + |
| 259 | +After the first manual upload, you can use trusted publishing for all future releases. |
| 260 | + |
| 261 | +## Troubleshooting |
| 262 | + |
| 263 | +### "Project name 'wordloom' is not valid" |
| 264 | +- Check that the name in `pyproject.toml` matches exactly |
| 265 | +- Names are case-insensitive but must match what you registered on PyPI |
| 266 | + |
| 267 | +### "Invalid or non-existent authentication information" |
| 268 | +- For trusted publishing: Double-check the repository name, owner, and workflow name |
| 269 | +- For token auth: Make sure the token is saved as `PYPI_API_TOKEN` in GitHub secrets |
| 270 | + |
| 271 | +### Workflow fails with "Resource not accessible by integration" |
| 272 | +- Make sure the workflow has `id-token: write` permission |
| 273 | +- Check that the repository settings allow GitHub Actions |
| 274 | + |
| 275 | +### Package version already exists |
| 276 | +- You can't overwrite versions on PyPI |
| 277 | +- Increment the version in `pylib/__about__.py` and create a new release |
| 278 | + |
| 279 | +## Additional Resources |
| 280 | + |
| 281 | +- [PyPI Trusted Publishing Guide](https://docs.pypi.org/trusted-publishers/) |
| 282 | +- [GitHub Actions for Python](https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python) |
| 283 | +- [Python Packaging Guide](https://packaging.python.org/en/latest/) |
0 commit comments