reflet 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.
Files changed (50) hide show
  1. reflet-0.1.0/.github/workflows/ci.yml +57 -0
  2. reflet-0.1.0/.github/workflows/publish.yml +41 -0
  3. reflet-0.1.0/.gitignore +9 -0
  4. reflet-0.1.0/CHANGELOG.md +47 -0
  5. reflet-0.1.0/LICENSE +28 -0
  6. reflet-0.1.0/PKG-INFO +656 -0
  7. reflet-0.1.0/README.md +634 -0
  8. reflet-0.1.0/examples/clients.csv +5 -0
  9. reflet-0.1.0/examples/config.json +10 -0
  10. reflet-0.1.0/examples/declarative_pipeline.json +9 -0
  11. reflet-0.1.0/examples/declarative_pipeline.py +27 -0
  12. reflet-0.1.0/examples/example_pipeline.py +64 -0
  13. reflet-0.1.0/examples/insert_delete.py +64 -0
  14. reflet-0.1.0/examples/join_example.py +44 -0
  15. reflet-0.1.0/examples/orders.csv +4 -0
  16. reflet-0.1.0/examples/provenance_and_validation.py +50 -0
  17. reflet-0.1.0/examples/sources_example.py +68 -0
  18. reflet-0.1.0/examples/watch_example.py +42 -0
  19. reflet-0.1.0/pyproject.toml +45 -0
  20. reflet-0.1.0/src/reflet/__init__.py +36 -0
  21. reflet-0.1.0/src/reflet/__main__.py +3 -0
  22. reflet-0.1.0/src/reflet/cli.py +67 -0
  23. reflet-0.1.0/src/reflet/declarative.py +133 -0
  24. reflet-0.1.0/src/reflet/errors.py +72 -0
  25. reflet-0.1.0/src/reflet/lens.py +113 -0
  26. reflet-0.1.0/src/reflet/lenses.py +432 -0
  27. reflet-0.1.0/src/reflet/pipeline.py +218 -0
  28. reflet-0.1.0/src/reflet/provenance.py +30 -0
  29. reflet-0.1.0/src/reflet/py.typed +0 -0
  30. reflet-0.1.0/src/reflet/sources/__init__.py +88 -0
  31. reflet-0.1.0/src/reflet/sources/csv_source.py +55 -0
  32. reflet-0.1.0/src/reflet/sources/json_path_source.py +93 -0
  33. reflet-0.1.0/src/reflet/sources/json_source.py +56 -0
  34. reflet-0.1.0/src/reflet/sources/sqlite_source.py +83 -0
  35. reflet-0.1.0/src/reflet/view.py +509 -0
  36. reflet-0.1.0/tests/conftest.py +35 -0
  37. reflet-0.1.0/tests/test_cli.py +39 -0
  38. reflet-0.1.0/tests/test_declarative.py +118 -0
  39. reflet-0.1.0/tests/test_diff_sync.py +119 -0
  40. reflet-0.1.0/tests/test_differentiators.py +166 -0
  41. reflet-0.1.0/tests/test_join.py +64 -0
  42. reflet-0.1.0/tests/test_lens_laws.py +130 -0
  43. reflet-0.1.0/tests/test_lenses.py +82 -0
  44. reflet-0.1.0/tests/test_new_sources.py +81 -0
  45. reflet-0.1.0/tests/test_pipeline.py +50 -0
  46. reflet-0.1.0/tests/test_restructure_lenses.py +96 -0
  47. reflet-0.1.0/tests/test_sources.py +56 -0
  48. reflet-0.1.0/tests/test_stable_key.py +62 -0
  49. reflet-0.1.0/tests/test_view_provenance.py +65 -0
  50. reflet-0.1.0/tests/test_watch.py +43 -0
