idfkit 1.2.0__tar.gz → 1.3.0rc1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- idfkit-1.3.0rc1/.github/workflows/check-identity.yml +12 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.github/workflows/conformance.yml +1 -1
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.github/workflows/main.yml +49 -1
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.github/workflows/rehearse-all.yml +4 -1
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/CHANGELOG.md +238 -1
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/CLAUDE.md +6 -4
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/Makefile +2 -2
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/PKG-INFO +39 -21
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/README.md +34 -18
- idfkit-1.3.0rc1/agent_references/snippets/document-and-objects.py +332 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/snippets/hvac-loops.py +30 -11
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/snippets/parsing-idf-epjson.py +1 -2
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/snippets/result-parsing.py +1 -1
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/snippets/schema-and-validation.py +3 -2
- idfkit-1.3.0rc1/agent_references/snippets/threading.py +66 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/snippets/writing-output.py +6 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/templates/SKILL.md +5 -1
- idfkit-1.3.0rc1/agent_references/templates/document-and-objects.md +220 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/templates/hvac-loops.md +9 -9
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/templates/parsing-idf-epjson.md +5 -1
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/templates/reference-tracking.md +1 -1
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/templates/result-parsing.md +1 -1
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/templates/schema-and-validation.md +2 -2
- idfkit-1.3.0rc1/agent_references/templates/threading.md +71 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/templates/version-migration.md +2 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/templates/weather-data.md +1 -1
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/templates/writing-output.md +15 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/benchmarks/bench.py +56 -32
- idfkit-1.3.0rc1/benchmarks/bench_free_threading.py +177 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/pyproject.toml +14 -15
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/scripts/check_naming_register.py +20 -4
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/.agents/skills/developing-with-idfkit/SKILL.md +5 -1
- idfkit-1.3.0rc1/src/idfkit/.agents/skills/developing-with-idfkit/references/document-and-objects.md +457 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/.agents/skills/developing-with-idfkit/references/hvac-loops.md +39 -20
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/.agents/skills/developing-with-idfkit/references/parsing-idf-epjson.md +6 -3
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/.agents/skills/developing-with-idfkit/references/reference-tracking.md +1 -1
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/.agents/skills/developing-with-idfkit/references/result-parsing.md +2 -2
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/.agents/skills/developing-with-idfkit/references/schema-and-validation.md +5 -4
- idfkit-1.3.0rc1/src/idfkit/.agents/skills/developing-with-idfkit/references/threading.md +100 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/.agents/skills/developing-with-idfkit/references/version-migration.md +2 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/.agents/skills/developing-with-idfkit/references/weather-data.md +1 -1
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/.agents/skills/developing-with-idfkit/references/writing-output.md +16 -0
- idfkit-1.3.0rc1/src/idfkit/_atomic.py +109 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/_compat.py +7 -1
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/_compat_object.py +18 -16
- idfkit-1.3.0rc1/src/idfkit/_document_types.py +130 -0
- idfkit-1.3.0rc1/src/idfkit/_forksafe.py +56 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/_generated_types.pyi +20564 -7753
- idfkit-1.3.0rc1/src/idfkit/codegen/generate_stubs.py +1984 -0
- idfkit-1.3.0rc1/src/idfkit/codegen/verify_stubs.py +544 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/compat/_cli.py +3 -3
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/document.py +88 -17
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/document.pyi +2119 -70
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/download.py +4 -19
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/epjson_parser.py +6 -4
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/exceptions.py +17 -9
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/geometry.py +11 -11
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/geometry_builders.py +11 -11
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/idf_parser.py +25 -19
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/introspection.py +6 -2
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/migration/async_runner.py +3 -3
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/migration/diff.py +6 -6
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/migration/runner.py +3 -3
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/objects.py +208 -47
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/scene.py +8 -8
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schedules/builder.py +4 -4
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schedules/evaluate.py +7 -7
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schedules/file.py +57 -9
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schedules/holidays.py +4 -4
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schedules/series.py +5 -5
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schedules/week.py +4 -4
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schedules/year.py +4 -4
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schema.py +119 -29
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/_common.py +14 -15
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/_external_files.py +5 -5
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/async_runner.py +6 -5
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/cache.py +4 -4
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/expand.py +32 -26
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/outputs.py +14 -26
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/runner.py +9 -8
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/surface_matching.py +9 -9
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/validation.py +18 -15
- idfkit-1.3.0rc1/src/idfkit/versioned.py +55 -0
- idfkit-1.3.0rc1/src/idfkit/versioned.pyi +25311 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/visualization/model.py +6 -6
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/weather/designday.py +51 -14
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/weather/download.py +144 -46
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/weather/geocode.py +10 -5
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/weather/index.py +11 -4
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/writers.py +46 -25
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/zoning.py +12 -10
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/conftest.py +14 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_agent_references.py +2 -2
- idfkit-1.3.0rc1/tests/test_atomic.py +173 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_codegen.py +25 -17
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_document.py +214 -30
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_download.py +1 -1
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_eppy_compat.py +5 -19
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_expand.py +14 -4
- idfkit-1.3.0rc1/tests/test_fixed_fields_not_flat_extensible.py +222 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_geometry.py +7 -36
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_introspection.py +28 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_parsers.py +3 -2
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_schema.py +0 -8
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_outputs.py +29 -1
- idfkit-1.3.0rc1/tests/test_simulation_prep_outputs.py +60 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_runner.py +1 -1
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_strict_typing.py +6 -4
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_surface_matching.py +2 -3
- idfkit-1.3.0rc1/tests/test_thread_safety.py +666 -0
- idfkit-1.3.0rc1/tests/test_trailing_underscore_fields.py +315 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_validation.py +80 -8
- idfkit-1.3.0rc1/tests/test_versioned.py +346 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_weather_designday.py +43 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_weather_download.py +79 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_weather_index.py +20 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_writers.py +130 -1
- idfkit-1.3.0rc1/tests/type_checks/typed_fields_fixture.py +65 -0
- idfkit-1.3.0rc1/tests/type_checks/versioned_fixture.py +180 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tox.ini +2 -1
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/uv.lock +1 -1
- idfkit-1.2.0/agent_references/snippets/document-and-objects.py +0 -131
- idfkit-1.2.0/agent_references/templates/document-and-objects.md +0 -132
- idfkit-1.2.0/src/idfkit/.agents/skills/developing-with-idfkit/references/document-and-objects.md +0 -203
- idfkit-1.2.0/src/idfkit/codegen/generate_stubs.py +0 -852
- idfkit-1.2.0/tests/test_simulation_prep_outputs.py +0 -37
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.devcontainer/devcontainer.json +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.devcontainer/postCreateCommand.sh +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.github/CODEOWNERS +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.github/actions/setup-python-env/action.yml +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.github/ep-testfiles.sparse +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.github/workflows/adopt-energyplus.yml +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.github/workflows/archive-retired-site.yml +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.github/workflows/benchmark.yml +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.github/workflows/deploy-py-redirects.yml +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.github/workflows/notify-downstream.yml +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.github/workflows/on-release-main.yml +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.github/workflows/validate-codecov-config.yml +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.gitignore +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.pre-commit-config.yaml +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.pre-commit-hooks.yaml +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.python-version +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.vscode/extensions.json +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/.vscode/settings.json +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/AGENTS.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/CONTRIBUTING.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/LICENSE +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/snippets/geometry-and-surfaces.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/snippets/geometry-builders-and-zoning.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/snippets/hvac-templates.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/snippets/reference-tracking.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/snippets/schedule-evaluation.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/snippets/simulation-execution.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/snippets/thermal-properties.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/snippets/version-migration.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/snippets/visualization.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/snippets/weather-data.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/templates/geometry-and-surfaces.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/templates/geometry-builders-and-zoning.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/templates/hvac-templates.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/templates/schedule-evaluation.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/templates/simulation-execution.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/templates/thermal-properties.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/agent_references/templates/visualization.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/benchmarks/aggregate.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/benchmarks/bench_eso.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/benchmarks/bench_progress.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/benchmarks/bench_typecheckers.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/benchmarks/eso_results.json +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/benchmarks/profile_field_access.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/benchmarks/profile_lookup.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/benchmarks/profile_overloads.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/benchmarks/profile_stubs.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/benchmarks/progress_benchmark_results.json +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/codecov.yaml +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/old-sitemaps/README.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/old-sitemaps/developers.idfkit.com.retired.txt +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/old-sitemaps/developers.idfkit.com.txt +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/old-sitemaps/js.idfkit.com.sitemap.xml +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/old-sitemaps/py.idfkit.com.sitemap.xml +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/redirects/README.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/redirects/path-map.json +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/scripts/_governance_source.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/scripts/adopt_energyplus.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/scripts/build_redirect_site.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/scripts/build_weather_index.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/scripts/check_parity_ledger.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/scripts/check_redirects.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/scripts/check_release_conformance.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/scripts/check_release_version.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/scripts/sweep_example_files.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/.agents/skills/developing-with-idfkit/references/geometry-and-surfaces.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/.agents/skills/developing-with-idfkit/references/geometry-builders-and-zoning.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/.agents/skills/developing-with-idfkit/references/hvac-templates.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/.agents/skills/developing-with-idfkit/references/schedule-evaluation.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/.agents/skills/developing-with-idfkit/references/simulation-execution.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/.agents/skills/developing-with-idfkit/references/thermal-properties.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/.agents/skills/developing-with-idfkit/references/visualization.md +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/__init__.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/_accessors.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/_conformance.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/codegen/__init__.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/codegen/bake_references.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/codegen/generate_conformance.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/codegen/generate_doc_locations.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/codegen/generate_epw_sentinels.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/compat/__init__.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/compat/_checker.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/compat/_diff.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/compat/_extract.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/compat/_models.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/compat/_sarif.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/cst.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/docs.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/migration/__init__.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/migration/async_subprocess_backend.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/migration/chain.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/migration/progress.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/migration/protocol.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/migration/report.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/migration/subprocess_backend.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/py.typed +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/references.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schedules/__init__.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schedules/compact.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schedules/day.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schedules/day_types.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schedules/time_utils.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schedules/types.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V22-1-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V22-2-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V23-1-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V23-2-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V24-1-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V24-2-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V25-1-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V25-2-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V26-1-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V26-2-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V8-9-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V9-0-1/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V9-1-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V9-2-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V9-3-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V9-4-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V9-5-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/V9-6-0/Energy+.schema.epJSON.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/schemas/doc_locations.json +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/__init__.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/async_batch.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/batch.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/config.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/fs.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/parsers/__init__.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/parsers/_timeutil.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/parsers/csv.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/parsers/err.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/parsers/eso.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/parsers/html.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/parsers/rdd.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/parsers/sql.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/plotting/__init__.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/plotting/matplotlib.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/plotting/plotly.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/plotting/visualizations.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/progress.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/progress_bars.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/simulation/result.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/thermal/__init__.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/thermal/gas.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/thermal/properties.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/versions.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/visualization/__init__.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/visualization/svg.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/weather/__init__.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/weather/_browser/__init__.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/weather/_browser/assets/app.js +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/weather/_browser/assets/index.html +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/weather/_browser/assets/style.css +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/weather/_browser/server.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/weather/_cli.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/weather/_epw_sentinels.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/weather/data/stations.json.gz +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/weather/epw.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/weather/spatial.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/src/idfkit/weather/station.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/fixtures/simulation/generate_eso_fixtures.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/fixtures/simulation/sample.csv +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/fixtures/simulation/sample.err +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/fixtures/simulation/sample.eso +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/fixtures/simulation/sample.mdd +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/fixtures/simulation/sample.mtr +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/fixtures/simulation/sample.rdd +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/fixtures/simulation/sample_fatal.err +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/fixtures/simulation/sample_truncated.eso +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/fixtures/weather/empty.ddy +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/fixtures/weather/sample.ddy +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/schedules/__init__.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/schedules/test_compact.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/schedules/test_day.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/schedules/test_day_types.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/schedules/test_evaluate.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/schedules/test_file.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/schedules/test_holidays.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/schedules/test_series.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/schedules/test_time_utils.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/schedules/test_types.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/schedules/test_week.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/schedules/test_year.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_accessors.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_adopt_energyplus.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_basic.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_check_redirects.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_check_release_version.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_cli_migrate.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_compat_cli.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_compat_diff.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_compat_extract.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_docs.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_epjson_roundtrip.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_exceptions.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_extensible_canonical_api.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_extensible_eppy_compat.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_extensible_normalization.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_geometry_builders.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_governance_source_matches.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_idf_roundtrip.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_logging.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_migration_async_runner.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_migration_chain.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_migration_config.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_migration_diff.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_migration_e2e.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_migration_exceptions.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_migration_report.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_migration_runner.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_migration_subprocess_backend.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_object_update.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_objects.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_references.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_roundtrip.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_scene.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_schedule_builder.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_async.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_batch.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_cache.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_config.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_csv_parser.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_e2e.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_err_parser.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_eso_parser.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_external_files.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_fs.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_html_parser.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_plotting.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_preprocessor_timeout.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_progress.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_progress_bars.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_rdd_parser.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_result.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_sql_parser.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_simulation_version_mismatch.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_thermal.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_type_name_lookup.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_versions.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_visualization.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_visualization_model.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_weather_cli.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_weather_geocode.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_weather_offline.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_weather_spatial.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_weather_station.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/test_zoning.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/type_checks/update_fixture.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/weather/__init__.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/weather/epw_fixtures.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/weather/test_epw.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/weather/test_epw_sentinels.py +0 -0
- {idfkit-1.2.0 → idfkit-1.3.0rc1}/tests/weather/test_index_climate_zone.py +0 -0
|
@@ -68,7 +68,7 @@ jobs:
|
|
|
68
68
|
|
|
69
69
|
- name: Set up the environment
|
|
70
70
|
# 3.11 is the floor the corpus runner needs: it reads case files with tomllib, which is
|
|
71
|
-
# standard library only from 3.11. The library itself is tested across 3.10 to 3.
|
|
71
|
+
# standard library only from 3.11. The library itself is tested across 3.10 to 3.14 in
|
|
72
72
|
# main.yml; this job is about the corpus, not about the supported interpreter range.
|
|
73
73
|
uses: ./.github/actions/setup-python-env
|
|
74
74
|
with:
|
|
@@ -35,7 +35,7 @@ jobs:
|
|
|
35
35
|
runs-on: ubuntu-latest
|
|
36
36
|
strategy:
|
|
37
37
|
matrix:
|
|
38
|
-
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
38
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
39
39
|
fail-fast: false
|
|
40
40
|
defaults:
|
|
41
41
|
run:
|
|
@@ -62,6 +62,54 @@ jobs:
|
|
|
62
62
|
env:
|
|
63
63
|
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
64
64
|
|
|
65
|
+
tests-free-threaded:
|
|
66
|
+
# The suite on free-threaded CPython with the GIL off. The core is pure Python and declares
|
|
67
|
+
# the Free Threading classifier on the strength of this job, and tests/test_thread_safety.py
|
|
68
|
+
# reproduces races only here: on a GIL build most of them cannot happen.
|
|
69
|
+
name: "tests (3.14t, GIL off)"
|
|
70
|
+
runs-on: ubuntu-latest
|
|
71
|
+
# A lock regression shows up as a deadlock. The race tests fail on their own deadline, but this
|
|
72
|
+
# caps whatever they miss well short of GitHub's six-hour default.
|
|
73
|
+
timeout-minutes: 30
|
|
74
|
+
defaults:
|
|
75
|
+
run:
|
|
76
|
+
shell: bash
|
|
77
|
+
steps:
|
|
78
|
+
- name: Check out
|
|
79
|
+
uses: actions/checkout@v4
|
|
80
|
+
|
|
81
|
+
- name: Set up the environment
|
|
82
|
+
uses: ./.github/actions/setup-python-env
|
|
83
|
+
with:
|
|
84
|
+
python-version: "3.14t"
|
|
85
|
+
|
|
86
|
+
# A `3.14t` request that resolved to a GIL build would pass every test below while proving
|
|
87
|
+
# nothing, so fail loudly first. The import check runs WITHOUT PYTHON_GIL=0: an interpreter
|
|
88
|
+
# re-enables the GIL when it imports an extension module that does not declare support, and
|
|
89
|
+
# that override would hide such a module. idfkit and all of its sub-packages must keep it
|
|
90
|
+
# off on their own.
|
|
91
|
+
- name: Check the interpreter is free-threaded and idfkit keeps the GIL off
|
|
92
|
+
run: |
|
|
93
|
+
uv run python - <<'EOF'
|
|
94
|
+
import importlib, pkgutil, sys, sysconfig
|
|
95
|
+
assert sysconfig.get_config_var("Py_GIL_DISABLED"), f"not a free-threaded build: {sys.version}"
|
|
96
|
+
import idfkit
|
|
97
|
+
# walk_packages yields each package before importing it, so the import below is the first and
|
|
98
|
+
# raises on any failure: no `onerror` is needed for a broken package to fail this step.
|
|
99
|
+
for mod in pkgutil.walk_packages(idfkit.__path__, "idfkit."):
|
|
100
|
+
if ".codegen" not in mod.name:
|
|
101
|
+
importlib.import_module(mod.name)
|
|
102
|
+
assert not sys._is_gil_enabled(), "importing idfkit re-enabled the GIL"
|
|
103
|
+
print(sys.version, "- GIL off after importing every idfkit module")
|
|
104
|
+
EOF
|
|
105
|
+
|
|
106
|
+
# PYTHON_GIL=0 because the locked pandas (2.3) re-enables the GIL at import; pandas 3 does
|
|
107
|
+
# not. The override keeps the whole run, the pandas tests included, genuinely GIL-free.
|
|
108
|
+
- name: Run tests
|
|
109
|
+
env:
|
|
110
|
+
PYTHON_GIL: "0"
|
|
111
|
+
run: uv run python -m pytest -W error::DeprecationWarning
|
|
112
|
+
|
|
65
113
|
example-sweep:
|
|
66
114
|
# Read every EnergyPlus example file, for every version idfkit bundles a schema for.
|
|
67
115
|
#
|
|
@@ -14,6 +14,9 @@ name: Rehearse a candidate against every consumer
|
|
|
14
14
|
# consumer's pull requests, it cannot block any consumer's unrelated work (FR-013).
|
|
15
15
|
#
|
|
16
16
|
# A dispatch that does not land fails this run. A rehearsal that reached nobody is not a rehearsal.
|
|
17
|
+
# This run then waits for every rehearsal to conclude and fails if any one fails or times out, so a
|
|
18
|
+
# candidate that breaks a consumer is red here as well. The job timeout covers the consumers' own
|
|
19
|
+
# 45-minute rehearsal jobs.
|
|
17
20
|
on:
|
|
18
21
|
workflow_dispatch:
|
|
19
22
|
inputs:
|
|
@@ -28,7 +31,7 @@ permissions:
|
|
|
28
31
|
jobs:
|
|
29
32
|
rehearse:
|
|
30
33
|
runs-on: ubuntu-latest
|
|
31
|
-
timeout-minutes:
|
|
34
|
+
timeout-minutes: 60
|
|
32
35
|
steps:
|
|
33
36
|
- name: Check out this repository for its governance pin
|
|
34
37
|
uses: actions/checkout@v4
|
|
@@ -7,6 +7,242 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.3.0-rc.1] - 2026-11-14
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- The README opens with the idfkit identity header at `identity-2026.5`: the mark, the
|
|
15
|
+
repository's one sentence, the family links and the badge row. The `Identity` workflow
|
|
16
|
+
(`.github/workflows/check-identity.yml`) holds the header to that tag on every pull request.
|
|
17
|
+
- A field whose epJSON key ends in `_` could be given without the underscore, in `add()`,
|
|
18
|
+
attribute access, `update()` and the eppy helpers: `cond_flag_is_the_basement_conditioned="FALSE"`
|
|
19
|
+
set `GroundHeatTransfer:Basement:Interior.cond_flag_is_the_basement_conditioned_`, and the value
|
|
20
|
+
was stored and written under the schema's key. The underscore comes from IDD names that end in
|
|
21
|
+
punctuation or a space, and EnergyPlus has started dropping it: `WindowShadingControl`'s
|
|
22
|
+
`construction_with_shading_name_` in 9.0.1 and 9.1.0 is `construction_with_shading_name` from
|
|
23
|
+
9.2.0, and the one spelling worked on both. `name` was never such a spelling. `add()` refused a
|
|
24
|
+
call that gave both spellings of one field, even with one of them blank. The typed `update()`
|
|
25
|
+
stubs name only the schema's key. ([60c47cc](https://github.com/idfkit/idfkit/commit/60c47cc),
|
|
26
|
+
[9b208de](https://github.com/idfkit/idfkit/commit/9b208de))
|
|
27
|
+
- Python 3.14 became a supported version: CI runs the test suite and type check on it, and the package declares the 3.14 classifier ([#253](https://github.com/idfkit/idfkit/pull/253)).
|
|
28
|
+
- Free-threaded CPython 3.14 (`python3.14t`, GIL disabled) became a tested build: a CI job runs the test suite on it with the GIL off and fails if importing any idfkit module re-enables the GIL, and the package declares the `Free Threading :: 2 - Beta` classifier. The threading contract is now stated in the bundled agent references (`threading.md`): the schema manager and module-level caches are safe from any number of threads, separate documents are independent, and one document may be read from many threads but must not be mutated by several at once. Of the optional extras, only `pandas` before 3.0 re-enables the GIL on import. `benchmarks/bench_free_threading.py` measures thread scaling: on 4 CPUs, four threads parse IDF files 2.6 times faster than one thread on the regular build, and other workloads gain 1.0 to 1.6 times ([#254](https://github.com/idfkit/idfkit/pull/254)).
|
|
29
|
+
- `idfkit.weather.designday.sanitize_ddy_bytes()`, the in-memory form of `sanitize_ddy_file()`, which blanks placeholder values in DDY content before it is written anywhere ([#254](https://github.com/idfkit/idfkit/pull/254)).
|
|
30
|
+
- **A document became typeable for the EnergyPlus release it was written for, not only the
|
|
31
|
+
latest one.** `idfkit.versioned` gained one type per supported release,
|
|
32
|
+
`IDFDocumentV<major>_<minor>` from `IDFDocumentV8_9` to `IDFDocumentV26_2` (which is
|
|
33
|
+
`IDFDocument`), and `as_version(doc, IDFDocumentV9_4)`, which returns the document under that
|
|
34
|
+
type after checking its release at run time. Given a tuple of those types, as `isinstance`
|
|
35
|
+
takes one, `as_version` accepts a document of any of them and types it as their union (mypy reduces
|
|
36
|
+
the union to what those releases share), which
|
|
37
|
+
narrows a model of unknown release into a range such as the releases that have `Space`. Such a document is indexed, completed and checked
|
|
38
|
+
with that release's object types, field value types and choices, accessors and `update()`
|
|
39
|
+
keywords: on a 9.4 model `doc["Space"]` is a type error and `People` has
|
|
40
|
+
`zone_or_zonelist_name`. Documents stay typed for the latest release unless their version is
|
|
41
|
+
stated this way. The stubs encode each object type's declaration once per contiguous range of
|
|
42
|
+
releases that share it, and `python -m idfkit.codegen.generate_stubs` now checks what it wrote
|
|
43
|
+
against every bundled schema before finishing, so adopting a release needs no hand edit of
|
|
44
|
+
the stubs, and a regeneration that would misdescribe a release fails ([#194](https://github.com/idfkit/idfkit/issues/194), [#251](https://github.com/idfkit/idfkit/pull/251)).
|
|
45
|
+
- `AnyIDFDocument` (in `idfkit.versioned` and `idfkit.document`) was added. It accepts a
|
|
46
|
+
document of any supported release and, through it, offers what every release has: the object
|
|
47
|
+
types present in all of them. A field whose value type changed between releases reads as any
|
|
48
|
+
release's value and, through assignment and `update()`, accepts only a value every release
|
|
49
|
+
accepts: `heater_fuel_type` can be set to `"NaturalGas"` but not to `"DistrictHeatingWater"`,
|
|
50
|
+
which 9.3 to 23.1 reject. idfkit's own
|
|
51
|
+
functions were retyped to take it, so `save_idf`, `simulate`, the geometry and zoning helpers
|
|
52
|
+
and the rest accept a document typed for any release; `expand_objects` and the ground
|
|
53
|
+
heat-transfer preprocessors return the type they were given. An object type or accessor that
|
|
54
|
+
some release lacks is reported against the type that lacks it, for example
|
|
55
|
+
`"Space" is not a defined key in "IDFDocumentV9_4[bool]"`, and through `AnyIDFDocument` as
|
|
56
|
+
`"Space" is not a defined key in "IDFDocumentAllVersions[bool]"`. Naming one release's type costs
|
|
57
|
+
pyright about what naming `IDFDocument` does, 2 to 3 seconds for a file; a file naming every
|
|
58
|
+
release's type takes about 7 seconds
|
|
59
|
+
([#194](https://github.com/idfkit/idfkit/issues/194), [#251](https://github.com/idfkit/idfkit/pull/251)).
|
|
60
|
+
- Every object type of the latest release gained an `Any<Class>` type, importable from `idfkit.document` inside
|
|
61
|
+
`if TYPE_CHECKING:`, for annotating code that takes an object of any supported release:
|
|
62
|
+
`def floor_area(zone: AnyZone)` accepts a latest-release zone, a 9.4 zone and a zone reached
|
|
63
|
+
through `AnyIDFDocument`, where `Zone` accepts only the first. Through it, fields follow the
|
|
64
|
+
`AnyIDFDocument` rules, extensible groups included, so `AnyBuildingSurfaceDetailed.vertices` is
|
|
65
|
+
typed. For a type no release changed, `Any<Class>` is the latest class itself (`AnyZoneList` is
|
|
66
|
+
`ZoneList`). For a type that arrived after 8.9, it covers the releases that have it:
|
|
67
|
+
`AnySpace` accepts a `Space` of any release from 9.6, and its docstring says so. A type that
|
|
68
|
+
a release before the latest removed, such as `DistrictHeating`, has none: its classes are
|
|
69
|
+
named for the releases that have it (`DistrictHeating_v8_9_to_v23_1`). `Any<Class>` covers the
|
|
70
|
+
releases idfkit supports, so adopting a release that drops or renames a field removes that
|
|
71
|
+
field from it
|
|
72
|
+
([#194](https://github.com/idfkit/idfkit/issues/194), [#251](https://github.com/idfkit/idfkit/pull/251)).
|
|
73
|
+
|
|
74
|
+
### Changed
|
|
75
|
+
|
|
76
|
+
- **Breaking:** for type checking only, an undeclared field name on a typed object is now a type
|
|
77
|
+
error. `material.thermal_resistance = 1.0` on a `Material` taken from `doc["Material"]`, or
|
|
78
|
+
`print(material.bogus)`, used to type-check clean because the catch-all `__getattr__` and
|
|
79
|
+
`__setattr__` of `IDFObject` accepted any name. pyright reports the name whether it is read or
|
|
80
|
+
assigned; mypy reports an assignment, and types a read as `object`, so it reports any use that
|
|
81
|
+
needs a more specific type.
|
|
82
|
+
The same holds for the groups of an extensible type, such as `surface.vertices[0]`. Typed objects
|
|
83
|
+
declare snake_case names only, so an eppy-style capitalised spelling such as
|
|
84
|
+
`material.Thickness = 0.2` is now reported too, although it still works at run time: use
|
|
85
|
+
`material.thickness`. The typed classes describe EnergyPlus 26.2, so a field name that only exists
|
|
86
|
+
in an earlier version, such as `Lights.watts_per_zone_floor_area` up to 23.2, is reported as well;
|
|
87
|
+
on such a model, reach it with item access (`lights["watts_per_zone_floor_area"]`) or `getattr`.
|
|
88
|
+
Objects from the eppy API (`doc.idfobjects[...]`, `newidfobject()`, `getobject()`) and other plain
|
|
89
|
+
`IDFObject`s, such as those from `doc.add()` or `doc.get_collection()`, stay permissive. Declared
|
|
90
|
+
fields, `name`, the spellings of trailing-underscore fields with and without the underscore, and
|
|
91
|
+
wrong-type errors behave as before. Run-time behaviour is unchanged. ([#272](https://github.com/idfkit/idfkit/pull/272))
|
|
92
|
+
|
|
93
|
+
- **Breaking:** `IDFDocument.add()` raised `InvalidFieldError` when given a non-empty name for a
|
|
94
|
+
type without a Name field, such as `Output:Meter`, `Output:Variable`, `Output:SQLite`,
|
|
95
|
+
`Timestep` or `SimulationControl` (165 of the 880 types in the 26.2 schema), whether or not
|
|
96
|
+
`validate` is set. The name used to be stored and then dropped by both writers, so
|
|
97
|
+
`add("Output:SQLite", "SimpleAndTabular")` wrote `Output:SQLite,` and EnergyPlus produced no
|
|
98
|
+
`.sql` file. The message names the field to pass instead (`key_name="Electricity:Facility"`
|
|
99
|
+
for `Output:Meter`, `option_type=...` for `Output:SQLite`); the value is never moved there for
|
|
100
|
+
you. The same rule applies to `obj.name = ...` and to `newidfobject`, `addidfobject` and
|
|
101
|
+
`copyidfobject(..., new_name=...)`. Loading existing IDF and epJSON files is unaffected.
|
|
102
|
+
([11ac720](https://github.com/idfkit/idfkit/commit/11ac720))
|
|
103
|
+
- **Breaking:** `IDFDocument.add()` refused a key that is not a field of the object type even
|
|
104
|
+
with `validate=False`, raising `InvalidFieldError` that names every such key, whatever its
|
|
105
|
+
value. `validate=False` used to skip schema validation entirely, so the key was stored, then
|
|
106
|
+
silently dropped by `write_idf()` and written as an unknown property by `write_epjson()`. It
|
|
107
|
+
still skips value, required-field and range checks. The object's name belongs in the `name`
|
|
108
|
+
argument, not in `fields`; display spellings such as `"X Origin"` are refused with the field
|
|
109
|
+
to use instead; and `FenestrationSurface:Detailed` takes its fixed `vertex_N_x_coordinate`
|
|
110
|
+
fields, not a `vertices` list. ([1fe5171](https://github.com/idfkit/idfkit/commit/1fe5171),
|
|
111
|
+
[b415635](https://github.com/idfkit/idfkit/commit/b415635))
|
|
112
|
+
- **Breaking:** `IDFDocument.add()` checked the extensible groups it was given in either
|
|
113
|
+
validate mode, as `IDFObject.update()` already did, and raised `TypeError` for a group key the
|
|
114
|
+
group does not name (`reports=[{"report_nme": ...}]`) or a wrapper value that is not a list of
|
|
115
|
+
groups (a string, a list of strings or tuples, or another object's live `vertices` view).
|
|
116
|
+
Validation never looked inside the groups, so these were stored, and `write_idf()` dropped the
|
|
117
|
+
values or crashed. ([b415635](https://github.com/idfkit/idfkit/commit/b415635))
|
|
118
|
+
- `IDFCollection` became covariant in its object type, so `IDFCollection[Zone]` is accepted
|
|
119
|
+
where `IDFCollection[IDFObject]` is expected. `IDFCollection.remove` now takes any `IDFObject`,
|
|
120
|
+
and `get(name, default)` returns the object type or the default's type. The usual cost of
|
|
121
|
+
covariance came with it: a function that takes `IDFCollection[IDFObject]` can `add()` an object of
|
|
122
|
+
another type to the collection it is given, such as a `Material` to `doc["Zone"]`, without a type
|
|
123
|
+
error, and `add()` does not check it at run time
|
|
124
|
+
([#194](https://github.com/idfkit/idfkit/issues/194), [#251](https://github.com/idfkit/idfkit/pull/251)).
|
|
125
|
+
|
|
126
|
+
### Removed
|
|
127
|
+
|
|
128
|
+
- **Breaking:** `SchemaManager.get_schema` is no longer wrapped in `functools.lru_cache`, so `get_schema.cache_clear()`, `get_schema.cache_info()` and `get_schema.cache_parameters()` are gone. The manager's own cache already held every loaded version; call `SchemaManager.clear_cache()` to drop it ([#254](https://github.com/idfkit/idfkit/pull/254)).
|
|
129
|
+
|
|
130
|
+
### Fixed
|
|
131
|
+
|
|
132
|
+
- The bundled agent references described the changes above wrongly or not at all. The HVAC loops
|
|
133
|
+
reference still called `validate_document` and `get_referencing` the safety net for node wiring,
|
|
134
|
+
though neither sees node names, and offered renaming a coil as a fix for a mismatched node name.
|
|
135
|
+
The references now say that typed objects accept only 26.2 snake_case field names, that an empty
|
|
136
|
+
group-only object such as `Output:Table:SummaryReports` is written to IDF as `Type,;`, and that
|
|
137
|
+
`prep_outputs` also requests the `AllSummary` tabular report.
|
|
138
|
+
([2399407](https://github.com/idfkit/idfkit/commit/2399407))
|
|
139
|
+
- `EpJSONSchema.get_field_names()` dropped the first field of every type, including types without
|
|
140
|
+
a Name field, whose first field is an ordinary one: `get_field_names("Output:Meter")` was
|
|
141
|
+
`['reporting_frequency']`. It now drops the first field only for a named type. As a result
|
|
142
|
+
`describe_object_type()` (and `IDFDocument.describe()`) lists `key_name` for `Output:Meter`,
|
|
143
|
+
and the generated `OutputMeter` class and its `update()` keywords include it; the same holds
|
|
144
|
+
for every other nameless type. Validation no longer counts a name stored on a nameless object
|
|
145
|
+
as a declared name. ([11ac720](https://github.com/idfkit/idfkit/commit/11ac720))
|
|
146
|
+
- Fixed fields whose names look like a flat spelling of the type's own extensible group were
|
|
147
|
+
treated as that group's fields. This affected `MaterialProperty:GlazingSpectralData`
|
|
148
|
+
(`wavelength_1` … `back_reflectance_4`), `Site:SpectrumData` (`wavelength`, `spectrum`,
|
|
149
|
+
`wavelength_1`, `spectrum_2`), `ZoneHVAC:HybridUnitaryHVAC` (`mode_0_*`) and, in EnergyPlus 8.9
|
|
150
|
+
to 9.1, `Table:MultiVariableLookup` (`field_1_…` and `field_2_…`). `add()` moved these values
|
|
151
|
+
into the extensible groups with a deprecation warning, or raised `ValueError` ("cannot mix") when
|
|
152
|
+
the groups were passed too. `load_epjson()` moved them silently, after any groups already in the
|
|
153
|
+
file. Either way `write_idf` wrote the fixed fields blank and the values out of place. On
|
|
154
|
+
`Site:SpectrumData`, `wavelength_1` overwrote `wavelength`. Attribute assignment stored the
|
|
155
|
+
value in a group (for `mode_0_*`, the last mode), attribute reads of an unset field returned a
|
|
156
|
+
group's value, and `update()` refused the field as a legacy flat name. These fields are now
|
|
157
|
+
kept as fixed fields.
|
|
158
|
+
([cee2d7c](https://github.com/idfkit/idfkit/commit/cee2d7c))
|
|
159
|
+
- A field whose epJSON name ends in `_` was out of reach by attribute: assigning it or passing it
|
|
160
|
+
to `update()` raised `InvalidFieldError`, and so did reading it unset in a strict document,
|
|
161
|
+
because the trailing underscore was stripped into a name the type does not have. In a document
|
|
162
|
+
opened with `strict=False`, the assignment was stored under that name instead, and `write_idf()`
|
|
163
|
+
dropped it. 24 such fields exist across the bundled schemas, among them
|
|
164
|
+
`GroundHeatTransfer:Basement:Interior.cond_flag_is_the_basement_conditioned_`,
|
|
165
|
+
`GroundHeatTransfer:Basement:ManualGrid.nx_number_of_cells_in_the_x_direction_20_` and
|
|
166
|
+
`SizingPeriod:DesignDay.ashrae_clear_sky_optical_depth_for_beam_irradiance_taub_`; `add()`
|
|
167
|
+
already accepted them. `update()` also refused `Output:Table:ReportPeriod.name_` as the
|
|
168
|
+
object's name. The eppy-style dotted `IDFDocument.update()`, `get_referenced_object()`,
|
|
169
|
+
`getrange()`, `checkrange()` and `getreferingobjs(fields=...)` missed them the same way.
|
|
170
|
+
([a520960](https://github.com/idfkit/idfkit/commit/a520960),
|
|
171
|
+
[9b208de](https://github.com/idfkit/idfkit/commit/9b208de))
|
|
172
|
+
- A flat extensible name with group number 0, such as `vertex_0_x_coordinate` or
|
|
173
|
+
`mode_0_minimum_outdoor_air_temperature`, was read as the last group: assignment overwrote the
|
|
174
|
+
last group's value, or raised `IndexError` when there were no groups, and `add()` inserted it
|
|
175
|
+
as a new first group. Group numbers now start at 1, so such a name is an unknown field.
|
|
176
|
+
([da8a613](https://github.com/idfkit/idfkit/commit/da8a613))
|
|
177
|
+
- `write_idf` and `save_idf` wrote an object with nothing in it without its terminating `;`, so it
|
|
178
|
+
swallowed the object after it, and EnergyPlus read that object's type name and values as fields
|
|
179
|
+
of the empty one. This happened to a nameless type with no fixed fields
|
|
180
|
+
(`Output:Table:SummaryReports`, `Output:Diagnostics`, `OutdoorAir:NodeList`,
|
|
181
|
+
`EnergyManagementSystem:GlobalVariable` and the six `GroundHeatTransfer` face types) when it held
|
|
182
|
+
no groups. It affected the standard and `nocomment` output types, `doc.copy()`, and objects
|
|
183
|
+
added to a document loaded with `preserve_formatting=True`. Such an object is now written with
|
|
184
|
+
one blank field, `Output:Diagnostics,;`, which keeps the next object intact. IDF has no spelling
|
|
185
|
+
that EnergyPlus reads as one of these objects with nothing in it: `Output:Diagnostics;` swallows
|
|
186
|
+
the next object too, and EnergyPlus reads `Output:Diagnostics,;` as one blank group. That gives a
|
|
187
|
+
warning for `Output:Diagnostics` and a Severe error for `Output:Table:SummaryReports`, and
|
|
188
|
+
EnergyPlus refuses the input for `OutdoorAir:NodeList` and
|
|
189
|
+
`EnergyManagementSystem:GlobalVariable`. Remove such an object, or write the model as epJSON, to
|
|
190
|
+
keep it empty. ([3e3e772](https://github.com/idfkit/idfkit/commit/3e3e772),
|
|
191
|
+
[0dcfdd3](https://github.com/idfkit/idfkit/commit/0dcfdd3))
|
|
192
|
+
- Strict IDF parsing no longer rejects blank fields past the last field of a type without
|
|
193
|
+
repeated groups, such as `Timestep,4,,;` or `GroundHeatTransfer:Slab:XFACE,;`; EnergyPlus accepts
|
|
194
|
+
them too. A non-blank extra value is still an error, and the error counts only the values up to
|
|
195
|
+
the last non-blank one. ([3e3e772](https://github.com/idfkit/idfkit/commit/3e3e772),
|
|
196
|
+
[0dcfdd3](https://github.com/idfkit/idfkit/commit/0dcfdd3))
|
|
197
|
+
- `write_idf` dropped the name and every field of an object whose type was spelled in a different
|
|
198
|
+
case from the schema, such as one added with `addidfobject(IDFObject(obj_type="TIMESTEP", ...))`,
|
|
199
|
+
and of an object of a type the schema does not know. Both are now written with their values.
|
|
200
|
+
([0dcfdd3](https://github.com/idfkit/idfkit/commit/0dcfdd3))
|
|
201
|
+
- **Breaking:** Validation reported unknown fields (`W003`) on extensible object types too, and
|
|
202
|
+
on unknown fields with a blank value. Extensible types used to be exempt, so
|
|
203
|
+
`doc.add("Output:Table:SummaryReports", "", report_1="AllSummary")` passed the default
|
|
204
|
+
`validate=True` and stored a key that `write_idf()` silently dropped and `write_epjson()`
|
|
205
|
+
emitted as an unknown property. Such a call now raises `ValidationFailedError`, as an unknown
|
|
206
|
+
field on a non-extensible type already did; the wrapper list (`reports=[...]`) and the
|
|
207
|
+
deprecated flat spellings (`report_name`, `report_name_2`) are still accepted.
|
|
208
|
+
`validate_document()` reports the same keys on objects loaded from epJSON.
|
|
209
|
+
([459258f](https://github.com/idfkit/idfkit/commit/459258f), [b415635](https://github.com/idfkit/idfkit/commit/b415635))
|
|
210
|
+
- `prep_outputs()` requested the `AllSummary` tabular report, which it never had. It passed
|
|
211
|
+
`report_1`, a spelling `Output:Table:SummaryReports` does not have, so `write_idf()` wrote the object with
|
|
212
|
+
no fields and no terminator, and EnergyPlus read the next object into it and stopped with a
|
|
213
|
+
fatal error. ([381c12f](https://github.com/idfkit/idfkit/commit/381c12f),
|
|
214
|
+
[1fe5171](https://github.com/idfkit/idfkit/commit/1fe5171))
|
|
215
|
+
- `OutputVariableIndex.add_all_to_model` stored each meter name in the `key_name` field of the
|
|
216
|
+
`Output:Meter` objects it adds. It used to pass the name as the object name, which
|
|
217
|
+
`Output:Meter` does not have, so both writers dropped it: `write_idf` emitted
|
|
218
|
+
`Output:Meter,,Timestep;` and EnergyPlus stopped with `Missing required property 'key_name'`.
|
|
219
|
+
The added meters now have an empty name, like meters loaded from a file, so
|
|
220
|
+
`doc["Output:Meter"]["<meter>"]` no longer finds them, and calling `add_all_to_model` twice
|
|
221
|
+
adds each meter twice instead of raising `DuplicateObjectError`
|
|
222
|
+
([d214b51](https://github.com/idfkit/idfkit/commit/d214b51)).
|
|
223
|
+
- `IDFCollection.remove` (and so `IDFDocument.removeidfobject`) removed the first object equal
|
|
224
|
+
to the one passed instead of that object. Two objects of a type with no Name field are equal
|
|
225
|
+
when their fields match, so removing one `Output:Meter` could remove another and leave the
|
|
226
|
+
one passed in the document ([c6514d0](https://github.com/idfkit/idfkit/commit/c6514d0)).
|
|
227
|
+
- The `hvac-loops` and `reference-tracking` agent references no longer state that
|
|
228
|
+
`validate_document` reports node-name typos. It reports a dangling object-name reference as
|
|
229
|
+
`E009`, not `E004`, and does not check node names at all. They also no longer list setpoint
|
|
230
|
+
managers among the objects `get_referencing` returns for a coil, and the node walk under
|
|
231
|
+
"Common mistakes" now finds a node in any field, including branch components and outdoor-air
|
|
232
|
+
mixer streams, so it no longer fails on correct models such as `5ZoneAirCooled`.
|
|
233
|
+
- Threads asking for the same schema version at the same moment each loaded and built their own copy, so a cold start with 16 threads read the schema file 16 times and handed out 16 different `EpJSONSchema` instances. All but one were then pickled by content instead of by version. The manager now loads each version once and gives every thread the same instance, and on a free-threaded build the first calls to `get_schema_manager()` no longer create several managers ([#254](https://github.com/idfkit/idfkit/pull/254)).
|
|
234
|
+
- `ScheduleFileCache.get_values` could raise `KeyError` when another thread cleared or invalidated the cache between its store and its read, and `ScheduleFileCache.invalidate` could raise `RuntimeError: dictionary changed size during iteration` when another thread added an entry while it ran. A read still in flight when another thread called `invalidate` or `clear` also cached what it had read before the call, which silently undid the invalidation; such a read is now returned but not cached ([#254](https://github.com/idfkit/idfkit/pull/254)).
|
|
235
|
+
- `SchemaManager.clear_cache` did not stop a load already in flight from caching its schema afterwards, so the clear was undone and a request made after it could be handed the pre-clear instance. Such a load now returns its schema to its caller without caching it. A logging handler or other code that asks for the version being loaded no longer deadlocks on the new load lock ([#254](https://github.com/idfkit/idfkit/pull/254)).
|
|
236
|
+
- `copy.deepcopy` of a `ScheduleFileCache` or `SchemaManager` that other threads were using could raise `RuntimeError: dictionary changed size during iteration`, and `copy.copy` of a cache returned an alias that shared its entries but not its invalidations. Both now copy a consistent snapshot into an independent object, and instances pickled by idfkit 1.2.0 still load and work ([#254](https://github.com/idfkit/idfkit/pull/254)).
|
|
237
|
+
- `ScheduleFileCache.invalidate` discarded every read in flight, of any file, so a steady stream of invalidations of one file stopped the cache caching the others. It now discards only reads of the file it invalidates. A child forked while another thread was inside `invalidate` or `clear` no longer inherits a half-invalidated cache ([#254](https://github.com/idfkit/idfkit/pull/254)).
|
|
238
|
+
- The weather cache is now safe to share between threads and processes. `WeatherDownloader.download` wrote the archive, the extracted files and the cleaned DDY in place, so callers downloading the same station at once could read a truncated file or raise "Downloaded file is not a valid ZIP archive", and a truncated file could stay in the cache for good; `StationIndex.refresh()` likewise rewrote `stations.json.gz` and its KML sources in place, so a concurrent `StationIndex.load()` raised `EOFError` or moved the half-written index aside. Every weather cache file, the IP-location cache and downloaded schemas are now written under a temporary name and renamed into place, with the permissions an in-place write would have given them. Extracted files carry their archive's modification time and size, so a file left truncated by an older version, or extracted from an archive that has since been replaced, is extracted again, and a corrupt archive is downloaded again on the next call. Threads of one process download a station once. Files inside folders of an archive, such as macOS `__MACOSX` resource forks, are no longer extracted beside the weather files ([#254](https://github.com/idfkit/idfkit/pull/254)).
|
|
239
|
+
- A child process forked while another thread was waiting out the geocoding rate limit hung on its first `geocode()` or `detect_location()` call ([#254](https://github.com/idfkit/idfkit/pull/254)).
|
|
240
|
+
- `simulate` computed the cache key from the caller's model before copying it, so an edit made on another thread in between could store one model's results under another model's key. `async_simulate` read the caller's model on a worker thread after copying it, which raised on a free-threaded build when another coroutine edited the model meanwhile. Both now work only from their copy ([#254](https://github.com/idfkit/idfkit/pull/254)).
|
|
241
|
+
- `expand_objects`, `IDFDocument.expand` and the ground heat-transfer preprocessors returned a
|
|
242
|
+
strict document for a model opened with `strict=False` whenever a preprocessor ran; only a model
|
|
243
|
+
with nothing to expand came back as it was. The result now keeps the model's strictness, as
|
|
244
|
+
`IDFDocument.copy` does ([#194](https://github.com/idfkit/idfkit/issues/194), [#251](https://github.com/idfkit/idfkit/pull/251)).
|
|
245
|
+
|
|
10
246
|
## [1.2.0] - 2026-10-28
|
|
11
247
|
|
|
12
248
|
This release moves to `conformance-2026.21`. Through `conformance-2026.19`, the level the TypeScript library also declares, the corpus adds five cases for the multi-field `update` shared with the TypeScript library, an `update` operation and a `post-operation-epjson` assertion (`conformance-2026.17`), and removes the divergence entries for those cases in both languages: the ten Python entries that `IDFObject.update` closes (`conformance-2026.18`) and the six TypeScript ones (`conformance-2026.19`). `conformance-2026.20` then removes the two Python round-trip entries that #183 closes. An idfkit release without `IDFObject.update` fails the five update cases at this level, and one that still stores a blank fixed field as `""` fails those two. `conformance-2026.21` removes the three Python entries that #187 closes, so a release that still drops an unterminated final object fails `malformed-truncated-object` and `preserve-unterminated-final`.
|
|
@@ -977,7 +1213,8 @@ Initial public release.
|
|
|
977
1213
|
- Performance benchmarks comparing idfkit against eppy and opyplus. ([#5](https://github.com/idfkit/idfkit/pull/5))
|
|
978
1214
|
- MkDocs Material documentation site with a full API reference, an eppy migration guide, and a getting-started Jupyter notebook. ([#2](https://github.com/idfkit/idfkit/pull/2))
|
|
979
1215
|
|
|
980
|
-
[Unreleased]: https://github.com/idfkit/idfkit/compare/v1.
|
|
1216
|
+
[Unreleased]: https://github.com/idfkit/idfkit/compare/v1.3.0-rc.1...HEAD
|
|
1217
|
+
[1.3.0-rc.1]: https://github.com/idfkit/idfkit/compare/v1.2.0...v1.3.0-rc.1
|
|
981
1218
|
[1.2.0]: https://github.com/idfkit/idfkit/compare/v1.1.1...v1.2.0
|
|
982
1219
|
[1.1.1]: https://github.com/idfkit/idfkit/compare/v1.1.0...v1.1.1
|
|
983
1220
|
[1.1.0]: https://github.com/idfkit/idfkit/compare/v1.0.0...v1.1.0
|
|
@@ -14,12 +14,14 @@ Key capabilities: IDF/epJSON parsing and writing, schema-driven validation, 3D g
|
|
|
14
14
|
|
|
15
15
|
The core package — including simulation, schedules, thermal, and geometry — has **zero third-party dependencies** (stdlib only). Optional extras (defined in `pyproject.toml`):
|
|
16
16
|
|
|
17
|
-
- `
|
|
18
|
-
- `pandas`
|
|
17
|
+
- `sim` — empty; simulation needs no extras
|
|
18
|
+
- `pandas` — pandas (for DataFrame result conversion); `dataframes` is an alias
|
|
19
19
|
- `plot` — matplotlib | `plotly` — plotly (plotting backends)
|
|
20
20
|
- `progress` — tqdm (simulation progress bars)
|
|
21
|
-
- `s3`
|
|
22
|
-
- `all` —
|
|
21
|
+
- `s3` — boto3 (`cloud` is an alias) | `async-s3` — aiobotocore (cloud storage)
|
|
22
|
+
- `all` — pandas, matplotlib, plotly, boto3, aiobotocore and tqdm
|
|
23
|
+
|
|
24
|
+
There is no `weather` extra: weather search, download and station-index refresh are stdlib only.
|
|
23
25
|
|
|
24
26
|
## Common Commands
|
|
25
27
|
|
|
@@ -12,7 +12,7 @@ install: ## Install the virtual environment and install the pre-commit hooks
|
|
|
12
12
|
check-stubs: ## Verify generated type stubs are up-to-date
|
|
13
13
|
@echo "🚀 Checking type stub consistency"
|
|
14
14
|
@uv run python -m idfkit.codegen.generate_stubs
|
|
15
|
-
@git diff --exit-code src/idfkit/_generated_types.pyi src/idfkit/document.pyi || \
|
|
15
|
+
@git diff --exit-code src/idfkit/_generated_types.pyi src/idfkit/document.pyi src/idfkit/versioned.pyi src/idfkit/versioned.py || \
|
|
16
16
|
(echo "❌ Generated stubs are out of date. Run: uv run python -m idfkit.codegen.generate_stubs" && exit 1)
|
|
17
17
|
|
|
18
18
|
.PHONY: check-conformance-level
|
|
@@ -99,7 +99,7 @@ test: ## Test the code with pytest
|
|
|
99
99
|
@uv run python -m pytest --cov --cov-config=pyproject.toml --cov-report=xml
|
|
100
100
|
|
|
101
101
|
.PHONY: weather-index
|
|
102
|
-
weather-index: ## Rebuild the bundled weather station index (requires network
|
|
102
|
+
weather-index: ## Rebuild the bundled weather station index (requires network; standard library only)
|
|
103
103
|
@echo "🚀 Building weather station index"
|
|
104
104
|
@uv run python scripts/build_weather_index.py
|
|
105
105
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: idfkit
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0rc1
|
|
4
4
|
Summary: A fast, modern EnergyPlus IDF/epJSON parser with O(1) lookups and reference tracking
|
|
5
|
-
Project-URL: Homepage, https://
|
|
5
|
+
Project-URL: Homepage, https://developers.idfkit.com/
|
|
6
6
|
Project-URL: Repository, https://github.com/idfkit/idfkit
|
|
7
|
-
Project-URL: Documentation, https://
|
|
7
|
+
Project-URL: Documentation, https://developers.idfkit.com/
|
|
8
8
|
Author-email: Samuel Letellier-Duchesne <developers@idfkit.com>
|
|
9
9
|
License-File: LICENSE
|
|
10
10
|
Keywords: building simulation,energy modeling,energyplus,epjson,idf,parser
|
|
@@ -18,6 +18,8 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta
|
|
21
23
|
Classifier: Topic :: Scientific/Engineering
|
|
22
24
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
25
|
Classifier: Typing :: Typed
|
|
@@ -48,12 +50,21 @@ Requires-Dist: boto3>=1.26; extra == 's3'
|
|
|
48
50
|
Provides-Extra: sim
|
|
49
51
|
Description-Content-Type: text/markdown
|
|
50
52
|
|
|
53
|
+
<p align="center">
|
|
54
|
+
<picture>
|
|
55
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/idfkit/idfkit-brand/identity-2026.5/marks/mark-on-dark.svg">
|
|
56
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/idfkit/idfkit-brand/identity-2026.5/marks/mark-on-light.svg">
|
|
57
|
+
<img alt="idfkit" width="72" src="https://raw.githubusercontent.com/idfkit/idfkit-brand/identity-2026.5/marks/tile.png">
|
|
58
|
+
</picture>
|
|
59
|
+
</p>
|
|
60
|
+
|
|
51
61
|
# idfkit
|
|
52
62
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
[
|
|
56
|
-
|
|
63
|
+
An EnergyPlus IDF and epJSON toolkit for Python, with no third-party dependencies.
|
|
64
|
+
|
|
65
|
+
[idfkit](https://idfkit.com) · [Developers](https://developers.idfkit.com) · [EnergyPlus docs](https://docs.idfkit.com) · [Envelop](https://app.idfkit.com) · [MCP](https://mcp.idfkit.com) · [Shoebox](https://shoebox.idfkit.com) · [GitHub](https://github.com/idfkit)
|
|
66
|
+
|
|
67
|
+
[](https://github.com/idfkit/idfkit/releases) [](https://github.com/idfkit/idfkit/actions/workflows/main.yml?query=branch%3Amain) [](https://codecov.io/gh/idfkit/idfkit) [](https://github.com/idfkit/idfkit/blob/main/LICENSE) [](https://developers.idfkit.com/explanation/parity/)
|
|
57
68
|
|
|
58
69
|
**A fast, modern EnergyPlus IDF/epJSON toolkit for Python.**
|
|
59
70
|
|
|
@@ -64,9 +75,9 @@ Description-Content-Type: text/markdown
|
|
|
64
75
|
>
|
|
65
76
|
> Code that still calls `write_*` with a path fails without naming the cause:
|
|
66
77
|
> `write_epjson(doc, path)` raises `TypeError: can't multiply sequence by
|
|
67
|
-
> non-int of type 'PosixPath'`, and `write_idf(doc, path)`
|
|
68
|
-
>
|
|
69
|
-
>
|
|
78
|
+
> non-int of type 'PosixPath'`, and `write_idf(doc, path)` takes the path as
|
|
79
|
+
> its `output_type` argument, returns the IDF text, and writes no file, so the
|
|
80
|
+
> failure surfaces only when the file is next read.
|
|
70
81
|
>
|
|
71
82
|
> Search for `write_idf(` and `write_epjson(` called with two positional
|
|
72
83
|
> arguments, or run a type checker, which rejects both. Full notes are in the
|
|
@@ -115,8 +126,8 @@ formats.
|
|
|
115
126
|
|
|
116
127
|
## Performance
|
|
117
128
|
|
|
118
|
-
idfkit is designed from the ground up for speed. On a **1,700-object IDF
|
|
119
|
-
looking up a single object by name is **over
|
|
129
|
+
idfkit is designed from the ground up for speed. On a **1,700-object IDF**
|
|
130
|
+
(Darwin arm64, median of 5 runs), looking up a single object by name is **over 2,000x** faster than eppy, **over 3,500x** faster than opyplus, and **over 130x** faster than energyplus-idd-idf-utilities
|
|
120
131
|
thanks to O(1) dict-based indexing:
|
|
121
132
|
|
|
122
133
|
<picture>
|
|
@@ -127,6 +138,7 @@ thanks to O(1) dict-based indexing:
|
|
|
127
138
|
|
|
128
139
|
See [full benchmark results](https://developers.idfkit.com/benchmarks/)
|
|
129
140
|
for all six operations (load, get by type, get by name, add, modify, write) across four tools.
|
|
141
|
+
energyplus-idd-idf-utilities is measured on four of them (load, get by type, get by name, write).
|
|
130
142
|
|
|
131
143
|
## Installation
|
|
132
144
|
|
|
@@ -146,13 +158,16 @@ uv add idfkit
|
|
|
146
158
|
|
|
147
159
|
| Extra | Install command | What it adds |
|
|
148
160
|
|-------|----------------|--------------|
|
|
149
|
-
| `
|
|
150
|
-
| `
|
|
161
|
+
| `sim` | `pip install idfkit[sim]` | Nothing; simulation requires no extra packages |
|
|
162
|
+
| `pandas` | `pip install idfkit[pandas]` | DataFrame result conversion (pandas) |
|
|
163
|
+
| `dataframes` | `pip install idfkit[dataframes]` | Alias of `pandas` |
|
|
151
164
|
| `s3` | `pip install idfkit[s3]` | S3 cloud storage backend (boto3) |
|
|
165
|
+
| `async-s3` | `pip install idfkit[async-s3]` | Asynchronous S3 storage backend (aiobotocore) |
|
|
166
|
+
| `cloud` | `pip install idfkit[cloud]` | Alias of `s3` |
|
|
152
167
|
| `plot` | `pip install idfkit[plot]` | Matplotlib plotting |
|
|
153
168
|
| `plotly` | `pip install idfkit[plotly]` | Plotly interactive charts |
|
|
154
169
|
| `progress` | `pip install idfkit[progress]` | tqdm progress bars for simulations |
|
|
155
|
-
| `all` | `pip install idfkit[all]` |
|
|
170
|
+
| `all` | `pip install idfkit[all]` | pandas, matplotlib, plotly, boto3, aiobotocore, and tqdm |
|
|
156
171
|
|
|
157
172
|
## Quick Example
|
|
158
173
|
|
|
@@ -177,9 +192,11 @@ for obj in doc.get_referencing("Office"):
|
|
|
177
192
|
save_idf(doc, "out.idf")
|
|
178
193
|
```
|
|
179
194
|
|
|
180
|
-
> **Note:** `load_idf()` defaults to strict parsing (`
|
|
181
|
-
> `IDFParseError` on malformed objects. Use `
|
|
182
|
-
> migration/compatibility fallback for legacy or noisy files.
|
|
195
|
+
> **Note:** `load_idf()` defaults to strict parsing (`strict_parsing=True`) and
|
|
196
|
+
> raises `IDFParseError` on malformed objects. Use `strict_parsing=False` only as a
|
|
197
|
+
> tolerant migration/compatibility fallback for legacy or noisy files. The separate
|
|
198
|
+
> `strict` argument (default `True`) makes reading or setting an unknown field name
|
|
199
|
+
> on an object raise `InvalidFieldError` instead of returning `None`.
|
|
183
200
|
|
|
184
201
|
### Creating a model from scratch
|
|
185
202
|
|
|
@@ -239,10 +256,12 @@ The two share a vocabulary and are held to a
|
|
|
239
256
|
that proves they read and write the same files the same way.
|
|
240
257
|
|
|
241
258
|
They are not equivalent, and this page will not imply that they are. All
|
|
242
|
-
|
|
259
|
+
fourteen first-tier capabilities exist in both: parsing, the object model,
|
|
243
260
|
references, writers, schema access, validation, introspection, documentation
|
|
244
261
|
addresses, generated object types, parse diagnostics, the weather station index,
|
|
245
|
-
weather file retrieval,
|
|
262
|
+
weather file retrieval, geocoding, and the conformance declaration. Three of them
|
|
263
|
+
are recorded as partial on one side: generated object types in Python, and the
|
|
264
|
+
weather station index and weather file retrieval in JavaScript. Almost everything else on this page is
|
|
246
265
|
Python-only today, including running EnergyPlus locally, reading simulation
|
|
247
266
|
results, geometry authoring, zoning, schedules, thermal properties, and
|
|
248
267
|
migration. Some of that is a port not yet done; some of it, such as driving a
|
|
@@ -296,7 +315,6 @@ baked into that exact version.
|
|
|
296
315
|
make install # Install dependencies and pre-commit hooks
|
|
297
316
|
make check # Run linting, formatting, and type checks
|
|
298
317
|
make test # Run tests with coverage
|
|
299
|
-
make docs # Serve documentation locally
|
|
300
318
|
```
|
|
301
319
|
|
|
302
320
|
## Contributing
|