Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
8d18f25
Merge branch 'main' into develop
FranekGit Oct 20, 2026
a630434
feat: add endpoint registry generator
FranekGit Oct 20, 2026
d62c238
feat: add generated endpoint registry
FranekGit Oct 20, 2026
2cc8548
test: add endpoint registry tests
FranekGit Oct 20, 2026
d5ac891
docs: document endpoint registry regeneration
FranekGit Oct 20, 2026
b124c5b
chore: move dev deps to uv dependency group, add uv.lock and .python-…
FranekGit Oct 20, 2026
a155a7c
refactor: sort __all__ (ruff RUF022)
FranekGit Oct 20, 2026
7fe81ec
docs: switch CONTRIBUTING to uv workflow
FranekGit Oct 20, 2026
d64295c
Merge pull request #39 from FranekGit/feature/uv-dev-tooling
FranekGit Oct 20, 2026
8b1f255
Merge branch 'develop' into feature/endpoint-registry
FranekGit Oct 20, 2026
231eef9
refactor: render registry with repr and ruff format
FranekGit Oct 20, 2026
4473418
docs: use uv for registry regeneration
FranekGit Oct 20, 2026
a87d215
Merge pull request #40 from FranekGit/pse-python-sdk:feature/endpoint…
FranekGit Oct 20, 2026
7ea646b
refactor: use string.Template and extract check helper in gen_registry
FranekGit Oct 20, 2026
e35b602
Merge pull request #41 from FranekGit:refactor/gen-registry-readability
FranekGit Oct 20, 2026
a274c02
feat: add registry-driven query helpers
FranekGit Oct 20, 2026
b0573d9
feat: add PSEClient.fetch()
FranekGit Oct 20, 2026
7ec236a
feat: route get_* methods through fetch()
FranekGit Oct 20, 2026
15b7ae3
docs: document fetch() in README and endpoints.md
FranekGit Oct 20, 2026
b134388
Merge pull request #42 from FranekGit:feature/generic-fetch
FranekGit Oct 20, 2026
8604f02
feat!: remove get_* methods and make_endpoint
FranekGit Oct 20, 2026
42d4a00
docs: drop get_* shortcut from README, add CHANGELOG entry
FranekGit Oct 20, 2026
e9c4016
docs: reorder endpoints table columns, drop Method and Status
FranekGit Oct 20, 2026
c8cedd2
Merge pull request #43 from FranekGit/feature/remove-get-methods
FranekGit Oct 20, 2026
32a3f85
feat: generate docs/endpoints.md from registry
FranekGit Oct 20, 2026
0ee2655
docs: move fetch() notes to README, document gen_docs, add CHANGELOG …
FranekGit Oct 20, 2026
7a50260
Merge pull request #45 from FranekGit/feature/generate-endpoints-docs
FranekGit Oct 20, 2026
850672e
feat: add endpoints() and columns() discovery helpers
FranekGit Oct 20, 2026
979b958
docs: document endpoints() and columns(), add CHANGELOG entry
FranekGit Oct 20, 2026
3c9cb0b
Merge pull request #46 from FranekGit/feature/discovery-helpers
FranekGit Oct 20, 2026
e2299b3
docs: fix CHANGELOG 1.0.0 entry and PSEClient docstring typo
FranekGit Oct 20, 2026
f231b21
Merge pull request #47 from FranekGit/bugfix/changelog-docstring-typos
FranekGit Oct 20, 2026
4d5f8cb
fix: retry first page request in fetch_all
FranekGit Oct 20, 2026
4e5ced8
Merge pull request #48 from FranekGit/bugfix/first-page-retry
FranekGit Oct 20, 2026
c4b4329
feat: validate endpoint and column names before request
FranekGit Oct 20, 2026
7bb817a
feat: include API error message in HTTPError
FranekGit Oct 20, 2026
c84ae01
docs: document name validation in README and CHANGELOG
FranekGit Oct 20, 2026
65fe93a
refactor: move HTTP error helpers into HTTPClient
FranekGit Oct 20, 2026
002ff8f
docs: drop name validation note from README
FranekGit Oct 20, 2026
a55777b
refactor: order HTTPClient methods public first, helpers in call order
FranekGit Oct 20, 2026
1377350
Merge pull request #49 from FranekGit/feature/validate-names
FranekGit Oct 20, 2026
72bdad1
refactor: simplify name validation
FranekGit Oct 20, 2026
0bce653
Merge pull request #50 from FranekGit/refactor/simplify-validate
FranekGit Oct 20, 2026
1c3ee77
style: format tests with ruff
FranekGit Oct 20, 2026
e286961
chore: lint tests with ruff
FranekGit Oct 20, 2026
8600fff
Merge pull request #52 from FranekGit/feature/lint-tests
FranekGit Oct 20, 2026
73d8f17
refactor: remove module docstrings
FranekGit Oct 20, 2026
9fb2d75
Merge pull request #53 from FranekGit/refactor/remove-module-docstrings
FranekGit Oct 20, 2026
ac8d4cb
feat: filter ogr-*-head endpoints on period
FranekGit Oct 20, 2026
e31a77f
test: cover period date column for ogr-*-head endpoints
FranekGit Oct 20, 2026
32577cd
docs: note period date filter for ogr-*-head endpoints
FranekGit Oct 20, 2026
3f4debf
Merge pull request #54 from FranekGit/feature/head-date-column
FranekGit Oct 20, 2026
9c706f2
docs: list date and key columns in endpoints.md
FranekGit Oct 20, 2026
629876d
docs: move fetch notes to docs/usage.md
FranekGit Oct 20, 2026
79a4d73
Merge pull request #55 from FranekGit/docs/usage-page
FranekGit Oct 20, 2026
77d1717
fix: raise ValueError for non-string endpoint
FranekGit Oct 27, 2026
80131e0
test: cover list and dict endpoints
FranekGit Oct 27, 2026
c2e8e68
docs: note non-string endpoint fix in changelog
FranekGit Oct 27, 2026
39b8198
Merge pull request #58 from FranekGit/bugfix/endpoint-non-str
FranekGit Oct 27, 2026
70fd737
docs: streamline usage page into step-by-step guide
FranekGit Oct 27, 2026
06137cb
docs: trim README to install and quick start
FranekGit Oct 27, 2026
48de86e
Merge pull request #59 from FranekGit/docs/streamline-usage
FranekGit Oct 27, 2026
5e2df9a
docs: remove PSE API endpoints map PDF
FranekGit Oct 27, 2026
f8c52bd
Merge pull request #60 from FranekGit/docs/remove-endpoints-map
FranekGit Oct 27, 2026
aa8deb4
chore: switch license to MIT
FranekGit Oct 27, 2026
2e093c4
chore: add PyPI metadata and read version from package
FranekGit Oct 27, 2026
d96706e
docs: use absolute links in README for PyPI
FranekGit Oct 27, 2026
ea6d331
chore: add tests and PyPI publish workflows
FranekGit Oct 27, 2026
6c56c0e
docs: note PyPI release and MIT license in changelog
FranekGit Oct 27, 2026
b03ab01
Merge pull request #61 from FranekGit/chore/pypi-release-prep
FranekGit Oct 27, 2026
6249c92
docs: mark SDK as unofficial and update install command
FranekGit Oct 27, 2026
4ecd4c3
Merge pull request #62 from FranekGit/docs/unofficial-disclaimer
FranekGit Oct 27, 2026
7af9bcd
chore: release 2.0.0
FranekGit Oct 27, 2026
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
56 changes: 56 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Publish