@@ -0,0 +1,57 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_call: # lets publish.yml reuse this as its pre-release gate
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Set up Python ${{ matrix.python-version }}
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+
25
+ - name: Install reflet with dev dependencies
26
+ run: pip install -e ".[dev]"
27
+
28
+ - name: Lint (ruff)
29
+ run: ruff check .
30
+
31
+ - name: Type-check (mypy --strict)
32
+ run: mypy src
33
+
34
+ - name: Test (pytest)
35
+ run: pytest -q
36
+
37
+ build:
38
+ runs-on: ubuntu-latest
39
+ needs: test
40
+ steps:
41
+ - uses: actions/checkout@v4
42
+
43
+ - name: Set up Python
44
+ uses: actions/setup-python@v5
45
+ with:
46
+ python-version: "3.12"
47
+
48
+ - name: Build sdist and wheel
49
+ run: |
50
+ pip install build
51
+ python -m build
52
+
53
+ - name: Upload build artifacts
54
+ uses: actions/upload-artifact@v4
55
+ with:
56
+ name: dist
57
+ path: dist/
@@ -0,0 +1,41 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ test:
9
+ uses: ./.github/workflows/ci.yml
10
+
11
+ publish:
12
+ runs-on: ubuntu-latest
13
+ needs: test
14
+ environment: pypi
15
+ permissions:
16
+ id-token: write # required for PyPI trusted publishing (OIDC) — no API token needed
17
+
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - name: Set up Python
22
+ uses: actions/setup-python@v5
23
+ with:
24
+ python-version: "3.12"
25
+
26
+ - name: Check release tag matches pyproject.toml version
27
+ run: |
28
+ tag="${GITHUB_REF_NAME#v}"
29
+ version=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
30
+ if [ "$tag" != "$version" ]; then
31
+ echo "Release tag v$tag does not match pyproject.toml version $version"
32
+ exit 1
33
+ fi
34
+
35
+ - name: Build sdist and wheel
36
+ run: |
37
+ pip install build
38
+ python -m build
39
+
40
+ - name: Publish to PyPI
41
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,9 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+ .mypy_cache/
8
+ .ruff_cache/
9
+ .pytest_cache/
@@ -0,0 +1,47 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are 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-11-01
11
+
12
+ Initial public release.
13
+
14
+ ### Added
15
+
16
+ - Core bidirectional lens engine: `Lens.get`/`put`, composition via `>>`,
17
+ `Pipeline`, `View`, `Row` with attribute access, and per-cell `Provenance`
18
+ exposed through `.why()`.
19
+ - Lenses: `rename`, `select`, `filter` (with `defaults=` for `insert()`),
20
+ `map`, `cast`, `split`, `merge`, `constant`, `compute`, `aggregate` (with
21
+ `ConflictPolicy`), `sort`, and `join` (inner join against another
22
+ pipeline; right-hand fields read-only).
23
+ - Sources: CSV, JSON (flat or nested via `rows_at=`), and SQLite
24
+ (`table=`), each with read and atomic write-back, and an optional
25
+ stable `key=` for row identity.
26
+ - `View.diff()` and `sync(dry_run=True)` to preview pending changes before
27
+ writing.
28
+ - `SourceConflictError`: `sync()` detects if the source file changed on
29
+ disk since it was read, and refuses unless `force=True`.
30
+ - `View.undo()`/`redo()` and `View.journal` for edit history and audit.
31
+ - `Pipeline.validate()`: field-level constraints checked at edit time,
32
+ with the field's provenance in the error message.
33
+ - `View.why_not(rid)` and `View.impact(rid, field)` for tracing why a row
34
+ is absent from a view, and what a source cell produced.
35
+ - `View.insert()`/`delete()` with `on_delete` policies (`delete`,
36
+ `tombstone`, `ignore`).
37
+ - `View.watch()`: a polling loop that auto-syncs pending edits and flags
38
+ external source changes via a callback.
39
+ - `reflet.declarative`: build a `Pipeline` from a JSON spec, for the
40
+ lenses that don't need arbitrary Python.
41
+ - CLI: `python -m reflet show|why`, accepting either a `.py` script or a
42
+ declarative `.json` spec.
43
+ - Zero runtime dependencies; typed, `mypy --strict` clean; tested on
44
+ Python 3.10–3.13.
45
+
46
+ [Unreleased]: https://github.com/r-seize/reflet/compare/v0.1.0...HEAD
47
+ [0.1.0]: https://github.com/r-seize/reflet/releases/tag/v0.1.0
reflet-0.1.0/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, r-seize
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.