aemo-mdff-reader 2.0.2__tar.gz → 2.0.4__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.
Files changed (43) hide show
  1. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/CHANGELOG.md +49 -0
  2. aemo_mdff_reader-2.0.4/CONTRIBUTING.md +196 -0
  3. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/PKG-INFO +14 -4
  4. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/README.md +13 -3
  5. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader/__init__.py +1 -1
  6. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader.egg-info/PKG-INFO +14 -4
  7. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/pyproject.toml +1 -1
  8. aemo_mdff_reader-2.0.2/CONTRIBUTING.md +0 -118
  9. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/LICENSE +0 -0
  10. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/MANIFEST.in +0 -0
  11. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader/aggregate.py +0 -0
  12. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader/cli.py +0 -0
  13. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader/parser.py +0 -0
  14. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader/py.typed +0 -0
  15. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader/reader.py +0 -0
  16. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader/spec.py +0 -0
  17. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader/sql/__init__.py +0 -0
  18. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader/sql/query.py +0 -0
  19. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader/sql/store.py +0 -0
  20. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader/types.py +0 -0
  21. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader.egg-info/SOURCES.txt +0 -0
  22. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader.egg-info/dependency_links.txt +0 -0
  23. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader.egg-info/entry_points.txt +0 -0
  24. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader.egg-info/requires.txt +0 -0
  25. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/aemo_mdff_reader.egg-info/top_level.txt +0 -0
  26. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/benchmarks/bench_parser.py +0 -0
  27. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/setup.cfg +0 -0
  28. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/setup.py +0 -0
  29. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/tests/__init__.py +0 -0
  30. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/tests/fixtures/generate.py +0 -0
  31. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/tests/fixtures/sample_nem12.csv +0 -0
  32. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/tests/fixtures/sample_nem13.csv +0 -0
  33. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/tests/test_cli.py +0 -0
  34. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/tests/test_datetime_formats.py +0 -0
  35. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/tests/test_edge_cases.py +0 -0
  36. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/tests/test_ergonomics.py +0 -0
  37. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/tests/test_events_b2b.py +0 -0
  38. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/tests/test_large_files.py +0 -0
  39. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/tests/test_nem13.py +0 -0
  40. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/tests/test_parser.py +0 -0
  41. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/tests/test_spec.py +0 -0
  42. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/tests/test_sql.py +0 -0
  43. {aemo_mdff_reader-2.0.2 → aemo_mdff_reader-2.0.4}/tests/test_validation.py +0 -0
