noaa-gml-file-reader 2.0.0__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 (24) hide show
  1. noaa_gml_file_reader-2.0.0/.gitattributes +2 -0
  2. noaa_gml_file_reader-2.0.0/.github/FUNDING.yml +16 -0
  3. noaa_gml_file_reader-2.0.0/.github/workflows/ci.yml +57 -0
  4. noaa_gml_file_reader-2.0.0/.github/workflows/publish.yml +79 -0
  5. noaa_gml_file_reader-2.0.0/.gitignore +25 -0
  6. noaa_gml_file_reader-2.0.0/CHANGELOG.md +62 -0
  7. noaa_gml_file_reader-2.0.0/CITATION.cff +22 -0
  8. noaa_gml_file_reader-2.0.0/LICENSE +21 -0
  9. noaa_gml_file_reader-2.0.0/PKG-INFO +137 -0
  10. noaa_gml_file_reader-2.0.0/README.md +113 -0
  11. noaa_gml_file_reader-2.0.0/docs/design/2026-07-07-gml-reader-v2.md +159 -0
  12. noaa_gml_file_reader-2.0.0/docs/format-notes.md +129 -0
  13. noaa_gml_file_reader-2.0.0/docs/plans/2026-07-07-repo-improvement-plan.md +172 -0
  14. noaa_gml_file_reader-2.0.0/docs/release-checklist.md +73 -0
  15. noaa_gml_file_reader-2.0.0/noaa_gml_file_reader/__init__.py +16 -0
  16. noaa_gml_file_reader-2.0.0/noaa_gml_file_reader/_reader.py +138 -0
  17. noaa_gml_file_reader-2.0.0/pyproject.toml +46 -0
  18. noaa_gml_file_reader-2.0.0/tests/fixtures/README.md +32 -0
  19. noaa_gml_file_reader-2.0.0/tests/fixtures/ch4_mlo_surface-flask_1_ccgg_event.txt +169 -0
  20. noaa_gml_file_reader-2.0.0/tests/fixtures/ch4_mlo_surface-flask_1_ccgg_month.txt +74 -0
  21. noaa_gml_file_reader-2.0.0/tests/fixtures/co2_mlo_surface-flask_1_ccgg_event.txt +169 -0
  22. noaa_gml_file_reader-2.0.0/tests/fixtures/co2_mlo_surface-flask_1_ccgg_month.txt +74 -0
  23. noaa_gml_file_reader-2.0.0/tests/fixtures/co2_mlo_surface-insitu_1_ccgg_HourlyData.txt +185 -0
  24. noaa_gml_file_reader-2.0.0/tests/test_reader.py +146 -0