# Tag push (v*) publishes to PyPI. Manual run publishes to TestPyPI.
on:
push:
tags: ["v*"]
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: astral-sh/setup-uv@v10.3.2
- run: uv build
- name: Check tag matches package version
if: github.ref_type == 'tag'
run: test -f "dist/pse_sdk-${GITHUB_REF_NAME#v}.tar.gz"
- uses: actions/upload-artifact@v7
with:
name: dist
path: dist/

testpypi:
if: github.event_name == 'workflow_dispatch'
needs: build
runs-on: ubuntu-latest
environment:
name: testpypi
url: https://test.pypi.org/project/pse-sdk/
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v8
with:
name: dist
path: dist/
- uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/

pypi:
if: github.ref_type == 'tag'
needs: build
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/project/pse-sdk/
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v8
with:
name: dist
path: dist/
- uses: pypa/gh-action-pypi-publish@release/v1
44 changes: 44 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Tests

on:
push:
branches: [main, develop]
pull_request:

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: astral-sh/setup-uv@v10.3.2
- run: uv run --locked ruff check src/ scripts/ tests/
- run: uv run --locked ruff format --check src/ scripts/ tests/
- run: uv run --locked scripts/gen_docs.py --check

test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v7
- uses: astral-sh/setup-uv@v10.3.2
with:
python-version: ${{ matrix.python-version }}
# manual_test.py calls the live API on import
- run: uv run --locked pytest --ignore=tests/manual_test.py

