tidy3syntax 0.1.2__tar.gz → 0.2.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 (33) hide show
  1. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/CHANGELOG.md +14 -0
  2. {tidy3syntax-0.1.2/src/tidy3syntax.egg-info → tidy3syntax-0.2.0}/PKG-INFO +11 -9
  3. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/README.md +10 -8
  4. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/docs/design.md +3 -3
  5. tidy3syntax-0.2.0/src/tidy3syntax/__version__.py +1 -0
  6. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/src/tidy3syntax/dialect.py +9 -5
  7. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/src/tidy3syntax/repairs.py +2 -2
  8. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0/src/tidy3syntax.egg-info}/PKG-INFO +11 -9
  9. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/tests/test_ipython.py +2 -2
  10. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/tests/test_reinterpretations.py +2 -2
  11. tidy3syntax-0.1.2/src/tidy3syntax/__version__.py +0 -1
  12. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/LICENSE +0 -0
  13. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/MANIFEST.in +0 -0
  14. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/pyproject.toml +0 -0
  15. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/setup.cfg +0 -0
  16. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/src/tidy3syntax/__init__.py +0 -0
  17. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/src/tidy3syntax/continuation.py +0 -0
  18. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/src/tidy3syntax/ipython.py +0 -0
  19. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/src/tidy3syntax/ownership.py +0 -0
  20. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/src/tidy3syntax/pipeline.py +0 -0
  21. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/src/tidy3syntax/placeholders.py +0 -0
  22. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/src/tidy3syntax/py.typed +0 -0
  23. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/src/tidy3syntax/scanner.py +0 -0
  24. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/src/tidy3syntax.egg-info/SOURCES.txt +0 -0
  25. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/src/tidy3syntax.egg-info/dependency_links.txt +0 -0
  26. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/src/tidy3syntax.egg-info/requires.txt +0 -0
  27. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/src/tidy3syntax.egg-info/top_level.txt +0 -0
  28. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/tests/dialects.py +0 -0
  29. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/tests/test_continuation.py +0 -0
  30. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/tests/test_integration.py +0 -0
  31. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/tests/test_properties.py +0 -0
  32. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/tests/test_repairs.py +0 -0
  33. {tidy3syntax-0.1.2 → tidy3syntax-0.2.0}/tests/test_scanner.py +0 -0
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.0 — 2026-11-02
4
+
5
+ Phase 7 of [the design](docs/design.md).
6
+
7
+ ### Changed
8
+
9
+ - `Dialect.mask` takes the notebook's imports as a third argument,
10
+ `mask(source, known, context)`, so a package's export masking can tell its
11
+ own calls from another package's; `Dialect.export_imports` lists the lines
12
+ an exported script needs once the mask changed something (`import tidy3a`).
13
+ - A formula being quoted turns only `__r_name__` back into a backtick name;
14
+ tidy3's `__tidy3_bt__` and plot3's `__plot3_bt__`, which no release of
15
+ either writes since tidy3 0.17 and plot3 0.10, are no longer read.
16
+
3
17
  ## 0.1.2 — 2026-11-01
4
18
 
5
19
  Phase 6a of [the design](docs/design.md): continuation lines and the coordinator.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tidy3syntax
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: R syntax in notebook cells, rewritten to Python: shared by tidy3, tidy3a, plot3 and stats3
5
5
  Author: Rigoberto Leyva Salmeron
6
6
  License-Expression: MIT
@@ -115,11 +115,12 @@ the ownership rule and the two reinterpretations, used by tidy3 0.15.1, tidy3a
115
115
  tidy3, `+` for plot3) and the coordinator, in 0.1.2, which tidy3 0.16, tidy3a
116
116
  0.17, plot3 0.9 and stats3 0.7 register with.
117
117
 
