Skip to main content

idfpy

PyPI Python 3.12+ License: MIT EnergyPlus 26.1 Autoupdate Ask DeepWiki

Type-safe Pydantic models for all EnergyPlus IDF object types, plus IDF file read/write and simulation execution, optimized for LLM tool calling and IDE auto-completion.

Auto-generated from Energy+.schema.epJSON version 26.1.0.

Features

  • 859 object types as Pydantic v2 models with full validation
  • 275 reference types with cross-object validation
  • Forward navigationsurface.zone resolves one reference field; surface.referenced() returns every referenced object
  • Reverse navigationzone.referencing("Lights") finds all objects that reference a given object
  • Reference validationidf.validate() batch-checks all cross-object references for existence and type compatibility
  • Extension plugin systemsurface.area, .normal, .centroid via auto-discovered geometry mixins with full IDE support
  • Case-insensitive Literal field matching (EnergyPlus IDF is case-insensitive)
  • Extensible field support (vertices, schedule data, etc.)
  • IDF read/write with positional field ordering
  • epJSON read/write with auto-detection by file extension
  • to_dict() / from_dict() for in-memory dict conversion (ideal for LLM tool calls)
  • EnergyPlus simulation execution with ExpandObjects support
  • Accepts both snake_case and original EnergyPlus schema key names

Why idfpy over eppy?

idfpy eppy
No EnergyPlus IDD required at runtime
Type-safe field validation ✅ Pydantic v2
epJSON read/write
Cross-reference validation ✅ 275 ref groups
Forward/reverse navigation ✅ 2849 properties
Surface geometry (area/normal) ✅ ext plugin
to_dict() / from_dict() for LLM
Dependencies 4 (pydantic, jinja2, loguru, typer) 12+ (lxml, pyparsing...)

Installation

pip install idfpy

Quick Start

from pathlib import Path
from idfpy import IDF
from idfpy.models import Version, Building, Zone

# Create an IDF
idf = IDF()
idf.add(Version())
idf.add(Building(name='MyBuilding', north_axis=0.0))
idf.add(Zone(name='Zone1'))

# Save as IDF
idf.save(Path('output.idf'))

# Save as epJSON
idf.save(Path('output.epjson'), output_type='epjson')

# Load (auto-detects format by extension)
idf = IDF.load(Path('existing.idf'))  # IDF format
idf = IDF.load(Path('existing.epjson'))  # epJSON format

# Run simulation
from idfpy.sim import simulate

result = simulate(
    Path('output.idf'), weather=Path('weather.epw'), output_dir=Path('results/')
)
print(result.success)  # True / False

In-memory dict conversion

from pathlib import Path
from idfpy import IDF

idf = IDF.load(Path('model.idf'))

# IDF → dict (epJSON structure)
data = idf.to_dict()
# {
#   "Building": {"MyBuilding": {"north_axis": 0.0, "terrain": "Suburbs"}},
#   "Zone": {"Zone1": {"direction_of_relative_north": 0.0}},
#   ...
# }

# dict → IDF
idf = IDF.from_dict(data)

Logging

idfpy keeps INFO and higher-level logs available through Loguru. Detailed per-object and internal progress messages use Loguru's TRACE level, so they do not appear in a handler configured at DEBUG level. To inspect these messages, configure a TRACE sink explicitly:

from loguru import logger

logger.add('idfpy.log', level='TRACE')

Object navigation

Every reference field generates a @property for direct forward navigation. referenced() returns all objects referenced by an object, while referencing() provides reverse navigation. These navigation methods and all query methods (get / has / all_of_type / remove) accept either an EnergyPlus type string, a Python class name, or the model class itself — passing the class preserves precise typing in your IDE.

from pathlib import Path
from idfpy import IDF
from idfpy.models import BuildingSurfaceDetailed, Zone

idf = IDF.load(Path('model.idf'))

# Forward navigation — resolve reference to target object
surface = idf.get(BuildingSurfaceDetailed, 'Wall1')  # → BuildingSurfaceDetailed | None
surface.zone_name  # "Zone1" (raw string, always works)
surface.zone  # Zone object (resolved via IDF)
surface.construction  # Construction object
surface.referenced()  # [Construction object, Zone object, ...]
surface.referenced(Zone)  # [Zone object]

# Reverse navigation — find all objects referencing a given object
zone = idf.get(Zone, 'Zone1')
zone.referencing(BuildingSurfaceDetailed)  # → [Wall1, Wall2, ...]
zone.referencing('Lights')  # → [OfficeLights, ...]

# Chained navigation
zone.referencing(BuildingSurfaceDetailed)[0].construction

Strict type-name validation (default)

Query methods raise UnknownObjectTypeError when the type name cannot be resolved — this surfaces typos immediately instead of returning an empty result. Pass strict=False for the legacy silent behavior.

from idfpy import UnknownObjectTypeError

try:
    idf.get('BuildingSurface:detailed', 'Wall1')  # note the lowercase 'd'
except UnknownObjectTypeError as e:
    print(e)  # → Unknown object type: 'BuildingSurface:detailed'. ...