@@ -4,6 +4,55 @@ All notable changes are documented here. The format is based on
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the
5
5
  project follows [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [2.0.4](https://github.com/Utilified/aemo-mdff-reader/compare/v2.0.3...v2.0.4) (2026-05-10)
8
+
9
+ First release published to PyPI after the supply-chain hardening landed
10
+ in v2.0.3 — which itself failed to publish due to two release-pipeline
11
+ bugs (see notice on the v2.0.3 GitHub Release). PyPI users upgrading
12
+ from 2.0.2 receive **both** the v2.0.3 hardening (SLSA build provenance,
13
+ CycloneDX SBOM, release-please automation, dependabot grouping) and the
14
+ fixes below in one upgrade. No source or behavioural changes versus 2.0.2.
15
+
16
+ ### Bug Fixes
17
+
18
+ * release-please dispatch + SBOM directory creation ([#17](https://github.com/Utilified/aemo-mdff-reader/issues/17)) ([8e3cd13](https://github.com/Utilified/aemo-mdff-reader/commit/8e3cd13ca11bad3399efd2e5fd2fe5ae6bcb2a90))
19
+
20
+ ## [2.0.3](https://github.com/Utilified/aemo-mdff-reader/compare/v2.0.2...v2.0.3) (2026-05-10)
21
+
22
+ Supply-chain hardening and release-process automation. No source or
23
+ behavioural changes versus 2.0.2 — same wheel/sdist content, plus
24
+ provenance, SBOM, and an automated release pipeline.
25
+
26
+ ### Added
27
+
28
+ - SLSA build provenance attestations on the wheel and sdist (via
29
+ `actions/attest-build-provenance`). Verifiable with
30
+ `gh attestation verify`.
31
+ - CycloneDX SBOM generated by `anchore/sbom-action` and attested
32
+ against both artifacts (via `actions/attest-sbom`). SBOM is also
33
+ attached to each GitHub Release alongside the sigstore signatures.
34
+ - `release-please` automation: releases are now proposed and cut
35
+ from Conventional Commits. Merging the auto-generated release PR
36
+ creates the tag, which dispatches the existing `release.yml`
37
+ pipeline. See [CONTRIBUTING.md](CONTRIBUTING.md) for the flow.
38
+ - Dependabot grouping: minor/patch GitHub Actions bumps land as a
39
+ single weekly PR; minor/patch runtime-extras bumps (pandas /
40
+ pyarrow / PyMySQL) land as a separate weekly PR. Majors stay
41
+ individual.
42
+ - README badges for CodeQL, OpenSSF Scorecard, and OpenSSF Best
43
+ Practices.
44
+
45
+ ### Changed
46
+
47
+ - Branch protection on `main` now requires PR conversation resolution
48
+ before merge.
49
+ - GitHub Discussions enabled on the repository as a Q&A surface
50
+ separate from the issue tracker.
51
+
52
+ ### Bug Fixes
53
+
54
+ * rename release-please config to default path ([#15](https://github.com/Utilified/aemo-mdff-reader/issues/15)) ([843d25f](https://github.com/Utilified/aemo-mdff-reader/commit/843d25ff8c35944e08eb70ebfdb076acdf1c9855))
55
+
7
56
  ## [Unreleased]
8
57
 
9
58
  ## [2.0.2] — 2026-05-10
@@ -0,0 +1,196 @@
1
+ # Contributing
2
+
3
+ Thanks for your interest in improving aemo-mdff-reader. The repository
4
+ is small and the bar for contributions is straightforward: a pull
5
+ request that passes CI and doesn't regress the public benchmark is
6
+ welcome.
7
+
8
+ Naming: everything (GitHub repo `Utilified/aemo-mdff-reader`, PyPI
9
+ distribution `aemo-mdff-reader`, Python import `aemo_mdff_reader`,
10
+ CLI `aemo-mdff-reader`) is consistently named after the AEMO spec —
11
+ MDFF, the Meter Data File Format that covers both NEM12 (interval) and
12
+ NEM13 (accumulation) formats. GitHub serves redirects from the
13
+ previous `Utilified/nem12-reader` repo URL so existing git pins
14
+ continue to work; v1 callers importing `from nem12_reader …` need to
15
+ update to `from aemo_mdff_reader …`.
16
+
17
+ ## Setup
18
+
19
+ ```bash
20
+ git clone https://github.com/Utilified/aemo-mdff-reader.git
21
+ cd aemo-mdff-reader
22
+ python -m venv .venv && source .venv/bin/activate
23
+ pip install -e .[dev]
24
+ pytest
25
+ ```
26
+
27
+ ## Running the test suite
28
+
29
+ ```bash
30
+ pytest -v
31
+ pytest --cov=aemo_mdff_reader --cov-report=term-missing
32
+ ```
33
+
34
+ A small, sanitized NEM12 sample lives at
35
+ `tests/fixtures/sample_nem12.csv`. To generate larger synthetic files
36
+ for ad-hoc testing or benchmarking:
37
+
38
+ ```bash
39
+ python tests/fixtures/generate.py /tmp/big.csv --nmis 4 --days 365 --interval-minutes 5
40
+ ```
41
+
42
+ ## Performance
43
+
44
+ `benchmarks/bench_parser.py` is the canonical performance test. Please
45
+ run it before and after changes that touch the hot path
46
+ (`parser.py::_emit_intervals`, `parse_to_columns`, `to_columns`):
47
+
48
+ ```bash
49
+ python benchmarks/bench_parser.py --nmis 4 --days 365 --interval-minutes 5
50
+ ```
51
+
52
+ The streaming and columnar fast paths must remain at or above the
53
+ current published throughput.
54
+
55
+ ## Code style
56
+
57
+ - Pure stdlib in the core. **No** new required runtime dependencies.
58
+ Optional features go behind `[project.optional-dependencies]`.
59
+ - Type hints on all public symbols.
60
+ - Keep `aemo_mdff_reader.types` slots-based — per-row allocation is on
61
+ the hot path.
62
+
63
+ ## Commit messages
64
+
65
+ Releases are generated automatically from commits using
66
+ [release-please](https://github.com/googleapis/release-please), so the
67
+ commit subject prefix is load-bearing — it determines whether a release
68
+ is cut and what kind of version bump it gets.
69
+
70
+ Use [Conventional Commits](https://www.conventionalcommits.org/):
71
+
72
+ | Prefix | Effect on next release |
73
+ | ---------------------------------- | -------------------------------------- |
74
+ | `feat: …` | minor bump (e.g. 2.0.x → 2.1.0) |
75
+ | `fix: …` | patch bump (e.g. 2.0.0 → 2.0.1) |
76
+ | `feat!: …` or `BREAKING CHANGE:` footer | major bump (e.g. 2.x → 3.0.0) |
77
+ | `chore: …` / `docs: …` / `refactor: …` / `style: …` / `test: …` / `ci: …` / `build: …` | no release on its own |
78
+ | any commit with `Release-As: x.y.z` footer | forces that exact version |
79
+
80
+ Subject line: imperative mood, under 72 chars, lowercase after the
81
+ prefix. Examples that work well:
82
+
83
+ ```
84
+ feat: stream NEM13 250 records via parse_accumulations
85
+ fix: handle CRLF line endings in 300-record payloads
86
+ chore: bump CI matrix to include Python 3.13
87
+ ```
88
+
89
+ Squash-merge is preferred — the squash commit message becomes the
90
+ release-please input, so make it count.
91
+
92
+ ## Reporting issues
93
+
94
+ Please open an issue with:
95
+
96
+ 1. The Python version and OS.
97
+ 2. A minimal reproducer (a few NEM12 rows is usually enough).
98
+ 3. The expected vs actual behaviour.
99
+
100
+ If you can share a sanitized sample file (no real NMIs / meter
101
+ serials), please attach it to the issue.
102
+
103
+ ## Releasing
104
+
105
+ Releases are automated via [release-please](https://github.com/googleapis/release-please).
106
+ Maintainers do not run `git tag` by hand for normal releases.
107
+
108
+ ### Normal flow (Conventional Commits drive it)
109
+
110
+ 1. Land a `feat:` or `fix:` commit on `main` (via squash-merged PR).
111
+ 2. The `release-please` workflow runs and either opens a new release PR
112
+ titled `chore(main): release X.Y.Z` or updates the existing one.
113
+ The PR auto-bumps `pyproject.toml` and `aemo_mdff_reader/__init__.py`
114
+ (the `# x-release-please-version` annotation in `__init__.py` marks
115
+ the line release-please rewrites) and drafts the `CHANGELOG.md`
116
+ entry from the commit log.
117
+ 3. Review the release PR. Edit the changelog entry directly on the PR
118
+ if you want to massage wording — release-please will keep your
119
+ edits across reruns. When happy, **squash-merge** it.
120
+ 4. release-please creates the `vX.Y.Z` git tag on merge.
121
+ 5. Because tags created by `GITHUB_TOKEN` do not trigger downstream
122
+ tag-push workflows (GitHub anti-recursion guard), `release-please.yml`
123
+ explicitly dispatches `release.yml` for the new tag.
124
+ 6. `release.yml` runs the publish pipeline:
125
+ build → SLSA build provenance attestation → CycloneDX SBOM +
126
+ attestation → upload artefacts → wait on the `pypi` Environment
127
+ reviewer → sigstore sign → PyPI Trusted Publishing → GitHub Release
128
+ with wheel + sdist + signatures + SBOM attached.
129
+ 7. Approve the deployment in the `pypi` Environment when GitHub
130
+ notifies you. The publish completes; verify at
131
+ https://pypi.org/project/aemo-mdff-reader/ and
132
+ https://github.com/Utilified/aemo-mdff-reader/releases.
133
+
134
+ ### Forcing a release without a feat/fix commit
135
+
136
+ Two options:
137
+
138
+ - Add `Release-As: x.y.z` as a commit-message footer on a commit
139
+ landing on `main` (works for `chore:` / `docs:` etc. that wouldn't
140
+ trigger a release on their own).
141
+ - Manually trigger the `release-please` workflow via GitHub Actions →
142
+ *release-please* → "Run workflow" (workflow_dispatch).
143
+
144
+ ### Emergency manual release (rare)
145
+
146
+ `release.yml` still listens on tag-push, so a maintainer can bypass
147
+ release-please entirely:
148
+
149
+ ```bash
150
+ # Bump version in pyproject.toml AND aemo_mdff_reader/__init__.py
151
+ # (preserve the `# x-release-please-version` comment on __init__.py),
152
+ # update CHANGELOG.md, then:
153
+ git commit -am "release: vX.Y.Z"
154
+ git tag vX.Y.Z
155
+ git push origin main vX.Y.Z
156
+ ```
157
+
158
+ Use only if release-please is broken — otherwise you'll fight it on
159
+ the next push.
160
+
161
+ ### One-time infrastructure setup (per project)
162
+
163
+ Already done for `aemo-mdff-reader`; documented here for posterity.
164
+
165
+ 1. **PyPI Trusted Publishing**: register the project at
166
+ https://pypi.org/manage/account/publishing/ with:
167
+ - PyPI project name: `aemo-mdff-reader`
168
+ - Owner: `Utilified`
169
+ - Repository: `aemo-mdff-reader`
170
+ - Workflow filename: `release.yml`
171
+ - Environment name: `pypi`
172
+ 2. **GitHub Environment**: in *Settings → Environments*, create an
173
+ environment named `pypi`. Add required reviewers (recommended) and
174
+ restrict the deployment branch policy to `v*` tags.
175
+ 3. **Repository variable**: set `PYPI_PUBLISH_ENABLED=true` under
176
+ *Settings → Secrets and variables → Actions → Variables*. The
177
+ publish job is gated on this so the workflow runs cleanly while
178
+ Trusted Publishing is being configured (build + sign succeed;
179
+ publish skips).
180
+ 4. **Workflow permissions**: under *Settings → Actions → General →
181
+ Workflow permissions*, set "Read and write permissions" and tick
182
+ "Allow GitHub Actions to create and approve pull requests" — the
183
+ `release-please` action needs both to open release PRs.
184
+
185
+ ### Local dry run of the build
186
+
187
+ ```bash
188
+ python -m build
189
+ twine check --strict dist/*
190
+ python -m venv /tmp/smoke && /tmp/smoke/bin/pip install dist/*.whl
191
+ /tmp/smoke/bin/aemo-mdff-reader --version
192
+ ```
193
+
194
+ There is no way to dry-run the publish step — Trusted Publishing only
195
+ authenticates a real `release.yml` run on a real tag. The first
196
+ release after touching `release.yml` is the de-facto integration test.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aemo-mdff-reader
3
- Version: 2.0.2
3
+ Version: 2.0.4
4
4
  Summary: Fast streaming reader for AEMO MDFF NEM12 / NEM13 metering files. Zero required dependencies.
5
5
  Author: Utilified Holdings Pty Ltd
6
6
  License-Expression: MIT
@@ -51,6 +51,10 @@ Dynamic: license-file
51
51
  [![PyPI](https://img.shields.io/pypi/v/aemo-mdff-reader.svg)](https://pypi.org/project/aemo-mdff-reader/)
52
52
  [![Python versions](https://img.shields.io/pypi/pyversions/aemo-mdff-reader.svg)](https://pypi.org/project/aemo-mdff-reader/)
53
53
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
54
+ [![CodeQL](https://github.com/Utilified/aemo-mdff-reader/actions/workflows/codeql.yml/badge.svg)](https://github.com/Utilified/aemo-mdff-reader/actions/workflows/codeql.yml)
55
+ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/Utilified/aemo-mdff-reader/badge)](https://scorecard.dev/viewer/?uri=github.com/Utilified/aemo-mdff-reader)
56
+ <!-- TODO: replace PROJECTID after registering at https://www.bestpractices.dev/ -->
57
+ [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/PROJECTID/badge)](https://www.bestpractices.dev/projects/PROJECTID)
54
58
 
55
59
  Fast, zero-dependency streaming reader for AEMO **NEM12** and **NEM13**
56
60
  metering files. Implements AEMO MDFF (Meter Data File Format) v2.6.
@@ -238,9 +242,15 @@ pytest
238
242
  ```
239
243
 
240
244
  CI runs ruff, mypy --strict, the test matrix on Python 3.9 → 3.12 /
241
- Linux / macOS / Windows, `pip-audit`, `bandit`, and a wheel-install
242
- smoke test. Releases are signed with sigstore and published to PyPI
243
- via Trusted Publishing on tag.
245
+ Linux / macOS / Windows, `pip-audit`, `bandit`, CodeQL, OpenSSF
246
+ Scorecard, and a wheel-install smoke test.
247
+
248
+ Releases are automated by [release-please](https://github.com/googleapis/release-please)
249
+ from [Conventional Commits](https://www.conventionalcommits.org/) on
250
+ `main`, then signed with sigstore, attested with SLSA build provenance
251
+ and a CycloneDX SBOM, and published to PyPI via Trusted Publishing.
252
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for the contributor commit
253
+ conventions and the full release flow.
244
254
 
245
255
  ## License
246
256
 
@@ -4,6 +4,10 @@
4
4
  [![PyPI](https://img.shields.io/pypi/v/aemo-mdff-reader.svg)](https://pypi.org/project/aemo-mdff-reader/)
5
5
  [![Python versions](https://img.shields.io/pypi/pyversions/aemo-mdff-reader.svg)](https://pypi.org/project/aemo-mdff-reader/)
6
6
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7
+ [![CodeQL](https://github.com/Utilified/aemo-mdff-reader/actions/workflows/codeql.yml/badge.svg)](https://github.com/Utilified/aemo-mdff-reader/actions/workflows/codeql.yml)
8
+ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/Utilified/aemo-mdff-reader/badge)](https://scorecard.dev/viewer/?uri=github.com/Utilified/aemo-mdff-reader)
9
+ <!-- TODO: replace PROJECTID after registering at https://www.bestpractices.dev/ -->
10
+ [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/PROJECTID/badge)](https://www.bestpractices.dev/projects/PROJECTID)
7
11
 
8
12
  Fast, zero-dependency streaming reader for AEMO **NEM12** and **NEM13**
9
13
  metering files. Implements AEMO MDFF (Meter Data File Format) v2.6.
@@ -191,9 +195,15 @@ pytest
191
195
  ```
192
196
 
193
197
  CI runs ruff, mypy --strict, the test matrix on Python 3.9 → 3.12 /
194
- Linux / macOS / Windows, `pip-audit`, `bandit`, and a wheel-install
195
- smoke test. Releases are signed with sigstore and published to PyPI
196
- via Trusted Publishing on tag.
198
+ Linux / macOS / Windows, `pip-audit`, `bandit`, CodeQL, OpenSSF
199
+ Scorecard, and a wheel-install smoke test.
200
+
201
+ Releases are automated by [release-please](https://github.com/googleapis/release-please)
202
+ from [Conventional Commits](https://www.conventionalcommits.org/) on
203
+ `main`, then signed with sigstore, attested with SLSA build provenance
204
+ and a CycloneDX SBOM, and published to PyPI via Trusted Publishing.
205
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for the contributor commit
206
+ conventions and the full release flow.
197
207
 
198
208
  ## License
199
209
 
@@ -48,7 +48,7 @@ from .types import (
48
48
  NMIDetails,
49
49
  )
50
50
 
51
- __version__ = "2.0.2"
51
+ __version__ = "2.0.4" # x-release-please-version
52
52
 
53
53
  __all__ = [
54
54
  "INTERVAL_DATA_OUTPUT_HEADERS",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aemo-mdff-reader
3
- Version: 2.0.2
3
+ Version: 2.0.4
4
4
  Summary: Fast streaming reader for AEMO MDFF NEM12 / NEM13 metering files. Zero required dependencies.
5
5
  Author: Utilified Holdings Pty Ltd
6
6
  License-Expression: MIT
@@ -51,6 +51,10 @@ Dynamic: license-file
51
51
  [![PyPI](https://img.shields.io/pypi/v/aemo-mdff-reader.svg)](https://pypi.org/project/aemo-mdff-reader/)
52
52
  [![Python versions](https://img.shields.io/pypi/pyversions/aemo-mdff-reader.svg)](https://pypi.org/project/aemo-mdff-reader/)
53
53
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
54
+ [![CodeQL](https://github.com/Utilified/aemo-mdff-reader/actions/workflows/codeql.yml/badge.svg)](https://github.com/Utilified/aemo-mdff-reader/actions/workflows/codeql.yml)
55
+ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/Utilified/aemo-mdff-reader/badge)](https://scorecard.dev/viewer/?uri=github.com/Utilified/aemo-mdff-reader)
56
+ <!-- TODO: replace PROJECTID after registering at https://www.bestpractices.dev/ -->
57
+ [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/PROJECTID/badge)](https://www.bestpractices.dev/projects/PROJECTID)
54
58
 
55
59
  Fast, zero-dependency streaming reader for AEMO **NEM12** and **NEM13**
56
60
  metering files. Implements AEMO MDFF (Meter Data File Format) v2.6.
@@ -238,9 +242,15 @@ pytest
238
242
  ```
239
243
 
240
244
  CI runs ruff, mypy --strict, the test matrix on Python 3.9 → 3.12 /
241
- Linux / macOS / Windows, `pip-audit`, `bandit`, and a wheel-install
242
- smoke test. Releases are signed with sigstore and published to PyPI
243
- via Trusted Publishing on tag.
245
+ Linux / macOS / Windows, `pip-audit`, `bandit`, CodeQL, OpenSSF
246
+ Scorecard, and a wheel-install smoke test.
247
+
248
+ Releases are automated by [release-please](https://github.com/googleapis/release-please)
249
+ from [Conventional Commits](https://www.conventionalcommits.org/) on
250
+ `main`, then signed with sigstore, attested with SLSA build provenance
251
+ and a CycloneDX SBOM, and published to PyPI via Trusted Publishing.
252
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for the contributor commit
253
+ conventions and the full release flow.
244
254
 
245
255
  ## License
246
256
 
@@ -11,7 +11,7 @@ build-backend = "setuptools.build_meta"
11
11
  # Pillow / PIL precedent (``pip install Pillow`` → ``import PIL``)
12
12
  # applies here.
13
13
  name = "aemo-mdff-reader"
14
- version = "2.0.2"
14
+ version = "2.0.4"
15
15
  description = "Fast streaming reader for AEMO MDFF NEM12 / NEM13 metering files. Zero required dependencies."
16
16
  readme = "README.md"
17
17
  license = "MIT"
@@ -1,118 +0,0 @@
1
- # Contributing
2
-
3
- Thanks for your interest in improving aemo-mdff-reader. The repository
4
- is small and the bar for contributions is straightforward: a pull
5
- request that passes CI and doesn't regress the public benchmark is
6
- welcome.
7
-
8
- Naming: everything (GitHub repo `Utilified/aemo-mdff-reader`, PyPI
9
- distribution `aemo-mdff-reader`, Python import `aemo_mdff_reader`,
10
- CLI `aemo-mdff-reader`) is consistently named after the AEMO spec —
11
- MDFF, the Meter Data File Format that covers both NEM12 (interval) and
12
- NEM13 (accumulation) formats. GitHub serves redirects from the
13
- previous `Utilified/nem12-reader` repo URL so existing git pins
14
- continue to work; v1 callers importing `from nem12_reader …` need to
15
- update to `from aemo_mdff_reader …`.
16
-
17
- ## Setup
18
-
19
- ```bash
20
- git clone https://github.com/Utilified/aemo-mdff-reader.git
21
- cd aemo-mdff-reader
22
- python -m venv .venv && source .venv/bin/activate
23
- pip install -e .[dev]
24
- pytest
25
- ```
26
-
27
- ## Running the test suite
28
-
29
- ```bash
30
- pytest -v
31
- pytest --cov=aemo_mdff_reader --cov-report=term-missing
32
- ```
33
-
34
- A small, sanitized NEM12 sample lives at
35
- `tests/fixtures/sample_nem12.csv`. To generate larger synthetic files
36
- for ad-hoc testing or benchmarking:
37
-
38
- ```bash
39
- python tests/fixtures/generate.py /tmp/big.csv --nmis 4 --days 365 --interval-minutes 5
40
- ```
41
-
42
- ## Performance
43
-
44
- `benchmarks/bench_parser.py` is the canonical performance test. Please
45
- run it before and after changes that touch the hot path
46
- (`parser.py::_emit_intervals`, `parse_to_columns`, `to_columns`):
47
-
48
- ```bash
49
- python benchmarks/bench_parser.py --nmis 4 --days 365 --interval-minutes 5
50
- ```
51
-
52
- The streaming and columnar fast paths must remain at or above the
53
- current published throughput.
54
-
55
- ## Code style
56
-
57
- - Pure stdlib in the core. **No** new required runtime dependencies.
58
- Optional features go behind `[project.optional-dependencies]`.
59
- - Type hints on all public symbols.
60
- - Keep `aemo_mdff_reader.types` slots-based — per-row allocation is on
61
- the hot path.
62
-
63
- ## Reporting issues
64
-
65
- Please open an issue with:
66
-
67
- 1. The Python version and OS.
68
- 2. A minimal reproducer (a few NEM12 rows is usually enough).
69
- 3. The expected vs actual behaviour.
70
-
71
- If you can share a sanitized sample file (no real NMIs / meter
72
- serials), please attach it to the issue.
73
-
74
- ## Releasing
75
-
76
- Maintainers only. Releases are tagged and pushed to GitHub; the
77
- `Release` workflow then builds, signs (sigstore), publishes to PyPI
78
- (via Trusted Publishing), and attaches signatures to the GitHub Release.
79
-
80
- ### One-time setup (per project)
81
-
82
- Before the first release, configure these on PyPI / GitHub:
83
-
84
- 1. **PyPI Trusted Publishing**: register the project at
85
- https://pypi.org/manage/account/publishing/ with:
86
- - PyPI project name: `aemo-mdff-reader`
87
- - Owner: `Utilified`
88
- - Repository: `aemo-mdff-reader`
89
- - Workflow filename: `release.yml`
90
- - Environment name: `pypi`
91
- 2. **GitHub Environment**: in *Settings → Environments*, create an
92
- environment named `pypi`. Add required reviewers if you want
93
- manual approval before publish (recommended for the first few
94
- releases). Without this environment, the publish job will fail with
95
- a confusing "environment not found" error.
96
-
97
- ### Cutting a release
98
-
99
- ```bash
100
- # Bump version in pyproject.toml AND aemo_mdff_reader/__init__.py.
101
- # Update CHANGELOG.md with the new section.
102
- git commit -am "release: vX.Y.Z"
103
- git tag vX.Y.Z
104
- git push origin main vX.Y.Z
105
- ```
106
-
107
- The `Release` workflow takes over from here. Verify the published
108
- artefact at https://pypi.org/project/aemo-mdff-reader/ and the
109
- GitHub Release at https://github.com/Utilified/aemo-mdff-reader/releases.
110
-
111
- ### Local dry run
112
-
113
- ```bash
114
- python -m build
115
- twine check --strict dist/*
116
- python -m venv /tmp/smoke && /tmp/smoke/bin/pip install dist/*.whl
117
- /tmp/smoke/bin/aemo-mdff-reader --version
118
- ```