Skip to content

Commit 321dcef

Browse files
committed
fix: harden API responses and package tooling
1 parent 55c2655 commit 321dcef

23 files changed

Lines changed: 806 additions & 119 deletions

‎.github/workflows/ci.yml‎

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ on:
66
pull_request:
77
branches: [main]
88

9+
permissions:
10+
contents: read
11+
912
jobs:
1013
test:
1114
name: Test Python ${{ matrix.python-version }}
@@ -25,18 +28,14 @@ jobs:
2528
- name: Install dependencies
2629
run: make install-dev
2730

28-
- name: Run tests
29-
run: make test
30-
31-
- name: Run coverage
32-
if: matrix.python-version == '3.14'
31+
- name: Run tests with coverage
3332
run: make coverage
3433

3534
- name: Upload coverage to Codecov
3635
if: matrix.python-version == '3.14'
3736
uses: codecov/codecov-action@v4
3837
with:
39-
file: ./coverage.xml
38+
files: ./coverage.xml
4039
fail_ci_if_error: false
4140

4241
lint:
@@ -59,3 +58,18 @@ jobs:
5958

6059
- name: Run type check
6160
run: make type-check
61+
62+
package:
63+
name: Build & Validate Distribution
64+
runs-on: ubuntu-latest
65+
steps:
66+
- name: Checkout code
67+
uses: actions/checkout@v4
68+
69+
- name: Set up Python
70+
uses: actions/setup-python@v5
71+
with:
72+
python-version: "3.14"
73+
74+
- name: Build, validate and install wheel
75+
run: make check-dist

‎.github/workflows/release.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ jobs:
5050
- name: Install dependencies
5151
run: make install-dev
5252

53-
- name: Build package
54-
run: make build
53+
- name: Build and validate package
54+
run: make check-dist
5555

5656
- name: Publish to PyPI
5757
uses: pypa/gh-action-pypi-publish@release/v1

‎.gitignore‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ wheels/
2323

2424
# Virtual environments
2525
venv/
26+
.venv/
2627
env/
2728
ENV/
2829

@@ -35,6 +36,7 @@ ENV/
3536
# Testing
3637
.pytest_cache/
3738
.coverage
39+
coverage.xml
3840
htmlcov/
3941

4042
# mypy

‎Makefile‎

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
.PHONY: help install install-dev clean test coverage lint format type-check build upload upload-test venv
1+
PYTHON ?= python3.14
2+
SOURCES = energy_tracker_api/ tests/ scripts/ example.py
3+
4+
.PHONY: help install install-dev clean test coverage lint format type-check build check-dist upload upload-test venv all
25

36
help:
47
@echo "Available commands:"
@@ -12,22 +15,24 @@ help:
1215
@echo " make format - Format code with black and isort"
1316
@echo " make type-check - Run type checking with mypy"
1417
@echo " make build - Build distribution packages"
18+
@echo " make check-dist - Validate packages and test an isolated wheel installation"
1519
@echo " make upload-test - Upload to TestPyPI"
1620
@echo " make upload - Upload to PyPI"
1721

1822
venv/bin/python:
1923
@echo "Creating virtual environment..."
20-
python3 -m venv venv
24+
$(PYTHON) -m venv venv
2125
@echo "Upgrading pip..."
2226
venv/bin/pip install --upgrade pip
2327

24-
.install-stamp: venv/bin/python requirements.txt
25-
venv/bin/pip install -r requirements.txt
28+
venv: venv/bin/python
29+
30+
.install-stamp: venv/bin/python pyproject.toml
2631
venv/bin/pip install -e .
2732
@touch .install-stamp
2833

29-
.install-dev-stamp: .install-stamp requirements-dev.txt
30-
venv/bin/pip install -r requirements-dev.txt
34+
.install-dev-stamp: .install-stamp pyproject.toml
35+
venv/bin/pip install -e '.[dev]'
3136
@touch .install-dev-stamp
3237

3338
install: .install-stamp
@@ -42,35 +47,39 @@ clean:
4247
rm -rf .mypy_cache/
4348
rm -rf htmlcov/
4449
rm -rf .coverage
45-
rm -rf venv/
50+
rm -f coverage.xml
4651
rm -rf .install-stamp .install-dev-stamp
47-
find . -type d -name __pycache__ -exec rm -rf {} +
48-
find . -type f -name "*.pyc" -delete
52+
find energy_tracker_api tests scripts -type d -name __pycache__ -exec rm -rf {} +
4953

5054
test: .install-dev-stamp
5155
venv/bin/python -m pytest tests/ -v
5256

5357
coverage: .install-dev-stamp
54-
venv/bin/python -m pytest tests/ --cov=energy_tracker_api --cov-report=html --cov-report=term
58+
venv/bin/python -m pytest tests/ --cov=energy_tracker_api --cov-report=html --cov-report=term --cov-report=xml
5559

5660
lint: .install-dev-stamp
57-
venv/bin/python -m black --check energy_tracker_api/ tests/
58-
venv/bin/python -m isort --check-only energy_tracker_api/ tests/
61+
venv/bin/python -m black --check $(SOURCES)
62+
venv/bin/python -m isort --check-only $(SOURCES)
5963

6064
format: .install-dev-stamp
61-
venv/bin/python -m black energy_tracker_api/ tests/
62-
venv/bin/python -m isort energy_tracker_api/ tests/
65+
venv/bin/python -m isort $(SOURCES)
66+
venv/bin/python -m black $(SOURCES)
6367

6468
type-check: .install-dev-stamp
65-
venv/bin/python -m mypy energy_tracker_api/
69+
venv/bin/python -m mypy energy_tracker_api/ scripts/ example.py
6670

6771
build: .install-dev-stamp
72+
rm -rf build/ dist/
6873
venv/bin/python -m build
6974

70-
upload-test: .install-dev-stamp build
75+
check-dist: build
76+
venv/bin/python -m twine check dist/*
77+
venv/bin/python scripts/check_distribution.py
78+
79+
upload-test: check-dist
7180
venv/bin/python -m twine upload --repository testpypi dist/*
7281

73-
upload: .install-dev-stamp build
82+
upload: check-dist
7483
venv/bin/python -m twine upload dist/*
7584

76-
all: clean format lint type-check test
85+
all: lint type-check coverage check-dist

‎README.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ client = EnergyTrackerClient(
5858
## Error Handling
5959

6060
All API errors inherit from `EnergyTrackerAPIError` and carry an `api_message` list with details from the server.
61+
Each operation accepts only its documented success status (200, 201 or 204).
62+
Unexpected statuses and redirects raise `EnergyTrackerAPIError`; redirects are not followed.
6163

6264
```python
6365
from energy_tracker_api import (
@@ -86,8 +88,20 @@ make test # Run tests
8688
make type-check # mypy
8789
make format # black + isort
8890
make lint # Linters
91+
make check-dist # Build, validate and import an isolated wheel installation
8992
```
9093

94+
Package metadata, version and dependencies are maintained in `pyproject.toml`.
95+
The requirements files are compatibility entry points for installing the package
96+
and its development extra. The Makefile uses `python3.14` by default; override it
97+
with `make install-dev PYTHON=/path/to/python3.14` when needed.
98+
99+
Meter reading values must be finite `Decimal` values. The client serializes them
100+
as fixed-point strings without redundant fractional zeros and never rounds them.
101+
Server-side range and precision validation still applies. When creating and
102+
deleting the same reading, reuse its timestamp; prefer UTC-aware timestamps
103+
with whole seconds as shown in `example.py`.
104+
91105
## License
92106

93107
MIT

0 commit comments

Comments
 (0)