118
- Until every package's AST pass reads the neutral placeholders, each package
119
- calls only the repairs whose output the others already read, and tidy3 and
120
- plot3 turn `__r_name__` and `__r_assign__` back into their own names
121
- (`__tidy3_bt__`, `__tidy3_assign__`, `__plot3_bt__`). tidy3a writes
122
- `__r_assign__` and hands it to tidy3 as `__tidy3_assign__` in tidy3's calls.
118
+ Phase 7, in 0.2.0: `__r_name__` and `__r_assign__` are the only
119
+ placeholders any package writes or reads; the packages' own names from before
120
+ (`__tidy3_bt__`, `__plot3_bt__`) are gone. Inside its own calls each
121
+ package's AST pass renames `__r_assign__` to a private name of its own
122
+ (`__tidy3_assign__`, `__tidy3a_assign__`), since the shared name's value in a
123
+ namespace can belong to no single package.
123
124
 
124
125
  Where the output differs from a package's own rewrite before the switch:
125
126
 
@@ -129,9 +130,10 @@ Where the output differs from a package's own rewrite before the switch:
129
130
  (`df.select(a = x, b)`) is rewritten like the verb, as `!` in one already
130
131
  was; backticks inside strings and comments stay; a backtick assignment is
131
132
  rewritten only as a call argument.
132
- - tidy3a: its placeholder is `__r_assign__` (it still reads `__tidy3a_assign__`).
133
- - plot3: a placeholder another package left inside a one-sided facet formula
134
- (`facet_wrap(~__tidy3_bt__('a b'))`) becomes the name again: `'~a b'`.
133
+ - tidy3a: its placeholder is `__r_assign__`.
134
+ - plot3: a backtick name inside a one-sided facet formula that another
135
+ package's rewrite reached first (`facet_wrap(~__r_name__('a b'))`) becomes
136
+ the name again: `'~a b'`.
135
137
 
136
138
  `scripts/family/` runs all five suites together on another machine: `sync.sh`
137
139
  copies the working trees and starts `run.sh` in a tmux session there, and
@@ -95,11 +95,12 @@ the ownership rule and the two reinterpretations, used by tidy3 0.15.1, tidy3a
95
95
  tidy3, `+` for plot3) and the coordinator, in 0.1.2, which tidy3 0.16, tidy3a
96
96
  0.17, plot3 0.9 and stats3 0.7 register with.
97
97
 
98
- Until every package's AST pass reads the neutral placeholders, each package
99
- calls only the repairs whose output the others already read, and tidy3 and
100
- plot3 turn `__r_name__` and `__r_assign__` back into their own names
101
- (`__tidy3_bt__`, `__tidy3_assign__`, `__plot3_bt__`). tidy3a writes
102
- `__r_assign__` and hands it to tidy3 as `__tidy3_assign__` in tidy3's calls.
98
+ Phase 7, in 0.2.0: `__r_name__` and `__r_assign__` are the only
99
+ placeholders any package writes or reads; the packages' own names from before
100
+ (`__tidy3_bt__`, `__plot3_bt__`) are gone. Inside its own calls each
101
+ package's AST pass renames `__r_assign__` to a private name of its own
102
+ (`__tidy3_assign__`, `__tidy3a_assign__`), since the shared name's value in a
103
+ namespace can belong to no single package.
103
104
 
104
105
  Where the output differs from a package's own rewrite before the switch:
105
106
 
@@ -109,9 +110,10 @@ Where the output differs from a package's own rewrite before the switch:
109
110
  (`df.select(a = x, b)`) is rewritten like the verb, as `!` in one already
110
111
  was; backticks inside strings and comments stay; a backtick assignment is
111
112
  rewritten only as a call argument.
112
- - tidy3a: its placeholder is `__r_assign__` (it still reads `__tidy3a_assign__`).
113
- - plot3: a placeholder another package left inside a one-sided facet formula
114
- (`facet_wrap(~__tidy3_bt__('a b'))`) becomes the name again: `'~a b'`.
113
+ - tidy3a: its placeholder is `__r_assign__`.
114
+ - plot3: a backtick name inside a one-sided facet formula that another
115
+ package's rewrite reached first (`facet_wrap(~__r_name__('a b'))`) becomes
116
+ the name again: `'~a b'`.
115
117
 
116
118
  `scripts/family/` runs all five suites together on another machine: `sync.sh`
117
119
  copies the working trees and starts `run.sh` in a tmux session there, and
@@ -1,6 +1,6 @@
1
1
  # A shared package for R syntax in notebooks
2
2
 
