tomlrt 0.1.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.
- tomlrt-0.1.0/.github/copilot-instructions.md +131 -0
- tomlrt-0.1.0/.github/workflows/ci.yml +68 -0
- tomlrt-0.1.0/.github/workflows/publish.yml +78 -0
- tomlrt-0.1.0/.gitignore +14 -0
- tomlrt-0.1.0/.python-version +1 -0
- tomlrt-0.1.0/CHANGELOG.md +15 -0
- tomlrt-0.1.0/LICENSE +21 -0
- tomlrt-0.1.0/PKG-INFO +62 -0
- tomlrt-0.1.0/README.md +42 -0
- tomlrt-0.1.0/pyproject.toml +111 -0
- tomlrt-0.1.0/renovate.json +9 -0
- tomlrt-0.1.0/src/tomlrt/__init__.py +23 -0
- tomlrt-0.1.0/src/tomlrt/_document.py +2453 -0
- tomlrt-0.1.0/src/tomlrt/_errors.py +25 -0
- tomlrt-0.1.0/src/tomlrt/_nodes.py +423 -0
- tomlrt-0.1.0/src/tomlrt/_parser.py +1304 -0
- tomlrt-0.1.0/src/tomlrt/_public.py +63 -0
- tomlrt-0.1.0/src/tomlrt/_synthesise.py +246 -0
- tomlrt-0.1.0/src/tomlrt/py.typed +0 -0
- tomlrt-0.1.0/tests/test_basic.py +296 -0
- tomlrt-0.1.0/tests/test_comments.py +688 -0
- tomlrt-0.1.0/tests/test_compliance.py +191 -0
- tomlrt-0.1.0/tests/test_edit_golden.py +539 -0
- tomlrt-0.1.0/tests/test_hypothesis.py +159 -0
- tomlrt-0.1.0/tests/test_mutation.py +324 -0
- tomlrt-0.1.0/tests/test_spacing.py +287 -0
- tomlrt-0.1.0/tests/test_synthesise_and_io.py +260 -0
- tomlrt-0.1.0/tests/test_toml11.py +214 -0
- tomlrt-0.1.0/uv.lock +485 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Instructions for AI coding agents
|
|
2
|
+
|
|
3
|
+
This file is read by GitHub Copilot, Copilot CLI, and similar agents
|
|
4
|
+
when they work in this repository. Humans are welcome to read it too —
|
|
5
|
+
it doubles as a high-signal contributor guide.
|
|
6
|
+
|
|
7
|
+
## What this project is
|
|
8
|
+
|
|
9
|
+
`tomlrt` is a **pure-Python, format-preserving** TOML parser and
|
|
10
|
+
writer. The non-negotiable invariant is:
|
|
11
|
+
|
|
12
|
+
> Parsing a document and dumping it again, with no mutations in
|
|
13
|
+
> between, must return the **exact same bytes** — including comments,
|
|
14
|
+
> whitespace, string style (literal vs basic, single vs multiline),
|
|
15
|
+
> number formatting, and line endings (LF vs CRLF).
|
|
16
|
+
|
|
17
|
+
If a change you are about to make could break that, stop and rethink.
|
|
18
|
+
|
|
19
|
+
## Toolchain
|
|
20
|
+
|
|
21
|
+
- **`uv`** is the only supported package/dependency manager. Do not
|
|
22
|
+
introduce `pip`, `poetry`, `pipenv`, `tox`, `nox`, `setuptools`, or
|
|
23
|
+
`requirements.txt`.
|
|
24
|
+
- Build backend is **`hatchling`**.
|
|
25
|
+
- Supported Python versions: **3.10 – 3.14**.
|
|
26
|
+
|
|
27
|
+
## Common commands
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
uv sync # install dev deps
|
|
31
|
+
uv run pytest -q # run the test suite (~1s)
|
|
32
|
+
uv run pytest --cov # tests + branch coverage
|
|
33
|
+
uv run mypy # strict type-check src/ and tests/
|
|
34
|
+
uv run ruff check . # lint
|
|
35
|
+
uv run ruff format . # apply formatting
|
|
36
|
+
uv run ruff format --check . # CI-style format check
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
All four checks (`pytest`, `mypy`, `ruff check`, `ruff format --check`)
|
|
40
|
+
must pass before any commit. CI runs the same set on Python 3.10–3.14.
|
|
41
|
+
|
|
42
|
+
## Coding standards
|
|
43
|
+
|
|
44
|
+
- **`mypy --strict`** clean — no `# type: ignore` without a specific
|
|
45
|
+
error code, and ideally no ignores at all. Prefer fixing the type.
|
|
46
|
+
- **`ruff` with `select = ["ALL"]`** clean — see `[tool.ruff.lint.ignore]`
|
|
47
|
+
in `pyproject.toml` for the curated exceptions. Do not add new
|
|
48
|
+
per-line `# noqa` without a strong reason.
|
|
49
|
+
- **`ruff format`** is the source of truth for formatting. Run it
|
|
50
|
+
before committing.
|
|
51
|
+
- **No runtime dependencies.** The project is and will remain pure
|
|
52
|
+
stdlib. Only `dependency-groups.dev` may grow, and only with care.
|
|
53
|
+
- **No `cast()` in user-facing code paths.** Tests should not need
|
|
54
|
+
`cast()` either; the typed accessors `Table.array(k)`,
|
|
55
|
+
`Table.table(k)`, `Table.aot(k)`, `Array.array(i)`, `Array.table(i)`
|
|
56
|
+
exist precisely to avoid this.
|
|
57
|
+
- **`from __future__ import annotations`** at the top of every module
|
|
58
|
+
(enforced by ruff's isort `required-imports`).
|
|
59
|
+
- Do not add comments that merely restate the code. Comment intent and
|
|
60
|
+
invariants, not mechanics.
|
|
61
|
+
|
|
62
|
+
## Architecture (in `src/tomlrt/`)
|
|
63
|
+
|
|
64
|
+
The codebase is small and deliberately layered. Read in this order:
|
|
65
|
+
|
|
66
|
+
- **`_nodes.py`** — the **concrete syntax tree (CST)**: dataclasses
|
|
67
|
+
that hold every byte of the original source (including trivia,
|
|
68
|
+
comments, and the literal lexeme of every value). Mutate these only
|
|
69
|
+
through helpers that maintain the round-trip invariant.
|
|
70
|
+
- **`_parser.py`** — hand-written recursive-descent parser, TOML 1.0 +
|
|
71
|
+
1.1, that produces the CST. Performance-sensitive: prefer bulk
|
|
72
|
+
`str` scans over per-character loops.
|
|
73
|
+
- **`_synthesise.py`** — converts plain Python values (`str`, `int`,
|
|
74
|
+
`bool`, `datetime`, `list`, `dict`, …) into newly synthesised CST
|
|
75
|
+
nodes when the user assigns into the document.
|
|
76
|
+
- **`_document.py`** — the **logical view layer**: `Document`, `Table`,
|
|
77
|
+
`Array`, `AoT` wrappers that present a dict/list-shaped API while
|
|
78
|
+
delegating all mutation to the CST. The Comment API and typed
|
|
79
|
+
accessors live here. This is by far the largest file.
|
|
80
|
+
- **`_public.py`** — the top-level `parse` / `loads` / `load` /
|
|
81
|
+
`dumps` / `dump` functions. `load` and `dump` require **binary**
|
|
82
|
+
file objects (`IO[bytes]`); text mode would silently translate
|
|
83
|
+
newlines on Windows and break round-tripping.
|
|
84
|
+
- **`_errors.py`** — public exception hierarchy.
|
|
85
|
+
- **`__init__.py`** — re-exports the public API; keep `__all__`
|
|
86
|
+
alphabetised.
|
|
87
|
+
|
|
88
|
+
When in doubt: a change that touches only one of these layers is
|
|
89
|
+
usually right; a change that has to touch all of them is usually wrong.
|
|
90
|
+
|
|
91
|
+
## Tests
|
|
92
|
+
|
|
93
|
+
- `tests/test_basic.py`, `test_spacing.py`, `test_edit_golden.py` —
|
|
94
|
+
parser and writer regressions, including byte-exact round-trip
|
|
95
|
+
fixtures.
|
|
96
|
+
- `tests/test_comments.py` — the comment manipulation API.
|
|
97
|
+
- `tests/test_compliance.py` — the official **`toml-test`** suite
|
|
98
|
+
(vendored under `vendor/`). Do not edit fixtures there to make
|
|
99
|
+
failures pass.
|
|
100
|
+
- `tests/test_toml11.py` — TOML 1.1-specific coverage.
|
|
101
|
+
- `tests/test_hypothesis.py` — property-based round-trip tests. If you
|
|
102
|
+
break round-tripping, this will usually catch it; add new strategies
|
|
103
|
+
here when you add a new construct.
|
|
104
|
+
- `tests/test_mutation.py` — the dict/list mutation API.
|
|
105
|
+
- `tests/test_synthesise_and_io.py` — value synthesis and binary I/O.
|
|
106
|
+
|
|
107
|
+
When adding behaviour, add a focused unit test in the relevant file
|
|
108
|
+
**and** consider whether the property tests should grow.
|
|
109
|
+
|
|
110
|
+
## Things to avoid
|
|
111
|
+
|
|
112
|
+
- Adding a runtime dependency.
|
|
113
|
+
- Reaching into `_nodes` from user-facing code instead of going through
|
|
114
|
+
`_document`.
|
|
115
|
+
- "Fixing" formatting differences in the writer's output without
|
|
116
|
+
adding a round-trip test that proves it.
|
|
117
|
+
- Touching `vendor/` (it is third-party, vendored verbatim).
|
|
118
|
+
- Editing `uv.lock` by hand — let `uv` regenerate it.
|
|
119
|
+
- Bumping action versions in `.github/workflows/*.yml` to a tag instead
|
|
120
|
+
of a 40-char commit SHA. The workflows are **`zizmor` clean** and
|
|
121
|
+
must stay that way (`uv tool run zizmor .`).
|
|
122
|
+
|
|
123
|
+
## Commit conventions
|
|
124
|
+
|
|
125
|
+
- Subject line: imperative mood, ≤ ~70 chars, no trailing period.
|
|
126
|
+
- Body: wrap around 72 chars; explain *why* not *what*. Bullets are
|
|
127
|
+
fine.
|
|
128
|
+
- One logical change per commit. Keep mechanical reformat passes
|
|
129
|
+
separate from substantive changes.
|
|
130
|
+
- Append a `Co-authored-by` trailer when an AI agent did the work, e.g.
|
|
131
|
+
`Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>`.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
permissions: {}
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
name: test (py${{ matrix.python-version }} on ${{ matrix.os }})
|
|
14
|
+
runs-on: ${{ matrix.os }}
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
strategy:
|
|
18
|
+
fail-fast: false
|
|
19
|
+
matrix:
|
|
20
|
+
os:
|
|
21
|
+
- ubuntu-latest
|
|
22
|
+
python-version:
|
|
23
|
+
- "3.10"
|
|
24
|
+
- "3.11"
|
|
25
|
+
- "3.12"
|
|
26
|
+
- "3.13"
|
|
27
|
+
- "3.14"
|
|
28
|
+
- "3.15"
|
|
29
|
+
include:
|
|
30
|
+
- os: macos-latest
|
|
31
|
+
python-version: "3.14"
|
|
32
|
+
- os: windows-latest
|
|
33
|
+
python-version: "3.14"
|
|
34
|
+
steps:
|
|
35
|
+
- name: Check out repository
|
|
36
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
37
|
+
with:
|
|
38
|
+
persist-credentials: false
|
|
39
|
+
|
|
40
|
+
- name: Set up python {{ matrix.python-version }}
|
|
41
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
42
|
+
with:
|
|
43
|
+
python-version: ${{ matrix.python-version }}
|
|
44
|
+
allow-prereleases: true
|
|
45
|
+
|
|
46
|
+
- name: Install uv
|
|
47
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
48
|
+
|
|
49
|
+
- name: Check lockfile
|
|
50
|
+
run: uv lock --check
|
|
51
|
+
|
|
52
|
+
- name: Install project
|
|
53
|
+
run: uv sync -p ${{ matrix.python-version }}
|
|
54
|
+
|
|
55
|
+
- name: Install ruff
|
|
56
|
+
uses: astral-sh/ruff-action@0ce1b0bf8b818ef400413f810f8a11cdbda0034b # v4.0.0
|
|
57
|
+
|
|
58
|
+
- name: ruff check
|
|
59
|
+
run: ruff check .
|
|
60
|
+
|
|
61
|
+
- name: ruff format
|
|
62
|
+
run: ruff format --check .
|
|
63
|
+
|
|
64
|
+
- name: pytest
|
|
65
|
+
run: uv run pytest
|
|
66
|
+
|
|
67
|
+
- name: mypy
|
|
68
|
+
run: uv run mypy
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
pull_request:
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions: {}
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
build:
|
|
16
|
+
name: Build distribution
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
22
|
+
with:
|
|
23
|
+
persist-credentials: false
|
|
24
|
+
|
|
25
|
+
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
26
|
+
with:
|
|
27
|
+
python-version: "3.14"
|
|
28
|
+
|
|
29
|
+
- name: Install uv
|
|
30
|
+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
|
|
31
|
+
with:
|
|
32
|
+
enable-cache: false
|
|
33
|
+
|
|
34
|
+
- name: Check tag matches pyproject version
|
|
35
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
36
|
+
env:
|
|
37
|
+
REF_NAME: ${{ github.ref_name }}
|
|
38
|
+
run: |
|
|
39
|
+
TAG_VERSION="${REF_NAME#v}"
|
|
40
|
+
PROJECT_VERSION=$(python -c '
|
|
41
|
+
import tomllib
|
|
42
|
+
with open("pyproject.toml", "rb") as f:
|
|
43
|
+
print(tomllib.load(f)["project"]["version"])
|
|
44
|
+
')
|
|
45
|
+
if [ "$TAG_VERSION" != "$PROJECT_VERSION" ]; then
|
|
46
|
+
echo "Tag $REF_NAME (version $TAG_VERSION) does not match pyproject version $PROJECT_VERSION" >&2
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
- name: Build sdist and wheel
|
|
51
|
+
run: uv build
|
|
52
|
+
|
|
53
|
+
- name: Upload distributions
|
|
54
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
55
|
+
with:
|
|
56
|
+
name: dist
|
|
57
|
+
path: dist/
|
|
58
|
+
|
|
59
|
+
publish:
|
|
60
|
+
name: Publish to PyPI
|
|
61
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
62
|
+
needs: build
|
|
63
|
+
runs-on: ubuntu-latest
|
|
64
|
+
environment:
|
|
65
|
+
name: pypi
|
|
66
|
+
url: https://pypi.org/p/tomlrt
|
|
67
|
+
permissions:
|
|
68
|
+
id-token: write
|
|
69
|
+
steps:
|
|
70
|
+
- name: Download distributions
|
|
71
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
72
|
+
with:
|
|
73
|
+
path: dist
|
|
74
|
+
|
|
75
|
+
- name: Publish package distributions to PyPI
|
|
76
|
+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
|
|
77
|
+
with:
|
|
78
|
+
packages-dir: dist/
|
tomlrt-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.14
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-04-20
|
|
11
|
+
|
|
12
|
+
Initial release.
|
|
13
|
+
|
|
14
|
+
[Unreleased]: https://github.com/dimbleby/tomlrt/compare/v0.1.0...HEAD
|
|
15
|
+
[0.1.0]: https://github.com/dimbleby/tomlrt/releases/tag/v0.1.0
|
tomlrt-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 tomlrt contributors
|
|
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.
|
tomlrt-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tomlrt
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A format-preserving TOML parser and writer for Python.
|
|
5
|
+
Project-URL: Repository, https://github.com/dimbleby/tomlrt
|
|
6
|
+
Project-URL: Issues, https://github.com/dimbleby/tomlrt/issues
|
|
7
|
+
Project-URL: Changelog, https://github.com/dimbleby/tomlrt/blob/main/CHANGELOG.md
|
|
8
|
+
Author-email: David Hotham <david.hotham@blueyonder.co.uk>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: config,configuration,format-preserving,pyproject,round-trip,toml,toml-parser,toml-writer,tomlrt
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Typing :: Typed
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Requires-Dist: typing-extensions>=4; python_version < '3.12'
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# tomlrt
|
|
22
|
+
|
|
23
|
+
[](https://pypi.org/project/tomlrt/)
|
|
24
|
+
[](https://pypi.org/project/tomlrt/)
|
|
25
|
+
[](https://github.com/dimbleby/tomlrt/blob/main/LICENSE)
|
|
26
|
+
[](https://github.com/dimbleby/tomlrt/actions/workflows/ci.yml)
|
|
27
|
+
|
|
28
|
+
A format-preserving TOML parser and writer for Python.
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import tomlrt
|
|
34
|
+
|
|
35
|
+
# Files must be opened in binary mode.
|
|
36
|
+
with open("pyproject.toml", "rb") as f:
|
|
37
|
+
doc = tomlrt.load(f)
|
|
38
|
+
|
|
39
|
+
doc["project"]["version"] = "0.2.0"
|
|
40
|
+
doc["project"]["dependencies"].append("requests>=2")
|
|
41
|
+
|
|
42
|
+
print(tomlrt.dumps(doc)) # comments and layout are preserved
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Comment API
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
doc = tomlrt.loads("""
|
|
49
|
+
[server]
|
|
50
|
+
host = "localhost" # default
|
|
51
|
+
port = 8080
|
|
52
|
+
""")
|
|
53
|
+
|
|
54
|
+
server = doc.table("server")
|
|
55
|
+
server.comments["port"] = "override with $PORT"
|
|
56
|
+
server.comments["host"] = None # clear
|
|
57
|
+
|
|
58
|
+
print(tomlrt.dumps(doc))
|
|
59
|
+
# [server]
|
|
60
|
+
# host = "localhost"
|
|
61
|
+
# port = 8080 # override with $PORT
|
|
62
|
+
```
|
tomlrt-0.1.0/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# tomlrt
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/tomlrt/)
|
|
4
|
+
[](https://pypi.org/project/tomlrt/)
|
|
5
|
+
[](https://github.com/dimbleby/tomlrt/blob/main/LICENSE)
|
|
6
|
+
[](https://github.com/dimbleby/tomlrt/actions/workflows/ci.yml)
|
|
7
|
+
|
|
8
|
+
A format-preserving TOML parser and writer for Python.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
import tomlrt
|
|
14
|
+
|
|
15
|
+
# Files must be opened in binary mode.
|
|
16
|
+
with open("pyproject.toml", "rb") as f:
|
|
17
|
+
doc = tomlrt.load(f)
|
|
18
|
+
|
|
19
|
+
doc["project"]["version"] = "0.2.0"
|
|
20
|
+
doc["project"]["dependencies"].append("requests>=2")
|
|
21
|
+
|
|
22
|
+
print(tomlrt.dumps(doc)) # comments and layout are preserved
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Comment API
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
doc = tomlrt.loads("""
|
|
29
|
+
[server]
|
|
30
|
+
host = "localhost" # default
|
|
31
|
+
port = 8080
|
|
32
|
+
""")
|
|
33
|
+
|
|
34
|
+
server = doc.table("server")
|
|
35
|
+
server.comments["port"] = "override with $PORT"
|
|
36
|
+
server.comments["host"] = None # clear
|
|
37
|
+
|
|
38
|
+
print(tomlrt.dumps(doc))
|
|
39
|
+
# [server]
|
|
40
|
+
# host = "localhost"
|
|
41
|
+
# port = 8080 # override with $PORT
|
|
42
|
+
```
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tomlrt"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A format-preserving TOML parser and writer for Python."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
authors = [{ name = "David Hotham", email = "david.hotham@blueyonder.co.uk" }]
|
|
9
|
+
keywords = [
|
|
10
|
+
"toml",
|
|
11
|
+
"toml-parser",
|
|
12
|
+
"toml-writer",
|
|
13
|
+
"tomlrt",
|
|
14
|
+
"format-preserving",
|
|
15
|
+
"round-trip",
|
|
16
|
+
"config",
|
|
17
|
+
"configuration",
|
|
18
|
+
"pyproject",
|
|
19
|
+
]
|
|
20
|
+
dependencies = ["typing_extensions>=4; python_version < '3.12'"]
|
|
21
|
+
classifiers = [
|
|
22
|
+
"Intended Audience :: Developers",
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Operating System :: OS Independent",
|
|
25
|
+
"Programming Language :: Python :: 3",
|
|
26
|
+
"Typing :: Typed",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Repository = "https://github.com/dimbleby/tomlrt"
|
|
31
|
+
Issues = "https://github.com/dimbleby/tomlrt/issues"
|
|
32
|
+
Changelog = "https://github.com/dimbleby/tomlrt/blob/main/CHANGELOG.md"
|
|
33
|
+
|
|
34
|
+
[dependency-groups]
|
|
35
|
+
dev = [
|
|
36
|
+
"pytest>=9",
|
|
37
|
+
"pytest-cov>=5",
|
|
38
|
+
"hypothesis>=6",
|
|
39
|
+
"mypy>=1.11",
|
|
40
|
+
"tomli>=2; python_version < '3.11'",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
[build-system]
|
|
44
|
+
requires = ["hatchling"]
|
|
45
|
+
build-backend = "hatchling.build"
|
|
46
|
+
|
|
47
|
+
[tool.pytest]
|
|
48
|
+
addopts = ["-ra"]
|
|
49
|
+
testpaths = ["tests"]
|
|
50
|
+
strict = true
|
|
51
|
+
|
|
52
|
+
[tool.coverage.run]
|
|
53
|
+
source = ["src/tomlrt"]
|
|
54
|
+
branch = true
|
|
55
|
+
|
|
56
|
+
[tool.coverage.report]
|
|
57
|
+
skip_covered = false
|
|
58
|
+
exclude_also = [
|
|
59
|
+
"if TYPE_CHECKING:",
|
|
60
|
+
"raise NotImplementedError",
|
|
61
|
+
"@overload",
|
|
62
|
+
"pragma: no cover",
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
[tool.mypy]
|
|
66
|
+
files = ["src", "tests"]
|
|
67
|
+
strict = true
|
|
68
|
+
warn_unreachable = true
|
|
69
|
+
disallow_any_unimported = true
|
|
70
|
+
enable_error_code = [
|
|
71
|
+
"deprecated",
|
|
72
|
+
"explicit-override",
|
|
73
|
+
"ignore-without-code",
|
|
74
|
+
"possibly-undefined",
|
|
75
|
+
"redundant-expr",
|
|
76
|
+
"redundant-self",
|
|
77
|
+
"truthy-bool",
|
|
78
|
+
"truthy-iterable",
|
|
79
|
+
"unused-awaitable",
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
[tool.ruff]
|
|
83
|
+
src = ["src", "tests"]
|
|
84
|
+
|
|
85
|
+
[tool.ruff.lint]
|
|
86
|
+
select = ["ALL"]
|
|
87
|
+
ignore = [
|
|
88
|
+
"C90", # mccabe
|
|
89
|
+
"COM", # flake8-commas
|
|
90
|
+
"CPY", # flake8-copyright
|
|
91
|
+
"D", # pydocstyle
|
|
92
|
+
"DOC", # pydoclint
|
|
93
|
+
"ERA", # eradicate
|
|
94
|
+
"PD", # pandas-vet
|
|
95
|
+
"PLR", # pylint-refactor
|
|
96
|
+
"T20", # flake8-print
|
|
97
|
+
"ANN401", # any-type
|
|
98
|
+
"E203", # whitespace before ':'
|
|
99
|
+
"S101", # assert-used
|
|
100
|
+
]
|
|
101
|
+
extend-safe-fixes = ["TC"]
|
|
102
|
+
unfixable = ["F841"]
|
|
103
|
+
|
|
104
|
+
[tool.ruff.lint.flake8-tidy-imports]
|
|
105
|
+
ban-relative-imports = "all"
|
|
106
|
+
|
|
107
|
+
[tool.ruff.lint.flake8-type-checking]
|
|
108
|
+
strict = true
|
|
109
|
+
|
|
110
|
+
[tool.ruff.lint.isort]
|
|
111
|
+
required-imports = ["from __future__ import annotations"]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""tomlrt: a format-preserving TOML parser and writer."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from tomlrt._document import AoT, Array, Document, Table
|
|
6
|
+
from tomlrt._errors import TOMLError, TOMLParseError
|
|
7
|
+
from tomlrt._public import dump, dumps, load, loads, parse
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"AoT",
|
|
11
|
+
"Array",
|
|
12
|
+
"Document",
|
|
13
|
+
"TOMLError",
|
|
14
|
+
"TOMLParseError",
|
|
15
|
+
"Table",
|
|
16
|
+
"dump",
|
|
17
|
+
"dumps",
|
|
18
|
+
"load",
|
|
19
|
+
"loads",
|
|
20
|
+
"parse",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
__version__ = "0.1.0"
|