psse-utils 2026.6.0b1__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.
- psse_utils-2026.6.0b1/.github/workflows/ci.yml +34 -0
- psse_utils-2026.6.0b1/.github/workflows/publish.yml +66 -0
- psse_utils-2026.6.0b1/.gitignore +10 -0
- psse_utils-2026.6.0b1/LICENSE +21 -0
- psse_utils-2026.6.0b1/PKG-INFO +81 -0
- psse_utils-2026.6.0b1/README.md +55 -0
- psse_utils-2026.6.0b1/docs/superpowers/plans/2026-06-23-psse-utils.md +423 -0
- psse_utils-2026.6.0b1/docs/superpowers/specs/2026-06-23-psse-utils-design.md +145 -0
- psse_utils-2026.6.0b1/pdm.lock +1728 -0
- psse_utils-2026.6.0b1/pdm.toml +2 -0
- psse_utils-2026.6.0b1/pyproject.toml +70 -0
- psse_utils-2026.6.0b1/src/psse_utils/__about__.py +3 -0
- psse_utils-2026.6.0b1/src/psse_utils/__init__.py +5 -0
- psse_utils-2026.6.0b1/src/psse_utils/flowgate_key_facilities.py +113 -0
- psse_utils-2026.6.0b1/tests/conftest.py +31 -0
- psse_utils-2026.6.0b1/tests/data/Model_1.raw +355 -0
- psse_utils-2026.6.0b1/tests/data/synthetic_flowgates.mon +41 -0
- psse_utils-2026.6.0b1/tests/test_flowgate_key_facilities_args.py +103 -0
- psse_utils-2026.6.0b1/tests/test_flowgate_key_facilities_main.py +85 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
name: Test & Coverage
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
env:
|
|
12
|
+
# platformdirs' site_data_dir defaults to /usr/local/share (root-only on
|
|
13
|
+
# the GHA runner). Redirect it to a writable path so Model.__init__'s
|
|
14
|
+
# pickle cache can be written during the end-to-end CLI tests.
|
|
15
|
+
XDG_DATA_DIRS: /tmp/psse-site-data
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python 3.11
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: '3.11'
|
|
23
|
+
|
|
24
|
+
# Installs flowgate-key-facilities (editable) plus its runtime deps from PyPI,
|
|
25
|
+
# including psse-model-util. --pre is needed while psse-model-util is a
|
|
26
|
+
# pre-release. pytest config adds the repo root to sys.path.
|
|
27
|
+
- name: Install package + test deps
|
|
28
|
+
run: |
|
|
29
|
+
python -m pip install --upgrade pip
|
|
30
|
+
python -m pip install --pre -e .
|
|
31
|
+
python -m pip install pytest pytest-cov
|
|
32
|
+
|
|
33
|
+
- name: Run pytest (enforces the 95% coverage gate)
|
|
34
|
+
run: pytest
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
# Trusted Publishing (OIDC) — no API tokens. Triggered when a GitHub Release is
|
|
4
|
+
# published, or manually via "Run workflow". The TestPyPI job runs automatically;
|
|
5
|
+
# the PyPI job is gated by the `pypi` environment (add a required reviewer in
|
|
6
|
+
# repo Settings → Environments).
|
|
7
|
+
#
|
|
8
|
+
# Note: a Release created by another workflow's GITHUB_TOKEN cannot trigger this
|
|
9
|
+
# one, so use the manual workflow_dispatch (or a human-created Release).
|
|
10
|
+
on:
|
|
11
|
+
release:
|
|
12
|
+
types: [published]
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
build:
|
|
17
|
+
name: Build sdist + wheel
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
- uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.11"
|
|
24
|
+
- name: Build
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade build
|
|
27
|
+
python -m build
|
|
28
|
+
- uses: actions/upload-artifact@v4
|
|
29
|
+
with:
|
|
30
|
+
name: dist
|
|
31
|
+
path: dist/
|
|
32
|
+
|
|
33
|
+
publish-testpypi:
|
|
34
|
+
name: Publish to TestPyPI
|
|
35
|
+
needs: build
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
environment:
|
|
38
|
+
name: testpypi
|
|
39
|
+
url: https://test.pypi.org/p/psse-utils
|
|
40
|
+
permissions:
|
|
41
|
+
id-token: write
|
|
42
|
+
steps:
|
|
43
|
+
- uses: actions/download-artifact@v4
|
|
44
|
+
with:
|
|
45
|
+
name: dist
|
|
46
|
+
path: dist/
|
|
47
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
48
|
+
with:
|
|
49
|
+
repository-url: https://test.pypi.org/legacy/
|
|
50
|
+
skip-existing: true
|
|
51
|
+
|
|
52
|
+
publish-pypi:
|
|
53
|
+
name: Publish to PyPI
|
|
54
|
+
needs: publish-testpypi
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
environment:
|
|
57
|
+
name: pypi
|
|
58
|
+
url: https://pypi.org/p/psse-utils
|
|
59
|
+
permissions:
|
|
60
|
+
id-token: write
|
|
61
|
+
steps:
|
|
62
|
+
- uses: actions/download-artifact@v4
|
|
63
|
+
with:
|
|
64
|
+
name: dist
|
|
65
|
+
path: dist/
|
|
66
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 cadvena
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: psse-utils
|
|
3
|
+
Version: 2026.6.0b1
|
|
4
|
+
Summary: A collection of small PSS/E utility scripts built on psse-model-util.
|
|
5
|
+
Project-URL: Homepage, https://github.com/ppsyOps/psse_utils
|
|
6
|
+
Project-URL: Repository, https://github.com/ppsyOps/psse_utils
|
|
7
|
+
Project-URL: Issues, https://github.com/ppsyOps/psse_utils/issues
|
|
8
|
+
Author: cadvena
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: PSS/E,flowgate,power systems,psse,scripts
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering
|
|
21
|
+
Requires-Python: !=3.14.1,<3.15,>=3.11
|
|
22
|
+
Requires-Dist: networkx
|
|
23
|
+
Requires-Dist: pandas
|
|
24
|
+
Requires-Dist: psse-model-util>=2026.4.5b1
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# psse-utils
|
|
28
|
+
|
|
29
|
+
A collection of small PSS/E utility scripts built on
|
|
30
|
+
[`psse-model-util`](https://pypi.org/project/psse-model-util/). Instead of a new
|
|
31
|
+
repo + PyPI project per script, scripts live here and ship as one package.
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
~~~
|
|
36
|
+
pip install --pre psse-utils
|
|
37
|
+
~~~
|
|
38
|
+
|
|
39
|
+
`--pre` is required while this package (and `psse-model-util`) are pre-releases.
|
|
40
|
+
|
|
41
|
+
## Scripts
|
|
42
|
+
|
|
43
|
+
### `flowgate-key-facilities`
|
|
44
|
+
|
|
45
|
+
Identify the **key facilities** for a set of PSS/E flowgates — the equipment
|
|
46
|
+
whose outage would most likely have a high impact on those flowgates. For each
|
|
47
|
+
flowgate in a `.mon` file, it keeps AC lines in a kV range and generators above a
|
|
48
|
+
PMax, all within `n` buses (hops) of the flowgate's elements, and writes the
|
|
49
|
+
results to CSVs.
|
|
50
|
+
|
|
51
|
+
~~~
|
|
52
|
+
flowgate-key-facilities \
|
|
53
|
+
--mon flowgates.mon --raw Model.raw \
|
|
54
|
+
--areas 1 2 3 --sc SCA --out-dir outputs/
|
|
55
|
+
~~~
|
|
56
|
+
|
|
57
|
+
Full options: `flowgate-key-facilities --help`. Outputs `branches.csv`,
|
|
58
|
+
`generators.csv`, `transformers_3w.csv`, `unresolved.csv` in `--out-dir`.
|
|
59
|
+
|
|
60
|
+
## Adding a script
|
|
61
|
+
|
|
62
|
+
1. Create `src/psse_utils/<name>.py` with the **logic as importable functions**
|
|
63
|
+
plus a thin `main(argv=None) -> int` that parses args and calls them (keeping
|
|
64
|
+
logic separate from the CLI leaves room for a future TUI/web UI).
|
|
65
|
+
2. Add a console command in `pyproject.toml`:
|
|
66
|
+
`[project.scripts]` → `your-command = "psse_utils.<name>:main"`.
|
|
67
|
+
3. Add tests `tests/test_<name>_*.py` (script-prefixed).
|
|
68
|
+
4. Put any heavy/extra dependencies behind an extra in `[project.optional-dependencies]`.
|
|
69
|
+
|
|
70
|
+
## Development
|
|
71
|
+
|
|
72
|
+
~~~
|
|
73
|
+
python -m venv .venv
|
|
74
|
+
.venv\Scripts\python -m pip install --pre -e .
|
|
75
|
+
.venv\Scripts\python -m pip install pytest pytest-cov
|
|
76
|
+
.venv\Scripts\python -m pytest
|
|
77
|
+
~~~
|
|
78
|
+
|
|
79
|
+
Versioning is CalVer (`YYYY.M.micro`) from `src/psse_utils/__about__.py`.
|
|
80
|
+
Releases publish to PyPI via Trusted Publishing — see the team setup runbook and
|
|
81
|
+
`psse-model-util`'s `docs/PUBLISHING.md`.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# psse-utils
|
|
2
|
+
|
|
3
|
+
A collection of small PSS/E utility scripts built on
|
|
4
|
+
[`psse-model-util`](https://pypi.org/project/psse-model-util/). Instead of a new
|
|
5
|
+
repo + PyPI project per script, scripts live here and ship as one package.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
~~~
|
|
10
|
+
pip install --pre psse-utils
|
|
11
|
+
~~~
|
|
12
|
+
|
|
13
|
+
`--pre` is required while this package (and `psse-model-util`) are pre-releases.
|
|
14
|
+
|
|
15
|
+
## Scripts
|
|
16
|
+
|
|
17
|
+
### `flowgate-key-facilities`
|
|
18
|
+
|
|
19
|
+
Identify the **key facilities** for a set of PSS/E flowgates — the equipment
|
|
20
|
+
whose outage would most likely have a high impact on those flowgates. For each
|
|
21
|
+
flowgate in a `.mon` file, it keeps AC lines in a kV range and generators above a
|
|
22
|
+
PMax, all within `n` buses (hops) of the flowgate's elements, and writes the
|
|
23
|
+
results to CSVs.
|
|
24
|
+
|
|
25
|
+
~~~
|
|
26
|
+
flowgate-key-facilities \
|
|
27
|
+
--mon flowgates.mon --raw Model.raw \
|
|
28
|
+
--areas 1 2 3 --sc SCA --out-dir outputs/
|
|
29
|
+
~~~
|
|
30
|
+
|
|
31
|
+
Full options: `flowgate-key-facilities --help`. Outputs `branches.csv`,
|
|
32
|
+
`generators.csv`, `transformers_3w.csv`, `unresolved.csv` in `--out-dir`.
|
|
33
|
+
|
|
34
|
+
## Adding a script
|
|
35
|
+
|
|
36
|
+
1. Create `src/psse_utils/<name>.py` with the **logic as importable functions**
|
|
37
|
+
plus a thin `main(argv=None) -> int` that parses args and calls them (keeping
|
|
38
|
+
logic separate from the CLI leaves room for a future TUI/web UI).
|
|
39
|
+
2. Add a console command in `pyproject.toml`:
|
|
40
|
+
`[project.scripts]` → `your-command = "psse_utils.<name>:main"`.
|
|
41
|
+
3. Add tests `tests/test_<name>_*.py` (script-prefixed).
|
|
42
|
+
4. Put any heavy/extra dependencies behind an extra in `[project.optional-dependencies]`.
|
|
43
|
+
|
|
44
|
+
## Development
|
|
45
|
+
|
|
46
|
+
~~~
|
|
47
|
+
python -m venv .venv
|
|
48
|
+
.venv\Scripts\python -m pip install --pre -e .
|
|
49
|
+
.venv\Scripts\python -m pip install pytest pytest-cov
|
|
50
|
+
.venv\Scripts\python -m pytest
|
|
51
|
+
~~~
|
|
52
|
+
|
|
53
|
+
Versioning is CalVer (`YYYY.M.micro`) from `src/psse_utils/__about__.py`.
|
|
54
|
+
Releases publish to PyPI via Trusted Publishing — see the team setup runbook and
|
|
55
|
+
`psse-model-util`'s `docs/PUBLISHING.md`.
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
# psse-utils Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** Repurpose the `flowgate_key_facilities` repo into **`psse-utils`** — a PyPI package that collects small PSS/E scripts built on `psse-model-util`, with the existing flowgate CLI as its first script.
|
|
6
|
+
|
|
7
|
+
**Architecture:** Restructure the single-module repo into a `src/psse_utils/` package (src layout, matching `psse-model-util`). Each script is a module with importable logic + a thin `main()`, exposed as its own console command. Reuse the repo's existing Trusted-Publishing `publish.yml`, pip-based `ci.yml`, and GitHub environments. Code changes land first on a branch; the GitHub-repo rename + PyPI pending-publisher (human/owner steps) and the publish happen after merge.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** Python 3.11+, Hatchling (build + CalVer version from `__about__.py`), pytest + pytest-cov, Trusted Publishing (OIDC) via GitHub Actions.
|
|
10
|
+
|
|
11
|
+
**Spec:** `docs/superpowers/specs/2026-06-23-psse-utils-design.md`.
|
|
12
|
+
|
|
13
|
+
**Baseline (current repo, branch `feat/psse-utils`):** single module `flowgate_key_facilities.py` at root; tests `tests/test_cli_args.py`, `tests/test_cli_main.py`, `tests/conftest.py`, `tests/data/`; `pyproject.toml` (name `flowgate-key-facilities`, static `version = "0.1.0b1"`); `.github/workflows/{ci,publish}.yml`; the flowgate CLI imports `psse_model_util` and is published as `flowgate-key-facilities 0.1.0b1` (a beta, to be yanked).
|
|
14
|
+
|
|
15
|
+
**Locked decisions:** repurpose (don't recreate); src layout; per-script console commands; logic separated from CLI; CalVer `YYYY.M.micro` (first release `2026.6.0b1`); keep the `flowgate-key-facilities` command and `flowgate_key_facilities.py` module name; script-prefixed test files; base dep `psse-model-util>=2026.4.5b1`.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## File structure (end state)
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
src/psse_utils/
|
|
23
|
+
__init__.py # from psse_utils.__about__ import __version__
|
|
24
|
+
__about__.py # __version__ = "2026.6.0b1"
|
|
25
|
+
flowgate_key_facilities.py # moved from repo root (imports unchanged)
|
|
26
|
+
tests/
|
|
27
|
+
conftest.py # adds src/ to sys.path fallback
|
|
28
|
+
test_flowgate_key_facilities_args.py # was test_cli_args.py
|
|
29
|
+
test_flowgate_key_facilities_main.py # was test_cli_main.py
|
|
30
|
+
data/ Model_1.raw synthetic_flowgates.mon
|
|
31
|
+
pyproject.toml README.md LICENSE pdm.lock pdm.toml
|
|
32
|
+
.github/workflows/ci.yml publish.yml
|
|
33
|
+
docs/superpowers/{specs,plans}/...
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Phase 0 — Baseline
|
|
39
|
+
|
|
40
|
+
Work on the existing `feat/psse-utils` branch (already has the spec + this plan).
|
|
41
|
+
|
|
42
|
+
- [ ] **Step 0.1: Confirm the current suite is green before restructuring**
|
|
43
|
+
|
|
44
|
+
Run (from the repo root, using the project venv's python — `python -m pip install --pre -e .` first if needed):
|
|
45
|
+
```
|
|
46
|
+
python -m pytest -q
|
|
47
|
+
```
|
|
48
|
+
Expected: the existing flowgate tests pass (16 passed, ~100% coverage). If red, stop and fix before continuing.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Phase 1 — Restructure into `src/psse_utils/`
|
|
53
|
+
|
|
54
|
+
**Files:** move `flowgate_key_facilities.py`; create `src/psse_utils/__init__.py`, `src/psse_utils/__about__.py`.
|
|
55
|
+
|
|
56
|
+
- [ ] **Step 1.1: Move the module into the package**
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
mkdir -p src/psse_utils
|
|
60
|
+
git mv flowgate_key_facilities.py src/psse_utils/flowgate_key_facilities.py
|
|
61
|
+
```
|
|
62
|
+
No code edits inside the file — its imports are `from psse_model_util... import`, unaffected by the move.
|
|
63
|
+
|
|
64
|
+
- [ ] **Step 1.2: Create the version source `src/psse_utils/__about__.py`**
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
"""Package version — single source of truth for psse_utils versioning."""
|
|
68
|
+
|
|
69
|
+
__version__ = "2026.6.0b1"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- [ ] **Step 1.3: Create `src/psse_utils/__init__.py`**
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
"""psse_utils — a collection of small PSS/E utility scripts built on psse-model-util."""
|
|
76
|
+
|
|
77
|
+
from psse_utils.__about__ import __version__
|
|
78
|
+
|
|
79
|
+
__all__ = ["__version__"]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
- [ ] **Step 1.4: Commit**
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
git add -A
|
|
86
|
+
git commit -m "refactor: move flowgate module into src/psse_utils package"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Phase 2 — pyproject + workflows retarget
|
|
92
|
+
|
|
93
|
+
**Files:** `pyproject.toml`, `.github/workflows/publish.yml`. (`ci.yml` already does `pip install --pre -e .` and needs no change.)
|
|
94
|
+
|
|
95
|
+
- [ ] **Step 2.1: Rewrite the `pyproject.toml` `[project]` + tool tables**
|
|
96
|
+
|
|
97
|
+
Replace the existing `[project]` name/version/description/urls/scripts and the
|
|
98
|
+
`[tool.*]` packaging/test/coverage tables so the file reads:
|
|
99
|
+
|
|
100
|
+
```toml
|
|
101
|
+
[project]
|
|
102
|
+
name = "psse-utils"
|
|
103
|
+
dynamic = ["version"]
|
|
104
|
+
description = "A collection of small PSS/E utility scripts built on psse-model-util."
|
|
105
|
+
readme = "README.md"
|
|
106
|
+
requires-python = ">=3.11,!=3.14.1,<3.15"
|
|
107
|
+
license = "MIT"
|
|
108
|
+
license-files = ["LICENSE"]
|
|
109
|
+
authors = [
|
|
110
|
+
{ name = "cadvena" }
|
|
111
|
+
]
|
|
112
|
+
keywords = ["psse", "power systems", "PSS/E", "scripts", "flowgate"]
|
|
113
|
+
classifiers = [
|
|
114
|
+
"Development Status :: 4 - Beta",
|
|
115
|
+
"Environment :: Console",
|
|
116
|
+
"Intended Audience :: Science/Research",
|
|
117
|
+
"License :: OSI Approved :: MIT License",
|
|
118
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
119
|
+
"Programming Language :: Python :: 3.11",
|
|
120
|
+
"Programming Language :: Python :: 3.12",
|
|
121
|
+
"Programming Language :: Python :: 3.13",
|
|
122
|
+
"Topic :: Scientific/Engineering",
|
|
123
|
+
]
|
|
124
|
+
dependencies = [
|
|
125
|
+
"psse-model-util>=2026.4.5b1",
|
|
126
|
+
"pandas",
|
|
127
|
+
"networkx",
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
[project.urls]
|
|
131
|
+
Homepage = "https://github.com/ppsyOps/psse_utils"
|
|
132
|
+
Repository = "https://github.com/ppsyOps/psse_utils"
|
|
133
|
+
Issues = "https://github.com/ppsyOps/psse_utils/issues"
|
|
134
|
+
|
|
135
|
+
[project.scripts]
|
|
136
|
+
flowgate-key-facilities = "psse_utils.flowgate_key_facilities:main"
|
|
137
|
+
|
|
138
|
+
[build-system]
|
|
139
|
+
requires = ["hatchling"]
|
|
140
|
+
build-backend = "hatchling.build"
|
|
141
|
+
|
|
142
|
+
[tool.hatch.version]
|
|
143
|
+
path = "src/psse_utils/__about__.py"
|
|
144
|
+
pattern = "__version__ = ['\"](?P<version>[^'\"]+)['\"]"
|
|
145
|
+
|
|
146
|
+
[tool.hatch.build.targets.wheel]
|
|
147
|
+
packages = ["src/psse_utils"]
|
|
148
|
+
|
|
149
|
+
[tool.pdm.dev-dependencies]
|
|
150
|
+
test = [
|
|
151
|
+
"pytest>=8",
|
|
152
|
+
"pytest-cov",
|
|
153
|
+
]
|
|
154
|
+
|
|
155
|
+
[tool.pytest.ini_options]
|
|
156
|
+
testpaths = ["tests"]
|
|
157
|
+
addopts = "--cov=psse_utils --cov-report=term-missing"
|
|
158
|
+
|
|
159
|
+
[tool.coverage.run]
|
|
160
|
+
source = ["src/psse_utils"]
|
|
161
|
+
|
|
162
|
+
[tool.coverage.report]
|
|
163
|
+
exclude_lines = [
|
|
164
|
+
"pragma: no cover",
|
|
165
|
+
"if __name__ == .__main__.:",
|
|
166
|
+
"raise NotImplementedError",
|
|
167
|
+
]
|
|
168
|
+
fail_under = 95
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Notes: `version` becomes **dynamic** (sourced from `__about__.py`); the old
|
|
172
|
+
`pythonpath = ["."]` is dropped — `conftest.py` (Step 3.3) handles import path.
|
|
173
|
+
|
|
174
|
+
- [ ] **Step 2.2: Retarget `publish.yml` environment URLs to the new project**
|
|
175
|
+
|
|
176
|
+
In `.github/workflows/publish.yml`, change the two `url:` lines:
|
|
177
|
+
- `https://test.pypi.org/p/flowgate-key-facilities` → `https://test.pypi.org/p/psse-utils`
|
|
178
|
+
- `https://pypi.org/p/flowgate-key-facilities` → `https://pypi.org/p/psse-utils`
|
|
179
|
+
|
|
180
|
+
- [ ] **Step 2.3: Commit**
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
git add pyproject.toml .github/workflows/publish.yml
|
|
184
|
+
git commit -m "build: rename distribution to psse-utils; CalVer dynamic version; src-layout packaging"
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Phase 3 — Tests: rename + fix imports
|
|
190
|
+
|
|
191
|
+
**Files:** rename the two test files; edit imports; update `tests/conftest.py`.
|
|
192
|
+
|
|
193
|
+
- [ ] **Step 3.1: Rename the test files (script-prefixed)**
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
git mv tests/test_cli_args.py tests/test_flowgate_key_facilities_args.py
|
|
197
|
+
git mv tests/test_cli_main.py tests/test_flowgate_key_facilities_main.py
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
- [ ] **Step 3.2: Update imports in the renamed tests**
|
|
201
|
+
|
|
202
|
+
In `tests/test_flowgate_key_facilities_args.py`: change
|
|
203
|
+
`from flowgate_key_facilities import _parse_args`
|
|
204
|
+
→ `from psse_utils.flowgate_key_facilities import _parse_args`.
|
|
205
|
+
|
|
206
|
+
In `tests/test_flowgate_key_facilities_main.py`: change
|
|
207
|
+
`from flowgate_key_facilities import main`
|
|
208
|
+
→ `from psse_utils.flowgate_key_facilities import main`.
|
|
209
|
+
|
|
210
|
+
(Also update the module-name references in their docstrings, `flowgate_key_facilities` →
|
|
211
|
+
`psse_utils.flowgate_key_facilities`, for accuracy.)
|
|
212
|
+
|
|
213
|
+
- [ ] **Step 3.3: Make `tests/conftest.py` add `src/` to `sys.path` (fallback when not installed)**
|
|
214
|
+
|
|
215
|
+
Replace `tests/conftest.py` with:
|
|
216
|
+
```python
|
|
217
|
+
"""Shared fixtures + import path for the psse_utils tests.
|
|
218
|
+
|
|
219
|
+
With the src/ layout the package is normally importable via the editable
|
|
220
|
+
install (`pip install -e .`). As a fallback for fresh checkouts, add src/ to
|
|
221
|
+
sys.path so `import psse_utils...` resolves.
|
|
222
|
+
"""
|
|
223
|
+
import sys
|
|
224
|
+
from pathlib import Path
|
|
225
|
+
|
|
226
|
+
_SRC = Path(__file__).resolve().parent.parent / "src"
|
|
227
|
+
if _SRC.is_dir() and str(_SRC) not in sys.path:
|
|
228
|
+
sys.path.insert(0, str(_SRC))
|
|
229
|
+
```
|
|
230
|
+
(Keep any existing fixtures from the old conftest below this block.)
|
|
231
|
+
|
|
232
|
+
- [ ] **Step 3.4: Reinstall editable + run the suite**
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
python -m pip install --pre -e .
|
|
236
|
+
python -m pytest -q
|
|
237
|
+
```
|
|
238
|
+
Expected: same tests pass (now importing from `psse_utils.flowgate_key_facilities`),
|
|
239
|
+
coverage measured on `psse_utils`, gate ≥ 95% met.
|
|
240
|
+
|
|
241
|
+
- [ ] **Step 3.5: Commit**
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
git add -A
|
|
245
|
+
git commit -m "test: script-prefix flowgate test files; import from psse_utils; src/ conftest"
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Phase 4 — README for the collection
|
|
251
|
+
|
|
252
|
+
**Files:** `README.md`.
|
|
253
|
+
|
|
254
|
+
- [ ] **Step 4.1: Rewrite `README.md`** so it describes the *collection*, lists the
|
|
255
|
+
flowgate script as the first entry, and documents install + how to add a script.
|
|
256
|
+
|
|
257
|
+
```markdown
|
|
258
|
+
# psse-utils
|
|
259
|
+
|
|
260
|
+
A collection of small PSS/E utility scripts built on
|
|
261
|
+
[`psse-model-util`](https://pypi.org/project/psse-model-util/). Instead of a new
|
|
262
|
+
repo + PyPI project per script, scripts live here and ship as one package.
|
|
263
|
+
|
|
264
|
+
## Installation
|
|
265
|
+
|
|
266
|
+
~~~
|
|
267
|
+
pip install --pre psse-utils
|
|
268
|
+
~~~
|
|
269
|
+
|
|
270
|
+
`--pre` is required while the package (and `psse-model-util`) are pre-releases.
|
|
271
|
+
|
|
272
|
+
## Scripts
|
|
273
|
+
|
|
274
|
+
### `flowgate-key-facilities`
|
|
275
|
+
|
|
276
|
+
Identify the key facilities for a set of PSS/E flowgates — equipment whose outage
|
|
277
|
+
would most impact those flowgates. For each flowgate in a `.mon` file it keeps AC
|
|
278
|
+
lines in a kV range and generators above a PMax, within `n` buses of the flowgate.
|
|
279
|
+
|
|
280
|
+
~~~
|
|
281
|
+
flowgate-key-facilities --mon flowgates.mon --raw Model.raw \
|
|
282
|
+
--areas 1 2 3 --sc SCA --out-dir outputs/
|
|
283
|
+
~~~
|
|
284
|
+
|
|
285
|
+
(Full options: `flowgate-key-facilities --help`.)
|
|
286
|
+
|
|
287
|
+
## Adding a script
|
|
288
|
+
|
|
289
|
+
1. Create `src/psse_utils/<name>.py` with importable functions (the logic) plus
|
|
290
|
+
a thin `main(argv=None) -> int` that parses args and calls them.
|
|
291
|
+
2. Add a console command: `[project.scripts]` → `your-command = "psse_utils.<name>:main"`.
|
|
292
|
+
3. Add tests `tests/test_<name>_*.py`.
|
|
293
|
+
4. Put any heavy/extra dependencies behind an extra in `[project.optional-dependencies]`.
|
|
294
|
+
|
|
295
|
+
## Development
|
|
296
|
+
|
|
297
|
+
~~~
|
|
298
|
+
pip install -e ../psse_model_util # if developing the engine alongside
|
|
299
|
+
pip install --pre -e .
|
|
300
|
+
pytest
|
|
301
|
+
~~~
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
- [ ] **Step 4.2: Commit**
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
git add README.md
|
|
308
|
+
git commit -m "docs: rewrite README for the psse-utils collection"
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Phase 5 — Verify the package
|
|
314
|
+
|
|
315
|
+
- [ ] **Step 5.1: Build + inspect the wheel**
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
python -m pip install --upgrade build
|
|
319
|
+
rm -rf dist && python -m build
|
|
320
|
+
python -c "import zipfile,glob; z=zipfile.ZipFile(sorted(glob.glob('dist/*.whl'))[-1]); print('\n'.join(n for n in z.namelist() if n.endswith(('.py','entry_points.txt','METADATA')))); print(z.read([n for n in z.namelist() if n.endswith('entry_points.txt')][0]).decode())"
|
|
321
|
+
```
|
|
322
|
+
Expected: files live under `psse_utils/` (e.g. `psse_utils/flowgate_key_facilities.py`),
|
|
323
|
+
metadata `Name: psse-utils`, version `2026.6.0b1`, `Requires-Dist: psse-model-util>=2026.4.5b1`,
|
|
324
|
+
and entry point `flowgate-key-facilities = psse_utils.flowgate_key_facilities:main`.
|
|
325
|
+
|
|
326
|
+
- [ ] **Step 5.2: twine check**
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
python -m pip install twine && python -m twine check dist/*
|
|
330
|
+
```
|
|
331
|
+
Expected: both `PASSED`.
|
|
332
|
+
|
|
333
|
+
- [ ] **Step 5.3: Clean-venv install smoke test**
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
python -m venv /tmp/psse-utils-verify
|
|
337
|
+
/tmp/psse-utils-verify/Scripts/python -m pip install --pre dist/psse_utils-*.whl
|
|
338
|
+
/tmp/psse-utils-verify/Scripts/python -c "import psse_utils; from psse_utils.flowgate_key_facilities import main; print('OK', psse_utils.__version__)"
|
|
339
|
+
/tmp/psse-utils-verify/Scripts/flowgate-key-facilities --help
|
|
340
|
+
```
|
|
341
|
+
Expected: `OK 2026.6.0b1`; the console command prints its usage. (Windows paths shown; adjust for OS.)
|
|
342
|
+
|
|
343
|
+
- [ ] **Step 5.4: Re-lock pdm (dependency set unchanged, but project metadata changed)**
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
python -m pdm lock
|
|
347
|
+
git add pdm.lock; git commit -m "build: refresh pdm.lock for psse-utils" || echo "no lock changes"
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## Phase 6 — (Optional, recommended) split flowgate logic from CLI
|
|
353
|
+
|
|
354
|
+
Sets the convention for future scripts and enables a future TUI/web UI. Keep tests green.
|
|
355
|
+
|
|
356
|
+
- [ ] **Step 6.1: Extract a `run(...)` function**
|
|
357
|
+
|
|
358
|
+
In `src/psse_utils/flowgate_key_facilities.py`, factor the body of `main()` (after
|
|
359
|
+
arg parsing) into a pure function, e.g.:
|
|
360
|
+
```python
|
|
361
|
+
def run(*, mon, raw, areas, sc, out_dir, hops, kv_min, kv_max, gen_min_mw) -> dict:
|
|
362
|
+
"""Resolve flowgates -> collect key facilities -> write CSVs; return the result dict."""
|
|
363
|
+
# (the existing pipeline body moves here)
|
|
364
|
+
```
|
|
365
|
+
`main(argv)` then parses args and calls `run(**kwargs)`.
|
|
366
|
+
|
|
367
|
+
- [ ] **Step 6.2: Add a focused test for `run()`** in
|
|
368
|
+
`tests/test_flowgate_key_facilities_main.py` that calls `run(...)` directly with the
|
|
369
|
+
fixtures and asserts the output CSVs / returned dict — independent of argparse.
|
|
370
|
+
|
|
371
|
+
- [ ] **Step 6.3: Run + commit**
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
python -m pytest -q
|
|
375
|
+
git add -A && git commit -m "refactor(flowgate): separate run() logic from main() CLI"
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## Phase 7 — Human / owner steps (cannot be automated by the agent)
|
|
381
|
+
|
|
382
|
+
These require GitHub-admin and PyPI-account actions. See
|
|
383
|
+
`OneDrive/Trapezia/PyPI-and-TestPyPI-setup-runbook.md`.
|
|
384
|
+
|
|
385
|
+
- [ ] **Step 7.1: Merge the branch** — open a PR `feat/psse-utils` → `master`, let CI pass, merge.
|
|
386
|
+
|
|
387
|
+
- [ ] **Step 7.2: Rename the GitHub repo** `flowgate_key_facilities` → `psse_utils`
|
|
388
|
+
(owner `cadvena`: GitHub Settings → Rename, or `gh repo rename psse_utils -R ppsyOps/flowgate_key_facilities`).
|
|
389
|
+
Then locally: `git remote set-url origin https://github.com/ppsyOps/psse_utils.git`,
|
|
390
|
+
rename the local clone folder, and recreate the venv with stdlib `python -m venv`.
|
|
391
|
+
|
|
392
|
+
- [ ] **Step 7.3: Add the `psse-utils` pending publishers** on PyPI and TestPyPI —
|
|
393
|
+
Project `psse-utils`, Owner `ppsyOps`, **Repo `psse_utils`**, Workflow `publish.yml`,
|
|
394
|
+
Env `pypi` / `testpypi`. (GitHub environments `pypi`/`testpypi` already exist on the repo.)
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Phase 8 — Publish
|
|
399
|
+
|
|
400
|
+
- [ ] **Step 8.1: Dispatch the publish workflow**
|
|
401
|
+
|
|
402
|
+
`gh workflow run publish.yml --ref master --repo ppsyOps/psse_utils`
|
|
403
|
+
(Manual dispatch — a `cd.yml`/token-created release can't trigger it.)
|
|
404
|
+
|
|
405
|
+
- [ ] **Step 8.2: TestPyPI → verify → approve PyPI gate**
|
|
406
|
+
|
|
407
|
+
Build → TestPyPI publishes automatically; verify
|
|
408
|
+
`pip install --pre --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ psse-utils`
|
|
409
|
+
in a clean venv. Then approve the `pypi` deployment (reviewer `cadvena`) to publish to real PyPI.
|
|
410
|
+
|
|
411
|
+
- [ ] **Step 8.3: Confirm + clean up**
|
|
412
|
+
|
|
413
|
+
`pip install --pre psse-utils` from real PyPI; `flowgate-key-facilities --help` works.
|
|
414
|
+
Then **yank** the orphaned `flowgate-key-facilities 0.1.0b1` on PyPI (project → Manage → yank),
|
|
415
|
+
since its functionality now ships in `psse-utils`.
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
## Self-review notes
|
|
420
|
+
|
|
421
|
+
- **Spec coverage:** repurpose (P1,P7.2) · src layout (P1,P2) · per-script command (P2.1 scripts) · logic/CLI split (P6) · CalVer `2026.6.0b1` (P1.2,P2.1) · keep flowgate command+module names (P2.1,P1.1) · script-prefixed tests (P3) · `psse-model-util` dep + extras note (P2.1, README P4) · reuse publish/ci/envs (P2.2, P7) · yank flowgate beta (P8.3) · PyPI publisher (P7.3). ✔
|
|
422
|
+
- **Placeholders:** none — every code/edit step shows the content. The only "optional" is Phase 6, explicitly marked.
|
|
423
|
+
- **Consistency:** distribution `psse-utils`, import `psse_utils`, module `psse_utils.flowgate_key_facilities`, command `flowgate-key-facilities`, version `2026.6.0b1`, repo `ppsyOps/psse_utils` — used uniformly across tasks.
|