PolicyEngine / PolicyEngine/policyengine.py
Drop Python 3.9 support (cleanup checklist)
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 7
- Forks
- 9
- Avg merge
- 15h 51m
- Merged PRs (30d)
- 9
Description
Trigger
File when all confirmed 3.9 users (currently: Census) have migrated to 3.10+.
Background
Supporting 3.9 across the stack required working around non-trivial syntax and dependency cruft in four repos. ~95% of the cruft is 3.9-specific — dropping 3.9 alone recovers most of it, even if 3.10 support remains (3.10 hits EOL Oct 2026, ~6 months out, so keeping it through natural life is cheap).
Landed as: PolicyEngine/policyengine-core#454, PolicyEngine/policyengine-us#8035, PolicyEngine/policyengine-uk#1625, PolicyEngine/policyengine.py#278.
Checklist
All 4 repos
-
pyproject.toml: raiserequires-pythonfrom>=3.9to>=3.10 - Remove
Programming Language :: Python :: 3.9classifier - Remove
"3.9"from all CI Python matrices
policyengine-core (PolicyEngine/policyengine-core)
- Remove numpy env marker; go back to single
numpy>=2.1.0,<3(2.1+ supports 3.10+) - Hand-revert
Optional[X]/Tuple[X]→X | None/tuple[X]inpolicyengine_core/tools/hugging_face.pyandpolicyengine_core/tools/google_cloud.py(~5 sites; this repo's ruff config doesn't have UP rules enabled)
policyengine-us (PolicyEngine/policyengine-us)
- Remove
[tool.uv] environmentsblock inpyproject.tomlif it still exists (likely already gone once downstream core picks up 3.9-compat release) - Hand-revert
Optional[X]→X | Nonein:policyengine_us/system.py,data/economic_assumptions.py,data/dataset_schema.py,tests/core/test_payroll_contributions.py,tests/microsimulation/data/fixtures/test_extend_single_year_dataset.py(5 sites) - Regenerate
uv.lock
policyengine-uk (PolicyEngine/policyengine-uk)
- Remove
[tool.uv] environmentsblock (if still present) - Hand-revert 3 sites in
policyengine_uk/data/dataset_schema.pyandpolicyengine_uk/simulation.py -
policyengine_uk/tests/test_build_metadata.py: revertExitStackback to parenthesizedwith (a, b, c): -
[tool.ruff] target-version = "py39"→"py310" - Regenerate
uv.lock
policyengine.py (this repo)
-
pyproject.toml:[tool.ruff] target-version = "py39"→"py310"[tool.mypy] python_version = "3.9"→"3.10"- Remove
UP006,UP007,UP035,UP045from[tool.ruff.lint] ignore
- Auto-revert ~210 annotation sites:
ruff check --fix --unsafe-fixes .— this re-applies UP045 (Optional[X]→X | None), UP007 (Union[X, Y]→X | Y), UP006/UP035 (List→list). - Hand-revert the two discriminated-union sites ruff's UP rules don't cover:
src/policyengine/core/scoping_strategy.py:222(insideAnnotated[]) andsrc/policyengine/core/region.py:18(module-level type alias). - Simplify
Python-CompatCI job in.github/workflows/pr_code_changes.yaml— drop the explicith5pyinstall (needed becausescoping_strategy.pyimports it but extras weren't available; once[us]/[uk]extras are bumped to versions that pull h5py via core, it's redundant). - Bump
[us]/[uk]/[dev]extras offpolicyengine-us==1.602.0/policyengine-uk==2.74.0to versions that don't pin 3.11+ themselves (separate follow-up from this cleanup — may already be bumped by the time this issue is actioned).
Not in scope
Keep until 3.10 EOL (October 2026):
class Foo(str, Enum)pattern (4 files:outputs/{aggregate,change_aggregate,inequality,poverty}.py) — StrEnum is 3.11+timezone.utcincore/tax_benefit_model_version.py—datetime.UTCis 3.11+- Gotcha when
StrEnumreturns:str(Foo.X)differs —StrEnumreturns"x",(str, Enum)returns"Foo.X". Audit any code relying onstr()of enum members before reverting.
Keep until 3.12 EOL (October 2028):
TypeVar+Generic[T]pattern incore/cache.pyandcore/output.py— PEP 695class Foo[T]is 3.12+.
Verification
After cleanup, each repo's CI should be green with reduced matrix (3.10+). Cross-repo smoke: pip install policyengine[us] and pip install policyengine[uk] succeed on 3.10 in a fresh venv.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the four repositories' pyproject.toml files and CI matrices, then inspect the listed Python files and policyengine.py's Ruff and mypy configuration. Check the dependency versions and existing 3.9 compatibility work before changing conditional items. Done means all four repositories support Python 3.10+, their CI is green, and fresh 3.10 environments can install the us and uk extras.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- build-system, ci-cd, tooling
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100