3
- Status: accepted 2026-11-01; phases 1 to 5 (§8) implemented and released (tidy3syntax 0.1.1, tidy3 0.15.1, tidy3a 0.16.1, plot3 0.8.1, stats3 0.6.1); phases 6 and 7 to come.
3
+ Status: accepted 2026-11-01; phases 1 to 6 (§8) implemented and released (tidy3syntax 0.1.2, tidy3 0.16.0, tidy3a 0.17.0, plot3 0.9.0, stats3 0.7.0); phase 7 released in tidy3syntax 0.2.0, tidy3 0.17.0, tidy3a 0.18.0, plot3 0.10.0 and stats3 0.8.0.
4
4
 
5
5
  tidy3, tidy3a, plot3 and stats3 each let notebook cells use R syntax that Python
6
6
  cannot parse: bare column names, `` `odd names` ``, `!` for negation, `name =
@@ -409,10 +409,10 @@ tidy3 0.14's backtick pass rewrites backticks inside string literals too. When i
409
409
  6. **Coordinator, continuation lines and ownership in the AST passes.** Install the single transformer and the entry points; move tidy3's `>>` and plot3's `+` continuation lines; let each package's AST pass use the shared `Owners`. Delete tidy3's plot3 hook and plot3 imports from `export.py`. Exit check: the four-package notebook passes in all 24 load orders. In three steps, each released on its own (planned 2026-11-01):
410
410
  - **6a, tidy3syntax only (0.1.2, additive).** Continuation lines: a line starting with `>>` continues the statement above, a repair (tidy3's `_wrap_pipe_statements`, and `join_broken_pipe`, which joins a broken pipe with backslashes so Python names the real error); an indented `+` line is a repair; an unindented `+` line is a reinterpretation, joined only when the call after `+` is owned by the dialect that lists it and the statement above starts with an owned call or ends a pipe whose last step is one. tidy3 today joins a `+` line after any pipe by name, the §1.3 bug for `+`; this replaces it. The coordinator, `tidy3syntax.ipython`: one input transformer for every registered dialect, kept ahead of CRAFT's router before each cell (tidy3's `pre_run_cell` hook does this today), the importing cell (§4.7), and entry points. The integration test: a notebook with the four packages in all 24 load orders, run in this repository's CI on pull requests and weekly.
411
411
  - **6b, each package (one release each).** Register with the coordinator instead of installing a transformer; delete its continuation code, its handling of the other packages' placeholders and hooks (tidy3's plot3 hook and `export.py`'s plot3 imports); write the neutral names; use `Owners` in its AST pass. Packages on 6b and packages not yet on it must still share a notebook: the coordinator leaves a package's own transformer in place until that package registers.
412
- - **6c.** The integration test passes against the four packages' releases.
412
+ - **6c.** The integration test passes against the four packages' releases. *Done 2026-11-01:* tidy3syntax's CI installed tidy3 0.16.0, tidy3a 0.17.0, plot3 0.9.0 and stats3 0.7.0 from PyPI with tidy3syntax 0.1.2, and all 24 load orders passed.
413
413
 
414
414
  Progress (2026-11-02): 6a is committed (continuation lines, the coordinator, the integration test). 6b is done in the four packages' working trees, not released: each registers with the coordinator and declares an entry point; stats3, tidy3a and plot3 read `__r_name__` as a column; each AST pass renames `__r_assign__` to its own private name inside its own calls (`__tidy3_assign__`, `__tidy3a_assign__`), since the shared name's value in the namespace can belong to no single package; plot3's AST pass checks ownership with `Owners`; tidy3a takes `>>` continuation lines; tidy3's `pre_run_cell` hook and plot3 hook are gone, and plot3 no longer looks for tidy3's preparser. tidy3's `nb_export`, partial runs and CRAFT path rewrite through tidy3syntax as well (2026-11-02): an entry point names a function returning the package's dialect, whose `extension` is its notebook loader and whose `mask` applies its AST pass to source text; `tidy3syntax.installed()` lists them, so `export.py` finds plot3 without importing it. tidy3a's and stats3's dialects have no `mask` yet: their AST passes write internal names an export cannot turn into public code, and tidy3's export did not handle them before either. At release, tidy3 should require the plot3 release that has the entry point.
415
- 7. **Drop the old placeholder aliases** two minor releases after phase 2.
415
+ 7. **Drop the old placeholder aliases** two minor releases after phase 2. *Done 2026-11-01, one minor release after phase 2 at the owner's choice, and released 2026-11-02:* the source passes write only `__r_name__` and `__r_assign__`, and no AST pass reads `__tidy3_bt__` or `__plot3_bt__`, or another package's assignment name; tidy3a no longer hands `__r_assign__` to tidy3. What stays are the private runtime names each AST pass renames `__r_assign__` to inside its own calls (`__tidy3_assign__`, `__tidy3a_assign__`), which no source text holds; scripts `nb_export` wrote define `__tidy3_assign__` themselves, so they keep running. A notebook mixing these releases with tidy3 0.15, tidy3a 0.16, plot3 0.8 or stats3 0.6 or older can lose backtick names in the other package's calls.
416
416
 
417
417
  Phases 2 to 5 are independent once phase 1 is released. Phase 6 needs all four.
418
418
 
@@ -0,0 +1 @@
1
+ __version__ = "0.2.0"
@@ -3,9 +3,9 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import importlib
6
- from collections.abc import Callable, Iterable
6
+ from collections.abc import Callable, Iterable, Mapping
7
7
  from dataclasses import dataclass, field
8
- from typing import Literal
8
+ from typing import Any, Literal
9
9
 
10
10
 
11
11
  def _names(values: Iterable[str]) -> frozenset[str]:
@@ -51,9 +51,13 @@ class Dialect:
51
51
  # The package's notebook loader, "module:function" taking the shell (its load_ipython_extension):
52
52
  # the coordinator calls it for a cell that imports the package.
53
53
  extension: str | None = field(default=None, compare=False)
54
- # The package's AST pass on source text, given the names that are not columns (an export's
55
- # imports and assignments): mask(source, known) -> source. None for a package without one.
56
- mask: Callable[[str, frozenset[str]], str] | None = field(default=None, compare=False)
54
+ # The package's AST pass on source text, for an export: mask(source, known, context) -> source,
55
+ # where known holds the names that are not columns (the notebook's imports and assignments) and
56
+ # context maps the names the notebook imports to their modules (ownership.imported_names). The
57
+ # result is public code a plain script can run, given the dialect's export_imports.
58
+ mask: Callable[[str, frozenset[str], Mapping[str, Any]], str] | None = field(default=None, compare=False)
59
+ # Lines an exported script needs once the mask has changed a cell ("import tidy3a").
60
+ export_imports: tuple[str, ...] = field(default=(), compare=False)
57
61
 
58
62
  def __post_init__(self) -> None:
59
63
  for name in (
@@ -32,8 +32,8 @@ from tidy3syntax.scanner import (
32
32
  )
33
33
 
34
34
  _BACKTICK = re.compile(r"`([^`\n]+)`")
35
- # Placeholders a package's own pass may have left before tidy3syntax ran (tidy3, plot3), and tidy3syntax's own.
36
- _NAME_CALL = re.compile(r"__(?:r_name|tidy3_bt|plot3_bt)__\((['\"])(.*?)\1\)")
35
+ # A backtick name another rewrite already turned into the placeholder, inside a formula being quoted.
36
+ _NAME_CALL = re.compile(r"__r_name__\((['\"])(.*?)\1\)")
37
37
 
38
38
 
39
39
  def _union(dialects: Iterable[Dialect], field: str) -> frozenset[str]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tidy3syntax
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: R syntax in notebook cells, rewritten to Python: shared by tidy3, tidy3a, plot3 and stats3
5
5
  Author: Rigoberto Leyva Salmeron
6
6
  License-Expression: MIT
@@ -115,11 +115,12 @@ the ownership rule and the two reinterpretations, used by tidy3 0.15.1, tidy3a
115
115
  tidy3, `+` for plot3) and the coordinator, in 0.1.2, which tidy3 0.16, tidy3a
116
116
  0.17, plot3 0.9 and stats3 0.7 register with.
117
117
 
118
- Until every package's AST pass reads the neutral placeholders, each package
119
- calls only the repairs whose output the others already read, and tidy3 and
120
- plot3 turn `__r_name__` and `__r_assign__` back into their own names
121
- (`__tidy3_bt__`, `__tidy3_assign__`, `__plot3_bt__`). tidy3a writes
122
- `__r_assign__` and hands it to tidy3 as `__tidy3_assign__` in tidy3's calls.
118
+ Phase 7, in 0.2.0: `__r_name__` and `__r_assign__` are the only
119
+ placeholders any package writes or reads; the packages' own names from before
120
+ (`__tidy3_bt__`, `__plot3_bt__`) are gone. Inside its own calls each
121
+ package's AST pass renames `__r_assign__` to a private name of its own
122
+ (`__tidy3_assign__`, `__tidy3a_assign__`), since the shared name's value in a
123
+ namespace can belong to no single package.
123
124
 
124
125
  Where the output differs from a package's own rewrite before the switch:
125
126
 
@@ -129,9 +130,10 @@ Where the output differs from a package's own rewrite before the switch:
129
130
  (`df.select(a = x, b)`) is rewritten like the verb, as `!` in one already
130
131
  was; backticks inside strings and comments stay; a backtick assignment is
131
132
  rewritten only as a call argument.
132
- - tidy3a: its placeholder is `__r_assign__` (it still reads `__tidy3a_assign__`).
133
- - plot3: a placeholder another package left inside a one-sided facet formula
134
- (`facet_wrap(~__tidy3_bt__('a b'))`) becomes the name again: `'~a b'`.
133
+ - tidy3a: its placeholder is `__r_assign__`.
134
+ - plot3: a backtick name inside a one-sided facet formula that another
135
+ package's rewrite reached first (`facet_wrap(~__r_name__('a b'))`) becomes
136
+ the name again: `'~a b'`.
135
137
 
136
138
  `scripts/family/` runs all five suites together on another machine: `sync.sh`
137
139
  copies the working trees and starts `run.sh` in a tmux session there, and
@@ -144,13 +144,13 @@ def test_entry_points_name_a_function_returning_the_dialect(shell, monkeypatch):
144
144
  module.loaded = []
145
145
  module.dialect = lambda: Dialect(
146
146
  "fakeplot", power_calls={"geom_function"}, exports={"geom_function"},
147
- extension="fakeplot:load", mask=lambda source, known: source.replace("MASKED", "masked"),
147
+ extension="fakeplot:load", mask=lambda source, known, context: source.replace("MASKED", "masked"),
148
148
  )
149
149
  module.load = lambda shell: (module.loaded.append(shell), coordinator.register(shell, module.dialect()))
150
150
  _entry_points(monkeypatch, ("fakeplot", "fakeplot:dialect"), ("broken", "nowhere_at_all:dialect"))
151
151
 
152
152
  assert [d.package for d in coordinator.installed()] == ["fakeplot"]
153
- assert coordinator.installed()[0].mask("MASKED", frozenset()) == "masked"
153
+ assert coordinator.installed()[0].mask("MASKED", frozenset(), {}) == "masked"
154
154
 
155
155
  coordinator.register(shell, VERBS)
156
156
  ns = run(shell, "from fakeplot import geom_function\nr = geom_function(lambda x: x ^ 2)")
@@ -38,8 +38,8 @@ USER_GEOM_FUNCTION = "def geom_function(fun):\n return fun(3)\n"
38
38
  ("facet_wrap( ~ cyl , ncol=2)", "facet_wrap( '~ cyl' , ncol=2)"),
39
39
  ("p + facet_wrap(\n ~ gear,\n ncol=2)", "p + facet_wrap(\n '~ gear',\n ncol=2)"),
40
40
  ('facet_wrap("~cyl")', None),
41
- # tidy3's backtick placeholder, left by a pass that ran first, keeps its name inside the formula.
42
- ("facet_wrap(~__tidy3_bt__('my col'))", "facet_wrap('~my col')"),
41
+ # A backtick name the backtick repair already rewrote keeps its name inside the formula.
42
+ ("facet_wrap(~__r_name__('my col'))", "facet_wrap('~my col')"),
43
43
  ],
44
44
  )
45
45
  def test_only_plot3_calls_are_reinterpreted(cell, expected):
@@ -1 +0,0 @@
1
- __version__ = "0.1.2"
File without changes
File without changes
File without changes
File without changes