Skip to content

Skip __pycache__ and hidden directories when loading parameter directories - #637

Open
anth-volk wants to merge 1 commit into
masterfrom
skip-pycache-parameter-directories
Open

anth-volk wants to merge 1 commit into
masterfrom
skip-pycache-parameter-directories

Conversation

@anth-volk

@anth-volk anth-volk commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #638

  • make format && make documentation has been run. (ruff format --check and ruff check were run on the changed files only; make documentation was not run.)

Bug fix

  • Regression test added
  • Regression test passing

What this fixes and how it's fixed

ParameterNode(directory_path=...) turns every subdirectory into a child node. EXCLUDED_PARAMETER_CHILD_NAMES already lists __pycache__, but only the YAML-file branch and the inline-data branch check it; the subdirectory branch does not. Once Python has written bytecode into a parameter directory that is also a Python package, the tree gains an empty <directory>.__pycache__ node.

policyengine-us 2.2.1 has six parameter directories that hold only an __init__.py and CSV files:

  • gov.hhs.medicaid.geography
  • gov.hud.fmr
  • gov.hud.income_limits
  • gov.hud.payment_standards
  • gov.states.fl.doe.sr.rates.reimbursement
  • gov.states.tx.twc.ccs.payment.rates_expanded_age_groups

US variable modules import these packages, so building the US system writes __pycache__ into them unless bytecode writing is off. Without the cache, each of these nodes has no children; with it, each has one empty __pycache__ child. policyengine.py skips parameter nodes that have no children, so its US parameter-node count changes by 6 depending on whether those caches are on disk. The Public API's v2 catalog takes its parameter nodes from policyengine.py, which is why its exact-count integration test reported 29,361 nodes on macOS with PYTHONDONTWRITEBYTECODE=1 and 29,367 elsewhere. The count follows the files on disk: with caches already written (for example by pip install's bytecode compilation or an earlier run), PYTHONDONTWRITEBYTECODE=1 still gives the higher count.

Change

  • When loading a parameter directory, skip subdirectories named __pycache__ and hidden subdirectories (names starting with ., such as .ipynb_checkpoints). A hidden directory name cannot form a valid dotted parameter name, and a Jupyter checkpoint directory would otherwise load duplicate copies of the parameters next to it.
  • reference is still excluded only as a YAML file name or data key, as before. A directory named reference still loads.

After this change, the loaded tree matches what loads when no bytecode cache exists.

Checked against policyengine-us 2.2.1 with policyengine-core 3.33.3 (the versions policyengine.py 6.11.1 pins) and this patch applied: 28,565 ParameterNodes, 28,559 of them with children, both with the nine __pycache__ directories under parameters/ on disk and with none. Without the patch, the run with caches had 28,574 and 28,565. policyengine-uk 2.132.6 has one package directory under parameters/ (gov.dwp.LHA), and it also holds YAML parameters, so UK counts in policyengine.py do not change.

Downstream effect: once policyengine.py bundles a release with this fix, the Public API's tests/integration/test_v2_catalog_installed.py will need parameter_nodes set to 29,361 instead of 29,367. The other counts in that test do not change.

Tests

  • New tests/core/parameters/test_parameter_directory_loading.py:
    • test_bytecode_cache_does_not_change_parameter_nodes builds a parameter directory with one YAML parameter and one package directory that holds only a CSV, loads it, writes the package's bytecode cache with py_compile, loads it again, and asserts the same node names both times and no children under the package node. Without the fix it fails because lookup.__pycache__ appears.
    • test_hidden_directories_are_not_loaded asserts that a .ipynb_checkpoints directory inside a parameter directory is not loaded. Without the fix it fails because .ipynb_checkpoints becomes a child node.
  • uv run pytest tests (Python 3.14, macOS): 2,716 passed, 4 skipped, 3 xfailed.
  • ruff format --check and ruff check on the changed files: pass.
  • policyengine-core test policyengine_core/country_template/tests -c policyengine_core.country_template: 39 passed.
  • Not run: mypy.

🤖 Generated with Claude Code

@anth-volk
anth-volk requested a review from MaxGhenis October 29, 2026 17:47
@anth-volk
anth-volk marked this pull request as ready for review October 29, 2026 17:55
@anth-volk
anth-volk force-pushed the skip-pycache-parameter-directories branch from 134734b to 6ab1d4f Compare October 30, 2026 12:54
@anth-volk
anth-volk changed the base branch from master to fix-yaml-runner-tests-pytest-9-2 October 30, 2026 12:54
@anth-volk
anth-volk added this pull request to stack #640 October 30, 2026 12:54
Base automatically changed from fix-yaml-runner-tests-pytest-9-2 to master October 30, 2026 13:03
The subdirectory branch of ParameterNode's directory loader never
checked EXCLUDED_PARAMETER_CHILD_NAMES, so a __pycache__ directory that
Python writes into a parameter directory that is also an imported
package became an empty child node. Whether that node existed depended
on whether bytecode had been written, which changed policyengine.py's
count of non-empty US parameter nodes by six.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@anth-volk
anth-volk force-pushed the skip-pycache-parameter-directories branch from 6ab1d4f to d4ff89c Compare October 30, 2026 13:03

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parameter loader turns __pycache__ directories into parameter nodes

1 participant