# Opt-in legacy silent behavior
idf.get('BuildingSurface:detailed', 'Wall1', strict=False)  # → None

Reference validation

from idfpy import IDF, RefValidationError

idf = IDF.load(Path('model.idf'))

# Batch check all cross-object references
errors = idf.validate()
for e in errors:
    print(e)
# [missing] Lights/OffLights.schedule_name: "BadSched" not found in any of [ScheduleNames]

# Or raise on first broken reference set
try:
    idf.validate_or_raise()
except RefValidationError as exc:
    print(f'{len(exc.errors)} broken reference(s)')

Real-world Example

from pathlib import Path
from idfpy import IDF

# Load a DOE reference building
idf = IDF.load(Path('LargeOffice.idf'))

# Modify all exterior walls' insulation
for con_name, con in idf.all_of_type('Construction').items():
    layer = con.outside_layer_ref
    if layer and hasattr(layer, 'conductivity'):
        print(f'{con.name}: k={layer.conductivity} W/m·K')

# Validate all references
errors = idf.validate()
print(f'{len(errors)} broken references')

Geometry extensions

Surface models include geometry properties via the built-in ext.geometry plugin — area, normal vector, and centroid are computed from vertices using Newell's method, with full IDE autocompletion.

from idfpy import IDF
from pathlib import Path

idf = IDF.load(Path('model.idf'))

surface = idf.get('BuildingSurface:Detailed', 'Wall1')
surface.area  # 30.0 (m²)
surface.normal  # (0.0, -1.0, 0.0) — outward unit normal
surface.centroid  # (5.0, 0.0, 1.5)
surface.vertices_as_tuples  # [(0,0,3), (0,0,0), (10,0,0), (10,0,3)]

window = idf.get('FenestrationSurface:Detailed', 'Win1')
window.area  # 16.0 (m²)

Supported surface types: BuildingSurface:Detailed, FenestrationSurface:Detailed, Floor:Detailed, RoofCeiling:Detailed, Wall:Detailed, Shading:Building:Detailed, Shading:Site:Detailed, Shading:Zone:Detailed.

Creating custom plugins

Extensions live in idfpy/ext/ as sub-packages. Each plugin exposes a MIXIN_MAP that the code generator auto-discovers:

# idfpy/ext/thermal/__init__.py
from .mixins import ThermalPropertyMixin

MIXIN_MAP: dict[str, type] = {
    'BuildingSurfaceDetailed': ThermalPropertyMixin,
}
# idfpy/ext/thermal/mixins.py
class ThermalPropertyMixin:
    @property
    def u_value(self) -> float:
        """Compute U-value from construction layers."""
        ...

After adding a plugin, re-run idfpy codegen to regenerate models — the mixin is injected into the class hierarchy and IDE autocompletion works immediately.

Container mutation

from idfpy.models import Zone

idf.remove(Zone, 'Zone1')  # unbinds + unregisters references
idf.remove('Zone', 'Zone1')  # string form (EnergyPlus or Python class name)

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

idfpy-26.1.2.tar.gz (620.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

idfpy-26.1.2-py3-none-any.whl (634.4 kB view details)

Uploaded Python 3

File details

Details for the file idfpy-26.1.2.tar.gz.

File metadata

  • Download URL: idfpy-26.1.2.tar.gz
  • Upload date:
  • Size: 620.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for idfpy-26.1.2.tar.gz
Algorithm Hash digest
SHA256 297e98e67193f7a4c5a35f1b9cc0d57f85c5a8affde49d767676f3144e5ac250
MD5 aba1ffb62e3a1f1b572570e7ce774a29
BLAKE2b-256 7cb15212ce79bab7de40ea54b36849638a8d4758fb7ee83d7cda3b485883bf46

See more details on using hashes here.

Provenance

The following attestation bundles were made for idfpy-26.1.2.tar.gz:

Publisher: release-version.yml on ITOTI-Y/idfpy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file idfpy-26.1.2-py3-none-any.whl.

File metadata

  • Download URL: idfpy-26.1.2-py3-none-any.whl
  • Upload date:
  • Size: 634.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for idfpy-26.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 e8934c161d485d21f8dd167129fe298967dba64935b7f042fa126d5d5951c0ab
MD5 92e6848e87b05484df27aa10dc99ff82
BLAKE2b-256 8cfccf1a36b3ba024b41ddc9ba49178c1f859b17d6a4777d9382876907d182d2

See more details on using hashes here.

Provenance

The following attestation bundles were made for idfpy-26.1.2-py3-none-any.whl:

Publisher: release-version.yml on ITOTI-Y/idfpy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

26.1.2 This release

2 files

26.1.1

2 files

26.1.0.post5

2 files

26.1.0.post4

2 files

26.1.0.post3

2 files

26.1.0.post2

2 files

26.1.0.post1

2 files

26.1.0

2 files

25.2.2

2 files

25.2.1

2 files

25.2.0.post4

2 files

25.2.0.post3

2 files

25.2.0.post2

2 files

25.2.0.post1

2 files

25.2.0

2 files

25.1.0.post2

2 files

25.1.0.post1

2 files

25.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page