isabelle-block 0.1.2__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.
@@ -0,0 +1,29 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+
9
+ # Virtual environments. `.venv/` is the throwaway install target the test
10
+ # instructions use -- the suite is run against a real `pip install .`, never
11
+ # against `PYTHONPATH=src`, so a venv is a working file rather than a artefact.
12
+ .venv/
13
+ venv/
14
+
15
+ # Editor / OS / agent
16
+ .claude/*
17
+ !.claude/memory/
18
+ .DS_Store
19
+
20
+ # Pytest / lint caches
21
+ .pytest_cache/
22
+ .ruff_cache/
23
+
24
+ # End-of-session handoff scratchpad -- rewritten each session.
25
+ prompt.md
26
+
27
+ # Working files: scratch space and the commit-message file (CLAUDE.md).
28
+ scratch/
29
+ .gitcommit.txt
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 András Salamon
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,140 @@
1
+ Metadata-Version: 2.5
2
+ Name: isabelle-block
3
+ Version: 0.1.2
4
+ Summary: Mechanical block surgery on Isabelle theory sources: move, copy, delete, rewrite and substitute inside regions named by line span or by entry name.
5
+ Project-URL: Homepage, https://github.com/ott2/isabelle-block
6
+ Project-URL: Source, https://github.com/ott2/isabelle-block
7
+ Author-email: András Salamon <Andras.Salamon@st-andrews.ac.uk>
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: afp,formal-verification,isabelle,isar,refactoring,theorem-proving
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
18
+ Classifier: Topic :: Software Development
19
+ Requires-Python: >=3.9
20
+ Requires-Dist: isabelle-layout>=0.2.2
21
+ Requires-Dist: isabelle-query>=1.1.1
22
+ Provides-Extra: test
23
+ Requires-Dist: pytest>=7; extra == 'test'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # isabelle-block
27
+
28
+ **Mechanical edits to regions of Isabelle theory files, where a region is
29
+ named by a line span or by the name of a lemma.**
30
+
31
+ ```sh
32
+ block move Foo.thy:helper_lemma before first_user # hoist a helper
33
+ block delete Foo.thy:dead_lemma
34
+ block move Foo.thy:1669..2657 before Bar.thy:46 # between theories
35
+ block reargs 'cost $1 $2' 'Suc (len $1)' Foo.thy --expect 14
36
+ ```
37
+
38
+ Name addressing is the reason to use it. `Foo.thy:helper_lemma` resolves,
39
+ through [`isabelle-query`](https://github.com/ott2/isabelle-query)'s parser,
40
+ to the lemma's span, from its doc block through the last line of its proof.
41
+ So an edit needs no line arithmetic, and it cannot go stale between looking
42
+ a lemma up and editing it.
43
+
44
+ ## Install
45
+
46
+ ```sh
47
+ python3 -m pip install git+https://github.com/ott2/isabelle-block@v0.1.2
48
+ ```
49
+
50
+ This puts `block` on your `PATH`. Needs Python 3.9 or later; depends on
51
+ `isabelle-query` and `isabelle-layout`, which pip fetches from PyPI. It
52
+ needs no Isabelle process.
53
+
54
+ `isabelle-block` is not on PyPI yet. It will be published there once the
55
+ standalone tool has seen more use; until then, install a tagged release from
56
+ GitHub as above.
57
+
58
+ ## Verbs
59
+
60
+ | verb | does |
61
+ |---|---|
62
+ | `move SRC:REGION before DEST` | relocate a block, within a file or between files |
63
+ | `copy SRC:REGION before DEST` | place a copy and keep the source |
64
+ | `delete FILE:REGION` | excise a block |
65
+ | `emit FILE:REGION` | print a block verbatim |
66
+ | `replace FILE:REGION NEWFILE` | swap a block for a file's contents |
67
+ | `sub OLD NEW FILE[:REGION]...` | literal substring substitution |
68
+ | `resub PAT NEW FILE[:REGION]...` | regex substitution; a match may span lines |
69
+ | `reargs 'F $1 $2' TMPL FILE[:REGION]...` | rewrite `F`'s applications by their (bracket-aware) arguments; skips prose |
70
+ | `split SRC 'NAME\|IMPORTS\|RANGES'... [--cut]` | cut a theory into several |
71
+ | `merge BASE.thy SRC.thy...` | splice theory bodies into one |
72
+
73
+ A **REGION** is `A..B` (or `A-B`), a single line `N`, an entry `NAME`, or
74
+ `all`, which is also what a bare `FILE` means. A **DEST** is `LINE`, `NAME`,
75
+ `FILE:LINE` or `FILE:NAME`; the block lands immediately before it, preamble
76
+ included.
77
+
78
+ **Modifiers:**
79
+
80
+ - `--dry-run` reports the edit and writes nothing.
81
+ - `--expect N` makes `sub`, `resub` and `reargs` refuse unless exactly N
82
+ substitutions are made.
83
+ - `--except NAME` leaves an entry out of every region.
84
+ - `--no-preamble` starts a resolved span at the entry, not its doc block.
85
+ - `--with-preamble` keeps the doc block even when it sits directly under a
86
+ section heading. Such a `text` may introduce the section rather than
87
+ document the entry, and the source cannot say which. So there, `delete`,
88
+ `move` and `replace` refuse until you choose one of these two flags.
89
+ - `--keep-heading` / `--with-heading`: deleting the only entry under a
90
+ heading refuses until you say whether the heading stays (bare) or the
91
+ whole section goes with the entry.
92
+
93
+ A block moved `before NAME` that starts with its own heading, of the same or
94
+ higher rank as the heading above NAME, lands above that heading. So it
95
+ becomes a section beside NAME's, and does not swallow NAME.
96
+ - `--root DIR` names the session root whose keyword table name resolution
97
+ uses. By default it is discovered as `query` discovers it: an
98
+ environment variable, a `.isabelle-query` marker, or the nearest `ROOT`.
99
+ The table matters because a theory may use a command that another theory
100
+ in its session declares.
101
+ - `--no-trailing-blank` cuts verbatim, without blank-line healing.
102
+
103
+ `block --help` gives the full grammar, and `block VERB --help` gives one
104
+ verb's.
105
+
106
+ Every run ends with an explicit `PASS:` or `FAIL:` line, and the exit status
107
+ agrees. `emit` prints its `PASS:` on stderr, so `block emit … > FILE` is a
108
+ clean copy. A refusal writes nothing.
109
+
110
+ ## Related tools
111
+
112
+ Editing by line span and plain substitution are what `ed`, `sed`, `sd` and
113
+ `fastmod` already do. [comby](https://comby.dev) does bracket-aware
114
+ rewriting much as `reargs` does. `block` is worth installing if your edits
115
+ need what those tools cannot see:
116
+
117
+ - lemma names as addresses;
118
+ - the difference between Isar code and prose (`text`, headings,
119
+ `\<comment>`);
120
+ - edits at theory level.
121
+
122
+ `docs/related-tools.md` compares them in detail.
123
+
124
+ ## Status
125
+
126
+ This is alpha, extracted from the NDTHT formalisation's `bin/block.py`, where it
127
+ did the project's mechanical theory surgery. The planned verbs (`rename`, a
128
+ caller-checked `delete` and an import-checked `move`) are in `tasks.md`.
129
+
130
+ ## Development
131
+
132
+ ```sh
133
+ python3 -m venv .venv
134
+ .venv/bin/pip install -e '.[test]'
135
+ .venv/bin/pytest
136
+ ```
137
+
138
+ ## Authors & license
139
+
140
+ By András Salamon, with Claude Opus 4.7, 4.8, 5, and 5.5. [MIT](LICENSE).
@@ -0,0 +1,115 @@
1
+ # isabelle-block
2
+
3
+ **Mechanical edits to regions of Isabelle theory files, where a region is
4
+ named by a line span or by the name of a lemma.**
5
+
6
+ ```sh
7
+ block move Foo.thy:helper_lemma before first_user # hoist a helper
8
+ block delete Foo.thy:dead_lemma
9
+ block move Foo.thy:1669..2657 before Bar.thy:46 # between theories
10
+ block reargs 'cost $1 $2' 'Suc (len $1)' Foo.thy --expect 14
11
+ ```
12
+
13
+ Name addressing is the reason to use it. `Foo.thy:helper_lemma` resolves,
14
+ through [`isabelle-query`](https://github.com/ott2/isabelle-query)'s parser,
15
+ to the lemma's span, from its doc block through the last line of its proof.
16
+ So an edit needs no line arithmetic, and it cannot go stale between looking
17
+ a lemma up and editing it.
18
+
19
+ ## Install
20
+
21
+ ```sh
22
+ python3 -m pip install git+https://github.com/ott2/isabelle-block@v0.1.2
23
+ ```
24
+
25
+ This puts `block` on your `PATH`. Needs Python 3.9 or later; depends on
26
+ `isabelle-query` and `isabelle-layout`, which pip fetches from PyPI. It
27
+ needs no Isabelle process.
28
+
29
+ `isabelle-block` is not on PyPI yet. It will be published there once the
30
+ standalone tool has seen more use; until then, install a tagged release from
31
+ GitHub as above.
32
+
33
+ ## Verbs
34
+
35
+ | verb | does |
36
+ |---|---|
37
+ | `move SRC:REGION before DEST` | relocate a block, within a file or between files |
38
+ | `copy SRC:REGION before DEST` | place a copy and keep the source |
39
+ | `delete FILE:REGION` | excise a block |
40
+ | `emit FILE:REGION` | print a block verbatim |
41
+ | `replace FILE:REGION NEWFILE` | swap a block for a file's contents |
42
+ | `sub OLD NEW FILE[:REGION]...` | literal substring substitution |
43
+ | `resub PAT NEW FILE[:REGION]...` | regex substitution; a match may span lines |
44
+ | `reargs 'F $1 $2' TMPL FILE[:REGION]...` | rewrite `F`'s applications by their (bracket-aware) arguments; skips prose |
45
+ | `split SRC 'NAME\|IMPORTS\|RANGES'... [--cut]` | cut a theory into several |
46
+ | `merge BASE.thy SRC.thy...` | splice theory bodies into one |
47
+
48
+ A **REGION** is `A..B` (or `A-B`), a single line `N`, an entry `NAME`, or
49
+ `all`, which is also what a bare `FILE` means. A **DEST** is `LINE`, `NAME`,
50
+ `FILE:LINE` or `FILE:NAME`; the block lands immediately before it, preamble
51
+ included.
52
+
53
+ **Modifiers:**
54
+
55
+ - `--dry-run` reports the edit and writes nothing.
56
+ - `--expect N` makes `sub`, `resub` and `reargs` refuse unless exactly N
57
+ substitutions are made.
58
+ - `--except NAME` leaves an entry out of every region.
59
+ - `--no-preamble` starts a resolved span at the entry, not its doc block.
60
+ - `--with-preamble` keeps the doc block even when it sits directly under a
61
+ section heading. Such a `text` may introduce the section rather than
62
+ document the entry, and the source cannot say which. So there, `delete`,
63
+ `move` and `replace` refuse until you choose one of these two flags.
64
+ - `--keep-heading` / `--with-heading`: deleting the only entry under a
65
+ heading refuses until you say whether the heading stays (bare) or the
66
+ whole section goes with the entry.
67
+
68
+ A block moved `before NAME` that starts with its own heading, of the same or
69
+ higher rank as the heading above NAME, lands above that heading. So it
70
+ becomes a section beside NAME's, and does not swallow NAME.
71
+ - `--root DIR` names the session root whose keyword table name resolution
72
+ uses. By default it is discovered as `query` discovers it: an
73
+ environment variable, a `.isabelle-query` marker, or the nearest `ROOT`.
74
+ The table matters because a theory may use a command that another theory
75
+ in its session declares.
76
+ - `--no-trailing-blank` cuts verbatim, without blank-line healing.
77
+
78
+ `block --help` gives the full grammar, and `block VERB --help` gives one
79
+ verb's.
80
+
81
+ Every run ends with an explicit `PASS:` or `FAIL:` line, and the exit status
82
+ agrees. `emit` prints its `PASS:` on stderr, so `block emit … > FILE` is a
83
+ clean copy. A refusal writes nothing.
84
+
85
+ ## Related tools
86
+
87
+ Editing by line span and plain substitution are what `ed`, `sed`, `sd` and
88
+ `fastmod` already do. [comby](https://comby.dev) does bracket-aware
89
+ rewriting much as `reargs` does. `block` is worth installing if your edits
90
+ need what those tools cannot see:
91
+
92
+ - lemma names as addresses;
93
+ - the difference between Isar code and prose (`text`, headings,
94
+ `\<comment>`);
95
+ - edits at theory level.
96
+
97
+ `docs/related-tools.md` compares them in detail.
98
+
99
+ ## Status
100
+
101
+ This is alpha, extracted from the NDTHT formalisation's `bin/block.py`, where it
102
+ did the project's mechanical theory surgery. The planned verbs (`rename`, a
103
+ caller-checked `delete` and an import-checked `move`) are in `tasks.md`.
104
+
105
+ ## Development
106
+
107
+ ```sh
108
+ python3 -m venv .venv
109
+ .venv/bin/pip install -e '.[test]'
110
+ .venv/bin/pytest
111
+ ```
112
+
113
+ ## Authors & license
114
+
115
+ By András Salamon, with Claude Opus 4.7, 4.8, 5, and 5.5. [MIT](LICENSE).
@@ -0,0 +1,61 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "isabelle-block"
7
+ version = "0.1.2"
8
+ description = "Mechanical block surgery on Isabelle theory sources: move, copy, delete, rewrite and substitute inside regions named by line span or by entry name."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "András Salamon", email = "Andras.Salamon@st-andrews.ac.uk" },
14
+ ]
15
+ keywords = [
16
+ "isabelle", "isar", "theorem-proving", "formal-verification",
17
+ "afp", "refactoring",
18
+ ]
19
+ classifiers = [
20
+ "Development Status :: 3 - Alpha",
21
+ "Intended Audience :: Developers",
22
+ "Intended Audience :: Science/Research",
23
+ "License :: OSI Approved :: MIT License",
24
+ "Programming Language :: Python :: 3",
25
+ "Programming Language :: Python :: 3 :: Only",
26
+ "Topic :: Scientific/Engineering :: Mathematics",
27
+ "Topic :: Software Development",
28
+ ]
29
+ dependencies = [
30
+ # 1.1.0: an entry no longer ends at a heading inside its own proof
31
+ # [early-end]. 1.1.1: a declaration in mid-line is an entry (#29), so no
32
+ # cut_span holds a second lemma. Both keep a span written through to
33
+ # one entry.
34
+ "isabelle-query>=1.1.1",
35
+ # default_t_dir, the session-root discovery `query` itself uses.
36
+ "isabelle-layout>=0.2.2",
37
+ ]
38
+
39
+ [project.optional-dependencies]
40
+ test = ["pytest>=7"]
41
+
42
+ [project.urls]
43
+ Homepage = "https://github.com/ott2/isabelle-block"
44
+ Source = "https://github.com/ott2/isabelle-block"
45
+
46
+ [project.scripts]
47
+ block = "isabelle_block.cli:main"
48
+
49
+ [tool.pytest.ini_options]
50
+ testpaths = ["tests"]
51
+ # The corpus tests read real trees and take about a minute: `pytest -m corpus`.
52
+ addopts = "-ra --strict-markers -m 'not corpus'"
53
+ markers = ["corpus: read-only checks against NDTHT's t/ and the AFP"]
54
+
55
+ [tool.hatch.build.targets.wheel]
56
+ packages = ["src/isabelle_block"]
57
+
58
+ [tool.hatch.build.targets.sdist]
59
+ # Anchored with a leading `/`: an unanchored "README.md" matches at any depth,
60
+ # and shipped docs/prior-art/README.md and upstream/README.md.
61
+ include = ["/src", "/tests", "/README.md", "/LICENSE"]
@@ -0,0 +1,11 @@
1
+ """Mechanical block surgery on Isabelle theory sources.
2
+
3
+ The command-line tool is the product; `isabelle_block.cli` is its
4
+ implementation and has no public library surface yet.
5
+ """
6
+ from importlib.metadata import PackageNotFoundError, version
7
+
8
+ try:
9
+ __version__ = version("isabelle-block")
10
+ except PackageNotFoundError: # running from a source tree, not installed
11
+ __version__ = "0+unknown"
@@ -0,0 +1,5 @@
1
+ import sys
2
+
3
+ from .cli import main
4
+
5
+ sys.exit(main())