Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.10", "3.11"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v4
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
[0.1.3] - 2026-02-03
--------------------

**Changed**
- Replaced deprecated `@classmethod @property` pattern in `GObject` with standard `@classmethod` methods for Python 3.13 compatibility (e.g. `Bus.keys` is now `Bus.keys()`)
- Added Python 3.12 and 3.13 to CI test matrix

[0.1.2] - 2026-02-03
--------------------

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.2
0.1.3
16 changes: 8 additions & 8 deletions docs/dev/components.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@ define fields with ``(PowerWorld name, data type, priority flags)``:
"""Name"""
# ... more fields ...

ObjectString = 'Bus' # Sets Bus.TYPE — must be last member
ObjectString = 'Bus' # Sets Bus.TYPE() — must be last member

The base class collects these into queryable properties:
The base class collects these into queryable classmethods:

.. code-block:: python

Bus.TYPE # 'Bus' - PowerWorld object type (from ObjectString)
Bus.keys # ['BusNum'] - primary key fields
Bus.fields # all field names
Bus.secondary # alternate identifier fields
Bus.editable # user-modifiable fields
Bus.TYPE() # 'Bus' - PowerWorld object type (from ObjectString)
Bus.keys() # ['BusNum'] - primary key fields
Bus.fields() # all field names
Bus.secondary() # alternate identifier fields
Bus.editable() # user-modifiable fields

Field Priority Flags
~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -131,4 +131,4 @@ API Stability
ESA++ uses semantic versioning:

- **Public API** (stable): PowerWorld, component classes, exception types
- **Internal API** (may change): SAW mixins, Indexable internals, GObject metaclass
- **Internal API** (may change): SAW mixins, Indexable internals, GObject internals
10 changes: 5 additions & 5 deletions docs/examples/getting_started/02_writing_data.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
"execution_count": 1,
"id": "hidden-setup",
"metadata": {
"nbsphinx": "hidden",
"tags": [
"remove-cell"
],
"nbsphinx": "hidden"
]
},
"outputs": [
{
Expand Down Expand Up @@ -96,7 +96,7 @@
"id": "array-md",
"metadata": {},
"source": [
"**Per-element values** — a list or array whose length matches the number\n",
"**Per-element values** - a list or array whose length matches the number\n",
"of objects sets each one individually."
]
},
Expand All @@ -115,7 +115,7 @@
"id": "multifield-md",
"metadata": {},
"source": [
"**Multiple fields** — pass a list of field names and a matching list\n",
"**Multiple fields** - pass a list of field names and a matching list\n",
"of values to set several columns at once."
]
},
Expand All @@ -138,7 +138,7 @@
"\n",
"For targeted updates to specific objects, build a DataFrame that\n",
"includes the primary-key columns and the fields you want to change.\n",
"Only the rows present in the DataFrame are modified — everything\n",
"Only the rows present in the DataFrame are modified - everything\n",
"else stays untouched."
]
},
Expand Down
27 changes: 13 additions & 14 deletions docs/examples/getting_started/03_components_and_fields.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,15 @@
"execution_count": 1,
"id": "hidden-setup",
"metadata": {
"nbsphinx": "hidden",
"tags": [
"remove-cell"
],
"nbsphinx": "hidden"
]
},
"outputs": [],
"source": [
"from esapp.components import *\n",
"from esapp import TS\n",
"from esapp.components import TSField"
"from esapp import TS"
]
},
{
Expand Down Expand Up @@ -72,7 +71,7 @@
}
],
"source": [
"Bus.keys, Gen.keys, Branch.keys"
"Bus.keys(), Gen.keys(), Branch.keys()"
]
},
{
Expand All @@ -82,21 +81,21 @@
"source": [
"Beyond primary keys, each component has several field categories:\n",
"\n",
"- **Identifiers** — the union of primary and secondary keys (like\n",
"- **Identifiers** - the union of primary and secondary keys (like\n",
" `BusName` or `AreaNum`). Secondary keys help PowerWorld resolve\n",
" which object you mean during writes.\n",
"- **Editable** — fields you can modify (generation setpoints, voltage\n",
"- **Editable** - fields you can modify (generation setpoints, voltage\n",
" targets, load values, etc.). Writing to a read-only field raises\n",
" a `ValueError`.\n",
"- **Settable** — identifiers plus editable fields, i.e. everything\n",
"- **Settable** - identifiers plus editable fields, i.e. everything\n",
" allowed in a write operation.\n",
"- **Fields** — the complete set of all known fields, including\n",
"- **Fields** - the complete set of all known fields, including\n",
" read-only calculated results."
]
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 8,
"id": "identifiers",
"metadata": {},
"outputs": [
Expand All @@ -106,13 +105,13 @@
"{'AreaNum', 'BusName', 'BusName_NomVolt', 'BusNomVolt', 'BusNum', 'ZoneNum'}"
]
},
"execution_count": 3,
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Bus.identifiers"
"Bus.identifiers()"
]
},
{
Expand All @@ -133,7 +132,7 @@
}
],
"source": [
"len(Bus.editable), len(Bus.settable), len(Bus.fields)"
"len(Bus.editable()), len(Bus.settable()), len(Bus.fields())"
]
},
{
Expand All @@ -144,7 +143,7 @@
"## Transient Stability Fields\n",
"\n",
"The `TS` class provides constants for transient stability result\n",
"fields, organized by object type — `TS.Gen`, `TS.Bus`, `TS.Branch`,\n",
"fields, organized by object type - `TS.Gen`, `TS.Bus`, `TS.Branch`,\n",
"`TS.Load`, etc. Each field is a `TSField` with a `name` and\n",
"`description`. Typing `TS.Gen.` in your IDE autocompletes every\n",
"available generator result field.\n",
Expand Down
55 changes: 6 additions & 49 deletions docs/examples/getting_started/04_creating_objects.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -59,41 +59,15 @@
"cell_type": "markdown",
"id": "prereqs-md",
"metadata": {},
"source": [
"## Prerequisites\n",
"\n",
"PowerWorld must be in **EDIT mode** before you can add new objects. Call `pw.edit_mode()` to enter it, and `pw.run_mode()` when you're done.\n",
"\n",
"The DataFrame you write should include all **identifier** fields\n",
"for the object type — that's the union of primary keys and\n",
"secondary keys. You can inspect these with `Bus.identifiers`,\n",
"`Gen.identifiers`, etc. Primary keys uniquely identify the object;\n",
"secondary keys provide the additional context PowerWorld needs to\n",
"fully define it (nominal voltage, area, zone, limits, etc.)."
]
"source": "## Prerequisites\n\nPowerWorld must be in **EDIT mode** before you can add new objects. Call `pw.edit_mode()` to enter it, and `pw.run_mode()` when you're done.\n\nThe DataFrame you write should include all **identifier** fields\nfor the object type — that's the union of primary keys and\nsecondary keys. You can inspect these with `Bus.identifiers()`,\n`Gen.identifiers()`, etc. Primary keys uniquely identify the object;\nsecondary keys provide the additional context PowerWorld needs to\nfully define it (nominal voltage, area, zone, limits, etc.)."
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": null,
"id": "show-keys",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Bus identifiers: {'BusNum', 'BusName_NomVolt', 'BusName', 'ZoneNum', 'BusNomVolt', 'AreaNum'}\n",
"Gen identifiers: {'GenMVRMax', 'GenMvrSetPoint', 'GenID', 'GenMWSetPoint', 'GenStatus', 'GenVoltSet', 'GenMVRMin', 'GenMWMax', 'BusNum', 'GenMWMin', 'GenAGCAble', 'BusName_NomVolt', 'GenAVRAble'}\n",
"Load identifiers: {'LoadSMW', 'BusNum', 'BusName_NomVolt', 'LoadStatus', 'LoadSMVR', 'LoadID'}\n"
]
}
],
"source": [
"# Identifier fields needed for creation\n",
"print(\"Bus identifiers:\", Bus.identifiers)\n",
"print(\"Gen identifiers:\", Gen.identifiers)\n",
"print(\"Load identifiers:\", Load.identifiers)"
]
"outputs": [],
"source": "# Identifier fields needed for creation\nprint(\"Bus identifiers:\", Bus.identifiers())\nprint(\"Gen identifiers:\", Gen.identifiers())\nprint(\"Load identifiers:\", Load.identifiers())"
},
{
"cell_type": "markdown",
Expand Down Expand Up @@ -464,24 +438,7 @@
"cell_type": "markdown",
"id": "tips-md",
"metadata": {},
"source": [
"## Tips\n",
"\n",
"- **Always enter edit mode** before creating objects and return\n",
" to run mode afterward. Forgetting this is the most common\n",
" cause of creation failures.\n",
"\n",
"- **Include all identifier fields** when creating objects. Use\n",
" `ComponentType.identifiers` to see the full set of primary and\n",
" secondary key fields. PowerWorld needs these to fully define\n",
" the object — omitting them may cause unexpected defaults or\n",
" creation failures.\n",
"\n",
"- **The broadcast syntax does not create objects.** Only the\n",
" DataFrame assignment path (`pw[Type] = df`) can create new\n",
" objects. The field-broadcast path\n",
" (`pw[Type, \"Field\"] = value`) only modifies existing ones."
]
"source": "## Tips\n\n- **Always enter edit mode** before creating objects and return\n to run mode afterward. Forgetting this is the most common\n cause of creation failures.\n\n- **Include all identifier fields** when creating objects. Use\n `ComponentType.identifiers()` to see the full set of primary and\n secondary key fields. PowerWorld needs these to fully define\n the object — omitting them may cause unexpected defaults or\n creation failures.\n\n- **The broadcast syntax does not create objects.** Only the\n DataFrame assignment path (`pw[Type] = df`) can create new\n objects. The field-broadcast path\n (`pw[Type, \"Field\"] = value`) only modifies existing ones."
}
],
"metadata": {
Expand All @@ -505,4 +462,4 @@
},
"nbformat": 4,
"nbformat_minor": 5
}
}
18 changes: 9 additions & 9 deletions docs/examples/getting_started/05_workbench_overview.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"Beyond the indexable interface, `PowerWorld` provides convenience\n",
"methods that wrap common workflows into single calls. These cover\n",
"data retrieval shortcuts, power flow, voltage analysis, matrix\n",
"extraction, sensitivity factors, and case control — so you spend\n",
"extraction, sensitivity factors, and case control - so you spend\n",
"less time assembling field lists and more time on analysis.\n",
"\n",
"```python\n",
Expand All @@ -26,10 +26,10 @@
"execution_count": 8,
"id": "hidden-setup",
"metadata": {
"nbsphinx": "hidden",
"tags": [
"remove-cell"
],
"nbsphinx": "hidden"
]
},
"outputs": [
{
Expand Down Expand Up @@ -61,7 +61,7 @@
"\n",
"These methods return DataFrames of common object types with their\n",
"most useful fields pre-selected. They're thin wrappers around the\n",
"indexable interface — `pw.gens()` is equivalent to\n",
"indexable interface - `pw.gens()` is equivalent to\n",
"`pw[Gen, [\"GenMW\", \"GenMVR\", \"GenStatus\"]]` but shorter to type.\n",
"\n",
"| Method | Returns |\n",
Expand Down Expand Up @@ -427,7 +427,7 @@
"pw.dc_mode = True # DC approximation\n",
"```\n",
"\n",
"See the :doc:`API Reference </api/workbench>` for the full list of\n",
"See the API Reference for the full list of\n",
"solver option descriptors."
]
},
Expand All @@ -440,7 +440,7 @@
"\n",
"Several methods wrap multi-step workflows into single calls.\n",
"\n",
"**Branch flows and overloads** — `flows()` retrieves MW, MVR, MVA,\n",
"**Branch flows and overloads** - `flows()` retrieves MW, MVR, MVA,\n",
"and percent loading for every branch. `overloads()` filters to\n",
"branches exceeding a threshold.\n",
"\n",
Expand All @@ -449,7 +449,7 @@
"| `pw.flows()` | Branch MW, MVR, MVA, and % loading |\n",
"| `pw.overloads(threshold=100)` | Branches exceeding a loading threshold |\n",
"\n",
"**Sensitivity factors** — `ptdf()` and `lodf()` compute Power\n",
"**Sensitivity factors** - `ptdf()` and `lodf()` compute Power\n",
"Transfer Distribution Factors and Line Outage Distribution Factors,\n",
"respectively. Both call the underlying SAW sensitivity commands and\n",
"return the results as a DataFrame.\n",
Expand All @@ -459,7 +459,7 @@
"| `pw.ptdf(seller, buyer)` | Power Transfer Distribution Factors |\n",
"| `pw.lodf(branch)` | Line Outage Distribution Factors |\n",
"\n",
"**Snapshot** — a context manager that saves the current case state\n",
"**Snapshot** - a context manager that saves the current case state\n",
"on entry and restores it on exit, even if an exception occurs.\n",
"Useful for \"what-if\" analyses where you want to modify the case\n",
"temporarily without losing the original state.\n",
Expand Down Expand Up @@ -511,7 +511,7 @@
"pw.gic.configure() # apply sensible defaults\n",
"```\n",
"\n",
"See the :doc:`API Reference </api/utils>` for full documentation\n",
"See the API Reference for full documentation\n",
"of each module."
]
}
Expand Down
Loading