test-lowest:
# Oldest dependency versions pyproject.toml allows. pandas 1.5 predates
# numpy 2 and breaks against it, so numpy is held below 2.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: astral-sh/setup-uv@v10.3.2
with:
python-version: "3.10"
- run: echo "numpy<2" > constraints.txt
- run: uv venv
- run: uv pip install --resolution lowest-direct -e . --group dev -c constraints.txt
- run: .venv/bin/python -m pytest --ignore=tests/manual_test.py
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.13
58 changes: 56 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,59 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.0.0] - 2026-10-27

### Added
- `PSEClient.fetch(endpoint, start, end, columns=None, format="dict")`:
query any of the 90 PSE API endpoints for a date range, fetched in
30-day chunks. Replaces the `get_*` methods
- Published on PyPI as `pse-sdk`: `pip install pse-sdk`, or
`pip install "pse-sdk[pandas]"` for DataFrame output
- `PSEClient.endpoints()`: names of all endpoints
- `PSEClient.columns(endpoint)`: data columns of an endpoint, in API order
(meta columns left out). Both read the bundled registry, no HTTP request.
- `fetch()` checks column names against the registry before any request.
Unknown columns raise `ValueError` naming each one with a hint (close
match, or other endpoints that have it) instead of an HTTP 400. `columns`
that is not a list or tuple of strings raises `TypeError` (#25)
- `fetch()` supports the six `ogr-*-head` endpoints, filtered on `period`
(#37)

### Changed
- License is now MIT (was proprietary)
- README and package description state the SDK is unofficial and not
affiliated with PSE S.A.
- Unknown endpoint errors suggest the closest endpoint name (#25)
- `HTTPError` from the API includes the API's error message, e.g.
`Invalid field to be returned requested: cen_cots`
- `docs/endpoints.md` is generated from the endpoint registry
(`scripts/gen_docs.py`) and lists the data columns of all 90 endpoints,
including the previously missing `wmb` and `his-gen-pal-sire`, plus the
date and key columns of each. The Description column is dropped.
- `fetch()` column and date-filter notes moved from `docs/endpoints.md` and
the README to the new `docs/usage.md`
- Development uses uv: dev dependencies in a uv dependency group,
`uv.lock` and `.python-version` committed
- Package version is read from `pse_sdk.__version__` (hatch dynamic
version)
- GitHub Actions: `tests.yml` runs ruff, `gen_docs.py --check` and tests on
Python 3.10–3.14; `publish.yml` publishes to PyPI on `v*` tag push
(TestPyPI on manual run)

### Removed
- **Breaking:** all 32 `get_*` methods of `PSEClient` (`get_cen`, `get_csdac`,
`get_kb`, `get_sk_cost`, `get_demand`, ...) and the internal `make_endpoint`
helper. Use `fetch()` with the endpoint and column instead:
`get_cen(s, e)` → `fetch("price-cost", s, e, columns=["cen_cost"])`.
`fetch()` also returns the `*_utc` meta columns.

### Fixed
- First page request of `fetch()` now retried on 5xx errors, like later
pages (#32)
- Non-string endpoint (e.g. a list or dict) raises `ValueError` naming its
type, e.g. `Endpoint must be a str, got list.`, instead of
`TypeError: unhashable type` (#56)

## [1.5.1] - 2026-10-20

### Added
Expand Down Expand Up @@ -67,11 +120,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added
- `PSEClient` class for interacting with the PSE public REST API
- `OutputFormat` enum for controlling response format (JSON, CSV, XML)
- `OutputFormat` type (`Literal["dict", "dataframe"]`) for controlling response
format: list of dicts or pandas DataFrame
- `HTTPClient` for managing HTTP requests with pagination support
- Coverage of the `price-cost` PSE API endpoint
- Date normalization and validation utilities
- Configurable `base_url` and `page_size` parameters
- Configurable HTTP `timeout` parameter
- Optional pandas integration via `pip install pse-sdk[pandas]`
- Unit tests for PSEClient and HTTPClient

Expand Down
52 changes: 44 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@
cd pse-python-sdk
```

2. **Set up a virtual environment** and install dev dependencies:
2. **Install [uv](https://docs.astral.sh/uv/getting-started/installation/)** and sync the environment (creates `.venv` with the package and dev dependencies, pinned by `uv.lock`):

```bash
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
uv sync
```

3. **Checkout `develop`** — all feature work starts here:
Expand Down Expand Up @@ -43,21 +41,59 @@ Short-lived branches for specific work:

## Development Workflow

Run these from the project root with your venv activated:
Run these from the project root:

```bash
# Run tests
pytest
uv run pytest

# Lint
ruff check src/
uv run ruff check src/ scripts/ tests/

# Format
ruff format src/
uv run ruff format src/ scripts/ tests/
```

Fix any lint/test failures before opening a PR.

## Endpoint Registry

`src/pse_sdk/_registry.py` is generated from the PSE OpenAPI spec (`https://api.raporty.pse.pl/api/openapi`) — don't edit it by hand.

```bash
# Regenerate from the live spec
uv run scripts/gen_registry.py

# Check that the committed registry is up to date
uv run scripts/gen_registry.py --check
```

## Endpoint Docs

`docs/endpoints.md` is generated from the registry — don't edit it by hand. Regenerate it after any registry change.

```bash
# Regenerate
uv run scripts/gen_docs.py

# Check that the committed docs are up to date
uv run scripts/gen_docs.py --check
```

## Dependencies

Dev dependencies live in the `dev` dependency group in `pyproject.toml`; exact versions are pinned in `uv.lock`.

```bash
# Add a dev dependency
uv add --dev <package>

# Upgrade a single locked package
uv lock --upgrade-package <package>
```

Commit `uv.lock` together with any `pyproject.toml` dependency change.

## Commit Convention

Use [Conventional Commits](https://www.conventionalcommits.org/):
Expand Down
44 changes: 21 additions & 23 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
Copyright (C) 2026 FranekGit - All Rights Reserved.

IMPORTANT NOTICE: PLEASE READ CAREFULLY BEFORE USING THE SOFTWARE.

1. PROPRIETARY AND CONFIDENTIAL INFORMATION

The contents of this project, including its source code, are proprietary and confidential. Unauthorized copying, transferring, or reproduction of any part of this project, through any medium, is strictly prohibited.

2. LICENSE GRANT

The receipt or possession of the source code and/or any parts thereof does not convey or imply any right to use them for any purpose other than the specific purpose for which they were provided to you.

3. DISCLAIMER OF WARRANTIES

The software is provided "AS IS," without warranty of any kind, express or implied, including, but not limited to, the warranties of merchantability, fitness for a particular purpose, and non-infringement.

4. LIMITATION OF LIABILITY

In no event shall Sourceduty, its authors, or copyright holders be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the Software or the use or other dealings in the Software.

5. COPYRIGHT NOTICE

You are required to include the above copyright notice and this permission notice in all copies or substantial portions of the Software.
MIT License

Copyright (c) 2026 FranekGit

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
48 changes: 22 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
<p align="center">
<img src="assets/pse_logo.png" alt="PSE Logo">
<img src="https://raw.githubusercontent.com/FranekGit/pse-python-sdk/main/assets/pse_logo.png" alt="PSE Logo">
</p>

# pse-python-sdk

![Version](https://img.shields.io/badge/version-v1.5.1-blue)
![Version](https://img.shields.io/badge/version-v2.0.0-blue)

Python SDK for the PSE (Polskie Sieci Elektroenergetyczne) public reporting API.

> API reference: https://api.raporty.pse.pl/app/home


> **Disclaimer:** not affiliated with PSE S.A.


## Installation

```bash
pip install git+https://github.com/FranekGit/pse-python-sdk.git
pip install pse-sdk
```

## Quick Start
Expand All @@ -24,29 +27,22 @@ from pse_sdk import PSEClient

client = PSEClient()

# Returns list[dict]
records = client.get_cen(start="2024-01-01", end="2024-01-31")

# Returns pd.DataFrame (requires pandas)
df = client.get_cen(start="2024-01-01", end="2024-01-31", format="dataframe")
# list[dict] with all columns
rows = client.fetch("price-cost", start="2025-10-01", end="2025-10-31")

# pd.DataFrame (requires pandas) with selected columns
df = client.fetch(
"price-cost",
start="2025-10-01",
end="2025-10-31",
columns=["cen_cost", "ckoeb_cost"],
format="dataframe",
)
```

## Date Formats

| Format | Example |
|--------------|--------------|
| `YYYY-MM-DD` | `2024-01-01` |
| `YYYY/MM/DD` | `2024/01/01` |
| `YYYYMMDD` | `20240101` |

## Output Formats

| Format | Return Type |
|---------------|----------------|
| `"dict"` | `list[dict]` |
| `"dataframe"` | `pd.DataFrame` |

## Endpoints

See [docs/endpoints.md](docs/endpoints.md) for available endpoints.
## Documentation

- [docs/usage.md](https://github.com/FranekGit/pse-python-sdk/blob/main/docs/usage.md): finding endpoints, date ranges, columns and
output formats
- [docs/endpoints.md](https://github.com/FranekGit/pse-python-sdk/blob/main/docs/endpoints.md): all endpoints, their columns and
types
Loading
Loading