pypuz is a Python library for reading, writing, and manipulating crossword puzzle files. It provides a common interface for interacting with several popular crossword formats.
- Multi-format Support: Read and write (or convert between) various crossword formats.
- Common Interface: Access metadata, grids, and clues through a unified object model.
- Automatic Numbering: Generates standard crossword numbering for grids.
- Clue Inference: Can reconstruct clue answers from the grid if they are missing in the source file.
- Rebus and Markup Support: Handles special cell types like rebuses and circles.
- .puz: The classic Across Lite format.
- .ipuz: The open, JSON-based format (v1).
- .jpz: The XML-based format used by many modern applications.
- .cfp: CrossFire project files.
- AmuseLabs: Supports loading from AmuseLabs JSON data.
pip install pypuzOr using Poetry:
poetry add pypuzThe easiest way to load a puzzle is using the load function, which automatically detects the format based on the file extension.
import pypuz
# Load any supported file type (.puz, .ipuz, .jpz, .xml, .cfp)
puzzle = pypuz.load('my_puzzle.puz')
# Access metadata
print(f"Title: {puzzle.metadata.title}")
print(f"Author: {puzzle.metadata.author}")You can also load specifically if needed (maintains backward compatibility):
from pypuz import Puzzle
puzzle = Puzzle().fromPuz('my_puzzle.puz')
puzzle = Puzzle().fromIPuz('my_puzzle.ipuz')# Access a specific cell
cell = puzzle.grid.cellAt(0, 0)
print(f"Solution at (0,0): {cell.solution}")
# Get the solution as a 2D array
arr = puzzle.grid.solutionArray()for cluelist in puzzle.clues:
print(f"\n{cluelist['title']}:")
for clue in cluelist['clues']:
print(f"{clue.number}. {clue.clue} -> {clue.answer}")# Save as .ipuz
puzzle.toIPuz('output.ipuz')
# Save as .puz (Note: this format is lossy)
puzzle.toPuz('output.puz')Tests are located in the tests/ directory and can be run using pytest:
# Run all tests
pytest
# Or using poetry
poetry run pytestTo install the package for development:
poetry installTo install locally from a build:
poetry build
pip install dist/pypuz-VERSION-py3-none-any.whlTo make a new release of pypuz:
- Merge to Main: Ensure all changes are merged into the
main(ormaster) branch. - Bump Version: Update the
versioninpyproject.tomland document changes inCHANGES.txt. - Create a Release and Tag:
- Option A: CLI:
git checkout main git pull origin main git tag -a v2026.3.7 -m "Release version 2026.3.7" git push origin main --tags - Option B: GitHub UI: Navigate to the "Releases" section of the repository, click "Draft a new release", and create a new tag (e.g.,
v2026.3.7) targeting themainbranch. Use the contents ofCHANGES.txtfor the release description.
- Option A: CLI:
- Publish to PyPI:
Regardless of how the Git tag is created, the package must be manually uploaded to PyPI (unless a GitHub Action is configured):
Note: PyPI authentication is independent of your local Git/GitHub user.
poetry build twine upload dist/*
MIT