@@ -0,0 +1,2 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
@@ -0,0 +1,16 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: [ErickShepherd] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4
+ patreon: ErickShepherd # Replace with a single Patreon username
5
+ open_collective: # Replace with a single Open Collective username
6
+ ko_fi: # Replace with a single Ko-fi username
7
+ tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8
+ community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9
+ liberapay: # Replace with a single Liberapay username
10
+ issuehunt: # Replace with a single IssueHunt username
11
+ otechie: # Replace with a single Otechie username
12
+ <<<<<<< HEAD
13
+ custom: ['paypal.me/ErickEShepherd', 'https://cash.app/$ErickShepherd', 'https://venmo.com/ErickShepherd', 'https://erickshepherd.com/pay/bitcoin/'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
14
+ =======
15
+ custom: ['paypal.me/ErickEShepherd', 'https://cash.app/$ErickShepherd', 'https://erickshepherd.com/pay/bitcoin/'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
16
+ >>>>>>> 8106f864c38116f9cb7259da31f4d22a813686a1
@@ -0,0 +1,57 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ lint:
13
+ name: ruff
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: actions/setup-python@v5
18
+ with:
19
+ python-version: "3.12"
20
+ - name: Install ruff
21
+ run: python -m pip install --upgrade pip ruff
22
+ - name: Ruff check
23
+ run: ruff check .
24
+
25
+ test:
26
+ name: test (py${{ matrix.python-version }})
27
+ runs-on: ubuntu-latest
28
+ strategy:
29
+ fail-fast: false
30
+ matrix:
31
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
32
+ steps:
33
+ - uses: actions/checkout@v4
34
+ - uses: actions/setup-python@v5
35
+ with:
36
+ python-version: ${{ matrix.python-version }}
37
+ - name: Install package + test deps
38
+ run: |
39
+ python -m pip install --upgrade pip
40
+ python -m pip install -e '.[test]'
41
+ - name: Pytest
42
+ run: python -m pytest -q
43
+
44
+ build:
45
+ name: build + twine check
46
+ runs-on: ubuntu-latest
47
+ steps:
48
+ - uses: actions/checkout@v4
49
+ - uses: actions/setup-python@v5
50
+ with:
51
+ python-version: "3.12"
52
+ - name: Install build tooling
53
+ run: python -m pip install --upgrade pip build twine
54
+ - name: Build sdist + wheel
55
+ run: python -m build
56
+ - name: Twine check
57
+ run: twine check dist/*
@@ -0,0 +1,79 @@
1
+ name: Publish to PyPI
2
+
3
+ # Publishes the package via PyPI Trusted Publishing (OIDC) — no API token is
4
+ # stored anywhere (not in the repo, not in GitHub secrets). PyPI verifies the
5
+ # workflow's short-lived OIDC identity instead.
6
+ #
7
+ # Two ways to run:
8
+ # * A published GitHub Release -> builds and publishes to PyPI.
9
+ # * Manual "Run workflow" -> choose testpypi (dry run) or pypi.
10
+ #
11
+ # The publish jobs run in protected GitHub Environments (`pypi` / `testpypi`).
12
+ # Add yourself as a required reviewer on each (repo Settings -> Environments)
13
+ # so every upload pauses for your one-click approval before it leaves.
14
+
15
+ on:
16
+ release:
17
+ types: [released] # full releases only — pre-releases never auto-publish
18
+ workflow_dispatch:
19
+ inputs:
20
+ target:
21
+ description: "Where to publish"
22
+ type: choice
23
+ options: [testpypi, pypi]
24
+ default: testpypi
25
+
26
+ permissions:
27
+ contents: read
28
+
29
+ jobs:
30
+ build:
31
+ name: Build sdist + wheel
32
+ runs-on: ubuntu-latest
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+ - uses: actions/setup-python@v5
36
+ with:
37
+ python-version: "3.12"
38
+ - name: Build
39
+ run: |
40
+ python -m pip install --upgrade build twine
41
+ python -m build
42
+ python -m twine check dist/*
43
+ - uses: actions/upload-artifact@v4
44
+ with:
45
+ name: dist
46
+ path: dist/
47
+
48
+ publish-testpypi:
49
+ name: Publish to TestPyPI
50
+ needs: build
51
+ if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
52
+ runs-on: ubuntu-latest
53
+ environment: testpypi
54
+ permissions:
55
+ id-token: write
56
+ steps:
57
+ - uses: actions/download-artifact@v4
58
+ with:
59
+ name: dist
60
+ path: dist/
61
+ - uses: pypa/gh-action-pypi-publish@release/v1
62
+ with:
63
+ repository-url: https://test.pypi.org/legacy/
64
+ skip-existing: true # re-dispatching a dry run for an existing version won't fail
65
+
66
+ publish-pypi:
67
+ name: Publish to PyPI
68
+ needs: build
69
+ if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.target == 'pypi')
70
+ runs-on: ubuntu-latest
71
+ environment: pypi
72
+ permissions:
73
+ id-token: write
74
+ steps:
75
+ - uses: actions/download-artifact@v4
76
+ with:
77
+ name: dist
78
+ path: dist/
79
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,25 @@
1
+ # Byte-compiled / optimized files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Build / packaging artifacts
7
+ build/
8
+ dist/
9
+ *.egg-info/
10
+ *.egg
11
+ .eggs/
12
+ wheels/
13
+
14
+ # Virtual environments
15
+ .venv/
16
+ venv/
17
+ env/
18
+ ENV/
19
+
20
+ # Test / lint / type caches
21
+ .pytest_cache/
22
+ .ruff_cache/
23
+ .mypy_cache/
24
+ .coverage
25
+ htmlcov/
@@ -0,0 +1,62 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
5
+ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [2.0.0] — 2026-07-08
8
+
9
+ Modernization release. **Breaking** — the package is renamed and unparseable
10
+ input now raises instead of returning an empty DataFrame.
11
+
12
+ ### Changed
13
+ - **Renamed** the package: import `noaa_esrl_gmd_file_reader` →
14
+ `noaa_gml_file_reader`, distribution `noaa-gml-file-reader`. NOAA renamed
15
+ ESRL's Global Monitoring Division (GMD) to the Global Monitoring Laboratory
16
+ (GML) in 2020.
17
+ - **`read_data` now auto-detects the header dialect** and parses both the legacy
18
+ `# number_of_header_lines:` format and the current `# header_lines :` format,
19
+ extracting column names correctly for each.
20
+ - Documented missing-value sentinels (`-999.99`, `-999.999`, `nan`) are mapped to
21
+ `NaN` so numeric columns parse numeric.
22
+ - **Relicensed** AGPL-3.0 → MIT.
23
+ - Modern packaging: `pyproject.toml` (hatchling), package split into
24
+ `_reader.py`, full type hints, and updated docstrings.
25
+
26
+ ### Added
27
+ - `UnrecognizedFormatError` (carries the file path and its first line), raised on
28
+ unrecognized, malformed, truncated, or empty input.
29
+ - Offline pytest suite over committed fixtures and a GitHub Actions CI workflow
30
+ (ruff + pytest on Python 3.10–3.13 + `python -m build` + `twine check`).
31
+
32
+ ### Removed
33
+ - The silent empty-DataFrame return on parse failure (v1 behavior) — it made a
34
+ parse failure indistinguishable from an empty file, so v1 failed silently on
35
+ every current NOAA file.
36
+
37
+ ### Fixed
38
+ - Current (post-2020) NOAA GML files now parse instead of returning empty.
39
+ - The inconsistent GPL/AGPL wording in the v1 module docstring (removed; the
40
+ LICENSE file governs).
41
+
42
+ ## [1.0.2] — 2020-04-13
43
+
44
+ ### Changed
45
+ - Linted the module: removed unused imports, added an encoding declaration, and
46
+ removed trailing whitespace.
47
+
48
+ ## [1.0.1] — 2020-03-29
49
+
50
+ ### Changed
51
+ - `read_data` now returns an empty `pandas.DataFrame` (instead of `None`) when it
52
+ fails to read a file.
53
+
54
+ ## [1.0.0] — 2020-03-25
55
+
56
+ ### Added
57
+ - Initial build developed and released.
58
+
59
+ [2.0.0]: https://github.com/ErickShepherd/noaa-gml-file-reader/releases/tag/v2.0.0
60
+ [1.0.2]: https://github.com/ErickShepherd/noaa-gml-file-reader/releases/tag/v1.0.2
61
+ [1.0.1]: https://github.com/ErickShepherd/noaa-gml-file-reader/releases/tag/v1.0.1
62
+ [1.0.0]: https://github.com/ErickShepherd/noaa-gml-file-reader/releases/tag/v1.0.0
@@ -0,0 +1,22 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software, please cite it using these metadata."
3
+ title: "noaa-gml-file-reader"
4
+ abstract: "Read NOAA GML atmospheric trace-gas ASCII data files as pandas DataFrames."
5
+ type: software
6
+ authors:
7
+ - family-names: "Shepherd"
8
+ given-names: "Erick Edward"
9
+ email: "Contact@ErickShepherd.com"
10
+ version: "2.0.0"
11
+ date-released: "2026-07-08"
12
+ license: MIT
13
+ repository-code: "https://github.com/ErickShepherd/noaa-gml-file-reader"
14
+ url: "https://github.com/ErickShepherd/noaa-gml-file-reader"
15
+ keywords:
16
+ - NOAA
17
+ - GML
18
+ - atmospheric
19
+ - trace gases
20
+ - CO2
21
+ - CH4
22
+ - pandas
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020-2026 Erick Edward Shepherd
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,137 @@
1
+ Metadata-Version: 2.4
2
+ Name: noaa-gml-file-reader
3
+ Version: 2.0.0
4
+ Summary: Read NOAA GML atmospheric trace-gas ASCII data files as pandas DataFrames.
5
+ Project-URL: Homepage, https://github.com/ErickShepherd/noaa-gml-file-reader
6
+ Author-email: Erick Edward Shepherd <Contact@ErickShepherd.com>
7
+ Maintainer-email: Erick Edward Shepherd <Contact@ErickShepherd.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: CH4,CO2,GMD,GML,NOAA,atmospheric,pandas,trace gases
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
19
+ Requires-Python: >=3.10
20
+ Requires-Dist: pandas>=2.0
21
+ Provides-Extra: test
22
+ Requires-Dist: pytest; extra == 'test'
23
+ Description-Content-Type: text/markdown
24
+
25
+ # noaa-gml-file-reader
26
+
27
+ [![CI](https://github.com/ErickShepherd/noaa-gml-file-reader/actions/workflows/ci.yml/badge.svg)](https://github.com/ErickShepherd/noaa-gml-file-reader/actions/workflows/ci.yml)
28
+ ![Python](https://img.shields.io/badge/python-3.10%2B-blue)
29
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
30
+
31
+ Read [NOAA GML](https://gml.noaa.gov) atmospheric trace-gas ASCII data files as
32
+ [`pandas.DataFrame`](https://pandas.pydata.org/) objects — one function,
33
+ `read_data(path)`.
34
+
35
+ ## What this reads
36
+
37
+ NOAA's Global Monitoring Laboratory (GML) publishes long-term atmospheric
38
+ trace-gas measurements (CO₂, CH₄, and others) as whitespace-delimited ASCII
39
+ files with a `#`-commented header — surface-flask **event** and **monthly**
40
+ series, in-situ **hourly**/daily series, and more, at
41
+ [gml.noaa.gov/aftp/data/trace_gases](https://gml.noaa.gov/aftp/data/trace_gases/).
42
+ This package turns one of those files into a tidy DataFrame, with the header's
43
+ column names and the documented missing-value sentinels handled for you.
44
+
45
+ > **Lineage (GMD → GML).** NOAA renamed ESRL's Global Monitoring *Division*
46
+ > (GMD) to the Global Monitoring *Laboratory* (GML) in 2020, and the file header
47
+ > format changed with it. This package was originally `noaa_esrl_gmd_file_reader`
48
+ > (2020); v2 renames it to **noaa-gml-file-reader** (import `noaa_gml_file_reader`)
49
+ > and reads the current header format. See the breaking-change note below.
50
+
51
+ ## Install
52
+
53
+ ```bash
54
+ pip install noaa-gml-file-reader
55
+ ```
56
+
57
+ Requires Python ≥ 3.10 and pandas ≥ 2.0. (Not yet on PyPI — install from source:
58
+ `pip install git+https://github.com/ErickShepherd/noaa-gml-file-reader`.)
59
+
60
+ ## Usage
61
+
62
+ ```python
63
+ from noaa_gml_file_reader import read_data
64
+
65
+ df = read_data("co2_mlo_surface-flask_1_ccgg_month.txt")
66
+ print(df.head())
67
+ ```
68
+
69
+ Real output (from the committed test fixture of the above Mauna Loa monthly file):
70
+
71
+ ```
72
+ site year month value
73
+ 0 MLO 1969 8 322.50
74
+ 1 MLO 1969 9 321.36
75
+ 2 MLO 1969 10 320.74
76
+ 3 MLO 1969 11 321.98
77
+ 4 MLO 1969 12 323.78
78
+ ```
79
+
80
+ Columns come straight from the file's header; numeric columns are numeric
81
+ (`value` is `float64`, `year`/`month` are `int64`), and NOAA's missing-value
82
+ sentinels (`-999.99`, `-999.999`, `nan`) are parsed as `NaN`.
83
+
84
+ ## Supported dialects
85
+
86
+ `read_data` auto-detects the header dialect — you don't need to know NOAA's
87
+ format history to read a file:
88
+
89
+ | dialect | header key | column names from | seen in |
90
+ | --- | --- | --- | --- |
91
+ | **current** | `# header_lines : N` | the bare column row that is the last header line | flask **event**, **in-situ** (hourly/daily) |
92
+ | **legacy** (2020) | `# number_of_header_lines: N` | the `# data_fields:` header line | flask **monthly** |
93
+
94
+ Supported products are those catalogued in [`docs/format-notes.md`](docs/format-notes.md)
95
+ (CO₂/CH₄ surface-flask event + monthly, CO₂ in-situ hourly, at MLO). The header
96
+ grammar is site- and gas-agnostic, so other stations/species in the same product
97
+ families parse the same way.
98
+
99
+ ## Errors
100
+
101
+ An unparseable file **raises** `UnrecognizedFormatError` (carrying the path and
102
+ the file's first line) rather than returning data:
103
+
104
+ ```python
105
+ from noaa_gml_file_reader import read_data, UnrecognizedFormatError
106
+
107
+ try:
108
+ df = read_data("not-a-noaa-file.txt")
109
+ except UnrecognizedFormatError as err:
110
+ print(err)
111
+ ```
112
+
113
+ ## v2 breaking changes
114
+
115
+ v2 is a breaking release (hence the major bump):
116
+
117
+ - **Renamed** `noaa_esrl_gmd_file_reader` → `noaa_gml_file_reader`
118
+ (distribution `noaa-gml-file-reader`).
119
+ - **Raises `UnrecognizedFormatError`** on unrecognized/malformed input. v1
120
+ returned an *empty DataFrame* on any parse failure — silently indistinguishable
121
+ from "the file had no data" — which meant v1 failed silently on every current
122
+ (post-2020) NOAA file. If you relied on the empty-DataFrame behavior, catch the
123
+ exception instead.
124
+ - **Relicensed** AGPL-3.0 → MIT.
125
+
126
+ ## Data & citation
127
+
128
+ The data are NOAA GML's, not this package's. Please cite the measurements per
129
+ NOAA GML's guidance — each product directory under
130
+ [gml.noaa.gov/aftp/data/trace_gases](https://gml.noaa.gov/aftp/data/trace_gases/)
131
+ ships a species-specific README with the citation text and data providers (the
132
+ file headers also carry contact and reciprocity information). This library only
133
+ parses the files; it does not download them.
134
+
135
+ ## License
136
+
137
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,113 @@
1
+ # noaa-gml-file-reader
2
+
3
+ [![CI](https://github.com/ErickShepherd/noaa-gml-file-reader/actions/workflows/ci.yml/badge.svg)](https://github.com/ErickShepherd/noaa-gml-file-reader/actions/workflows/ci.yml)
4
+ ![Python](https://img.shields.io/badge/python-3.10%2B-blue)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+
7
+ Read [NOAA GML](https://gml.noaa.gov) atmospheric trace-gas ASCII data files as
8
+ [`pandas.DataFrame`](https://pandas.pydata.org/) objects — one function,
9
+ `read_data(path)`.
10
+
11
+ ## What this reads
12
+
13
+ NOAA's Global Monitoring Laboratory (GML) publishes long-term atmospheric
14
+ trace-gas measurements (CO₂, CH₄, and others) as whitespace-delimited ASCII
15
+ files with a `#`-commented header — surface-flask **event** and **monthly**
16
+ series, in-situ **hourly**/daily series, and more, at
17
+ [gml.noaa.gov/aftp/data/trace_gases](https://gml.noaa.gov/aftp/data/trace_gases/).
18
+ This package turns one of those files into a tidy DataFrame, with the header's
19
+ column names and the documented missing-value sentinels handled for you.
20
+
21
+ > **Lineage (GMD → GML).** NOAA renamed ESRL's Global Monitoring *Division*
22
+ > (GMD) to the Global Monitoring *Laboratory* (GML) in 2020, and the file header
23
+ > format changed with it. This package was originally `noaa_esrl_gmd_file_reader`
24
+ > (2020); v2 renames it to **noaa-gml-file-reader** (import `noaa_gml_file_reader`)
25
+ > and reads the current header format. See the breaking-change note below.
26
+
27
+ ## Install
28
+
29
+ ```bash
30
+ pip install noaa-gml-file-reader
31
+ ```
32
+
33
+ Requires Python ≥ 3.10 and pandas ≥ 2.0. (Not yet on PyPI — install from source:
34
+ `pip install git+https://github.com/ErickShepherd/noaa-gml-file-reader`.)
35
+
36
+ ## Usage
37
+
38
+ ```python
39
+ from noaa_gml_file_reader import read_data
40
+
41
+ df = read_data("co2_mlo_surface-flask_1_ccgg_month.txt")
42
+ print(df.head())
43
+ ```
44
+
45
+ Real output (from the committed test fixture of the above Mauna Loa monthly file):
46
+
47
+ ```
48
+ site year month value
49
+ 0 MLO 1969 8 322.50
50
+ 1 MLO 1969 9 321.36
51
+ 2 MLO 1969 10 320.74
52
+ 3 MLO 1969 11 321.98
53
+ 4 MLO 1969 12 323.78
54
+ ```
55
+
56
+ Columns come straight from the file's header; numeric columns are numeric
57
+ (`value` is `float64`, `year`/`month` are `int64`), and NOAA's missing-value
58
+ sentinels (`-999.99`, `-999.999`, `nan`) are parsed as `NaN`.
59
+
60
+ ## Supported dialects
61
+
62
+ `read_data` auto-detects the header dialect — you don't need to know NOAA's
63
+ format history to read a file:
64
+
65
+ | dialect | header key | column names from | seen in |
66
+ | --- | --- | --- | --- |
67
+ | **current** | `# header_lines : N` | the bare column row that is the last header line | flask **event**, **in-situ** (hourly/daily) |
68
+ | **legacy** (2020) | `# number_of_header_lines: N` | the `# data_fields:` header line | flask **monthly** |
69
+
70
+ Supported products are those catalogued in [`docs/format-notes.md`](docs/format-notes.md)
71
+ (CO₂/CH₄ surface-flask event + monthly, CO₂ in-situ hourly, at MLO). The header
72
+ grammar is site- and gas-agnostic, so other stations/species in the same product
73
+ families parse the same way.
74
+
75
+ ## Errors
76
+
77
+ An unparseable file **raises** `UnrecognizedFormatError` (carrying the path and
78
+ the file's first line) rather than returning data:
79
+
80
+ ```python
81
+ from noaa_gml_file_reader import read_data, UnrecognizedFormatError
82
+
83
+ try:
84
+ df = read_data("not-a-noaa-file.txt")
85
+ except UnrecognizedFormatError as err:
86
+ print(err)
87
+ ```
88
+
89
+ ## v2 breaking changes
90
+
91
+ v2 is a breaking release (hence the major bump):
92
+
93
+ - **Renamed** `noaa_esrl_gmd_file_reader` → `noaa_gml_file_reader`
94
+ (distribution `noaa-gml-file-reader`).
95
+ - **Raises `UnrecognizedFormatError`** on unrecognized/malformed input. v1
96
+ returned an *empty DataFrame* on any parse failure — silently indistinguishable
97
+ from "the file had no data" — which meant v1 failed silently on every current
98
+ (post-2020) NOAA file. If you relied on the empty-DataFrame behavior, catch the
99
+ exception instead.
100
+ - **Relicensed** AGPL-3.0 → MIT.
101
+
102
+ ## Data & citation
103
+
104
+ The data are NOAA GML's, not this package's. Please cite the measurements per
105
+ NOAA GML's guidance — each product directory under
106
+ [gml.noaa.gov/aftp/data/trace_gases](https://gml.noaa.gov/aftp/data/trace_gases/)
107
+ ships a species-specific README with the citation text and data providers (the
108
+ file headers also carry contact and reciprocity information). This library only
109
+ parses the files; it does not download them.
110
+
111
+ ## License
112
+
113
+ MIT — see [LICENSE](LICENSE).