The epanetparser Library
Usage
Overview
The WNTREPANETNetwork class provides a simple interface for an EPANET
model to be parsed, represented as a Python object, and validated.
Two factory methods create an instance:
WNTREPANETNetwork.from_file()WNTREPANETNetwork.from_json()
…which operate on a file and a JSON string respectively. For example, to load a model with the default arguments:
from importlib.resources import files
from epanetparser.core.epanettypes.network import WNTREPANETNetwork
model = files("epanetparser.networks.core") / "Net1.inp"
network, errors, warnings = WNTREPANETNetwork.from_file(model)
Five example networks ship with the package under epanetparser.networks.core,
so there is a model to try this against without downloading anything. Both
.inp and WNTR .json files are accepted. An .inp file is converted to
WNTR’s JSON representation with WNTR before being parsed, so the model you get
back is always built from the JSON form.
If the input parses, the network variable holds the model and errors is
None. If it does not, network is None and errors holds the
structural problems. warnings holds any warnings raised during parsing, or
is None if there were none. Either network or errors is not None,
but not both.
Parsing reports structural problems only. Semantic checks are a separate step:
report = network.validate()
assert report.is_valid, [issue.code for issue in report.errors]
This separation is deliberate: assigning component.data never validates and
never raises, so building a model cannot fail because of a rule.
The errors and warnings objects
When present, the errors and warnings objects returned by the factory
methods are each a dictionary mapping the string names of EPANET network
components (nodes, links, curves, and so on) to the list of errors or
warnings generated for them.
Rule sets
Validation runs against a rule set. Exactly one core rule set is always applied; custom rule sets are added alongside it:
report = network.validate(["epanet_core", "milp"])
The selection may be given as a key, a list of keys, a
ValidationContext, or a mapping, so a project can put the choice in one
place:
from epanetparser.core.validation import ValidationContext
context = ValidationContext(core="epanet_core", custom=["milp"])
report = network.validate(context)
A key that is not discovered raises RuleSetSelectionError rather than
being ignored, so a typo in a rule set name fails loudly instead of silently
validating less than you asked for.
Results
validate() returns a ValidationReport, never an exception for a
rule failure. A rule that raises anything other than AssertionError is a
defect in the rule, and raises RuleExecutionError instead of being
reported as a finding about the model.
report.is_valid # False if any finding is Severity.ERROR
report.errors # the findings that block simulation
report.warnings # findings that inform without blocking
report.by_code("E_UNKNOWN_CURVE_REFERENCE")
report.by_component("T1")
report.grouped_by_component() # the shape display.write_results consumes
report.as_dict() # JSON-serialisable
A single component can also be validated on its own, with only the rules that apply to it:
for node in network.nodes:
for issue in node.validate().errors:
print(issue.code, issue.component_name, issue.message)
The results_as_dict and results_as_json functions in
epanetparser.core.display translate a report into dict and JSON forms
respectively, and write_results() renders it on the console.
See Rules, Warnings, and Rule Sets for how to write rules and rule sets.