ipython-postfix-completion 0.1.0__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 (18) hide show
  1. ipython_postfix_completion-0.2.0/CHANGELOG.md +32 -0
  2. {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/MANIFEST.in +1 -0
  3. ipython_postfix_completion-0.2.0/PKG-INFO +282 -0
  4. ipython_postfix_completion-0.2.0/README.md +247 -0
  5. {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/ipython_postfix_completion/__init__.py +378 -22
  6. ipython_postfix_completion-0.2.0/ipython_postfix_completion.egg-info/PKG-INFO +282 -0
  7. {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/ipython_postfix_completion.egg-info/SOURCES.txt +1 -0
  8. {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/ipython_postfix_completion.egg-info/requires.txt +3 -1
  9. {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/pyproject.toml +11 -2
  10. {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/tests/test_postfix_completion.py +254 -23
  11. ipython_postfix_completion-0.1.0/PKG-INFO +0 -150
  12. ipython_postfix_completion-0.1.0/README.md +0 -122
  13. ipython_postfix_completion-0.1.0/ipython_postfix_completion.egg-info/PKG-INFO +0 -150
  14. {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/LICENSE +0 -0
  15. {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/ipython_postfix_completion.egg-info/dependency_links.txt +0 -0
  16. {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/ipython_postfix_completion.egg-info/top_level.txt +0 -0
  17. {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/setup.cfg +0 -0
  18. {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/tests/conftest.py +0 -0
@@ -0,0 +1,32 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ ## [0.2.0] - 2026-08-09
6
+
7
+ ### Added
8
+
9
+ - Smart Tab navigation over Python string and bracket closing tokens.
10
+ - Editable `key` placeholder for the built-in `.var` template.
11
+ - Runtime configuration for enabling or disabling Smart Tab.
12
+ - CI coverage for Python 3.11–3.14 and IPython 9.x.
13
+
14
+ ### Changed
15
+
16
+ - `.var` now expands `expr.var` to `key = expr` and selects `key`.
17
+ - Smart Tab navigation is enabled by default in terminal IPython.
18
+ - IPython 10+ is not currently supported.
19
+
20
+ ### Migration from 0.1.x
21
+
22
+ The `.var` expansion changed from `expr = ` to `key = expr`. Users who
23
+ depend on the old cursor position or assignment shape should keep using a
24
+ custom template until they migrate.
25
+
26
+ ## [0.1.1] - 2026-07-10
27
+
28
+ - Added the `.var` and `.await` templates.
29
+
30
+ ## [0.1.0] - 2026-07-05
31
+
32
+ - Initial release.
@@ -1,3 +1,4 @@
1
1
  include LICENSE
2
2
  include README.md
3
+ include CHANGELOG.md
3
4
  recursive-include tests *.py
@@ -0,0 +1,282 @@
1
+ Metadata-Version: 2.4
2
+ Name: ipython-postfix-completion
3
+ Version: 0.2.0
4
+ Summary: Configurable postfix completion extension for IPython.
5
+ Author: IPython Postfix Completion Contributors
6
+ License-Expression: BSD-3-Clause
7
+ Project-URL: Homepage, https://github.com/fishandsheep/ipython-postfix-completion
8
+ Project-URL: Repository, https://github.com/fishandsheep/ipython-postfix-completion
9
+ Project-URL: Issues, https://github.com/fishandsheep/ipython-postfix-completion/issues
10
+ Project-URL: Changelog, https://github.com/fishandsheep/ipython-postfix-completion/blob/main/CHANGELOG.md
11
+ Keywords: ipython,completion,postfix,extension
12
+ Classifier: Framework :: IPython
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.11
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: ipython<10,>=9.0
25
+ Requires-Dist: traitlets>=5.13
26
+ Provides-Extra: test
27
+ Requires-Dist: pytest>=7; extra == "test"
28
+ Provides-Extra: dev
29
+ Requires-Dist: build; extra == "dev"
30
+ Requires-Dist: pip-audit>=2.7; extra == "dev"
31
+ Requires-Dist: ruff>=0.8; extra == "dev"
32
+ Requires-Dist: twine; extra == "dev"
33
+ Requires-Dist: ipython-postfix-completion[test]; extra == "dev"
34
+ Dynamic: license-file
35
+
36
+ # IPython Postfix Completion
37
+
38
+ Configurable postfix completion extension for IPython.
39
+
40
+ Package on PyPI: `ipython-postfix-completion`
41
+
42
+ ## Install
43
+
44
+ Install into the current Python environment with `uv`:
45
+
46
+ ```bash
47
+ uvx --with ipython-postfix-completion ipython
48
+ ```
49
+
50
+ Install into the current ipython environment with `uv`:
51
+
52
+ ```bash
53
+ uv tool install ipython --with ipython-postfix-completion
54
+ ```
55
+
56
+ ## Load
57
+
58
+ Inside IPython:
59
+
60
+ ```python
61
+ %load_ext ipython_postfix_completion
62
+ ```
63
+
64
+ To load it automatically, add this to `ipython_config.py`:
65
+
66
+ ```python
67
+ c.InteractiveShellApp.extensions = ["ipython_postfix_completion"]
68
+ ```
69
+
70
+ Smart Tab key bindings are supported in terminal IPython. Postfix matcher
71
+ completion can also work in other IPython frontends, but this package does not
72
+ promise frontend-specific Tab behavior outside the terminal.
73
+
74
+ ## Quick Example: Add a `for` Template
75
+
76
+ Add a template for the current IPython session:
77
+
78
+ ```python
79
+ %postfix_template add for "for item in {expr}:\n{indent} "
80
+ ```
81
+
82
+ Use it:
83
+
84
+ ```python
85
+ items.for<Tab>
86
+ ```
87
+
88
+ It expands to:
89
+
90
+ ```python
91
+ for item in items:
92
+
93
+ ```
94
+
95
+ Runtime templates only affect the current IPython session. Put templates in
96
+ `ipython_config.py` if you want them to persist.
97
+
98
+ ## Runtime Magic
99
+
100
+ List effective templates:
101
+
102
+ ```python
103
+ %postfix_template list
104
+ ```
105
+
106
+ Add or override a template for the current session:
107
+
108
+ ```python
109
+ %postfix_template add debug "print({expr}=)"
110
+ %postfix_template add forin "for item in {expr}:\n{indent} "
111
+ ```
112
+
113
+ Disable a template for the current session:
114
+
115
+ ```python
116
+ %postfix_template remove tuple
117
+ ```
118
+
119
+ Reset one runtime change:
120
+
121
+ ```python
122
+ %postfix_template reset forin
123
+ ```
124
+
125
+ Reset all runtime changes:
126
+
127
+ ```python
128
+ %postfix_template reset --all
129
+ ```
130
+
131
+ ## Persistent Config
132
+
133
+ Add persistent templates in `ipython_config.py`:
134
+
135
+ ```python
136
+ c.PostfixCompletionConfig.templates = {
137
+ "debug": "print({expr}=)",
138
+ "forin": "for item in {expr}:\n{indent} ",
139
+ }
140
+
141
+ c.PostfixCompletionConfig.disabled_templates = ["tuple"]
142
+ ```
143
+
144
+ Smart Tab jump is enabled by default. Disable it while keeping postfix
145
+ completion with:
146
+
147
+ ```python
148
+ c.PostfixCompletionConfig.smart_tab_jump = False
149
+ ```
150
+
151
+ Template names must match `[A-Za-z_][A-Za-z0-9_]*`.
152
+
153
+ Templates must include `{expr}` and may also use `{indent}`. No other template
154
+ fields are allowed.
155
+
156
+ ## `.var` Placeholder
157
+
158
+ The built-in `.var` template creates an assignment and selects `key` as an
159
+ editable placeholder:
160
+
161
+ ```text
162
+ "hello".var<Tab> -> key = "hello"
163
+ ^^^ selected
164
+ ```
165
+
166
+ While `key` remains selected:
167
+
168
+ - Tab accepts `key` and moves cursor to the end of the assignment.
169
+ - Enter behaves like Tab for this selection only; press Enter again to submit.
170
+ - Any other typed text replaces `key` with a custom variable name.
171
+
172
+ In 0.1.x, `.var` produced `expr = ` with the cursor after the assignment
173
+ target. Version 0.2.0 changes this to `key = expr` with an editable
174
+ placeholder; use a custom template if you need the old behavior.
175
+
176
+ ## Smart Tab Jump
177
+
178
+ When cursor is immediately before a valid Python closing token, Tab moves over
179
+ it without changing source text. Repeated Tab presses exit nested constructs:
180
+
181
+ ```text
182
+ "hello|" -> "hello"|
183
+ print("hello|") -> print("hello"|) -> print("hello")|
184
+ print(f"{name|}") -> print(f"{name}|") -> print(f"{name}"|) -> print(f"{name}")|
185
+ items[index|] -> items[index]|
186
+ list[dict[str, int|]] -> list[dict[str, int]|] -> list[dict[str, int]]|
187
+ {"name": value|} -> {"name": value}|
188
+ ```
189
+
190
+ `|` marks cursor and is not typed. Supported closers are single and triple
191
+ quotes plus `)`, `]`, and `}`. Detection follows Python tokens, including
192
+ multiline input, string prefixes, and f-string expressions. Tab still accepts
193
+ the `.var` name selection or an exact postfix template first; otherwise it
194
+ falls back to IPython completion or indentation. Ambiguous `< >`, colon, and
195
+ comma are intentionally excluded.
196
+
197
+ ## Built-in Templates
198
+
199
+ Default templates:
200
+
201
+ | Name | Expansion |
202
+ | --- | --- |
203
+ | `print` | `print({expr})` |
204
+ | `len` | `len({expr})` |
205
+ | `not` | `not {expr}` |
206
+ | `par` | `({expr})` |
207
+ | `var` | `key = {expr}`; selects `key`; Tab or Enter accepts it |
208
+ | `await` | `await {expr}` |
209
+ | `return` | `return {expr}` |
210
+ | `if` | `if {expr}:\n{indent} ` |
211
+ | `while` | `while {expr}:\n{indent} ` |
212
+ | `raise` | `raise {expr}` |
213
+ | `yield` | `yield {expr}` |
214
+ | `str` | `str({expr})` |
215
+ | `list` | `list({expr})` |
216
+ | `set` | `set({expr})` |
217
+ | `dict` | `dict({expr})` |
218
+ | `tuple` | `tuple({expr})` |
219
+
220
+ Use `%postfix_template list` in IPython to see the exact effective set, including
221
+ custom and disabled templates.
222
+
223
+ ## Local Validation
224
+
225
+ Run tests:
226
+
227
+ ```bash
228
+ uv run --extra test pytest -q
229
+ uv run --extra dev ruff check .
230
+ uv run --extra dev ruff format --check .
231
+ uv run --isolated --no-project --with "ipython>=9,<10" --with "traitlets>=5.13" --with "pip-audit>=2.7" pip-audit --strict --local
232
+ ```
233
+
234
+ Build and check release artifacts:
235
+
236
+ ```bash
237
+ uv run --extra dev python -m build
238
+ uv run --extra dev python -m twine check dist/*
239
+ ```
240
+
241
+ Validate the wheel in a clean local virtual environment:
242
+
243
+ ```bash
244
+ uv venv .venv-check
245
+ uv pip install --python .venv-check/bin/python dist/*.whl
246
+ .venv-check/bin/ipython
247
+ ```
248
+
249
+ Then inside IPython:
250
+
251
+ ```python
252
+ %load_ext ipython_postfix_completion
253
+ %postfix_template add for "for item in {expr}:\n{indent} "
254
+ %postfix_template list
255
+ ```
256
+
257
+ ## Publish
258
+
259
+ Publishing uses GitHub Actions and PyPI Trusted Publishing. Configure the
260
+ existing PyPI project once under **Manage > Publishing > Add a new publisher**:
261
+
262
+ | Setting | Value |
263
+ | --- | --- |
264
+ | Owner | `fishandsheep` |
265
+ | Repository | `ipython-postfix-completion` |
266
+ | Workflow | `publish.yml` |
267
+ | Environment | `pypi` |
268
+
269
+ For each release, update `project.version` in `pyproject.toml`, commit and push
270
+ the change, then create a matching `v` tag. For this release:
271
+
272
+ ```bash
273
+ git tag v0.2.0
274
+ git push origin v0.2.0
275
+ ```
276
+
277
+ The workflow verifies the tag against `project.version`, runs tests, builds and
278
+ checks both distributions, then publishes them to PyPI using a short-lived OIDC
279
+ credential. PyPI versions are immutable: never reuse a published version or tag;
280
+ fixes require the next version.
281
+
282
+ See [CHANGELOG.md](CHANGELOG.md) for release notes and migration guidance.
@@ -0,0 +1,247 @@
1
+ # IPython Postfix Completion
2
+
3
+ Configurable postfix completion extension for IPython.
4
+
5
+ Package on PyPI: `ipython-postfix-completion`
6
+
7
+ ## Install
8
+
9
+ Install into the current Python environment with `uv`:
10
+
11
+ ```bash
12
+ uvx --with ipython-postfix-completion ipython
13
+ ```
14
+
15
+ Install into the current ipython environment with `uv`:
16
+
17
+ ```bash
18
+ uv tool install ipython --with ipython-postfix-completion
19
+ ```
20
+
21
+ ## Load
22
+
23
+ Inside IPython:
24
+
25
+ ```python
26
+ %load_ext ipython_postfix_completion
27
+ ```
28
+
29
+ To load it automatically, add this to `ipython_config.py`:
30
+
31
+ ```python
32
+ c.InteractiveShellApp.extensions = ["ipython_postfix_completion"]
33
+ ```
34
+
35
+ Smart Tab key bindings are supported in terminal IPython. Postfix matcher
36
+ completion can also work in other IPython frontends, but this package does not
37
+ promise frontend-specific Tab behavior outside the terminal.
38
+
39
+ ## Quick Example: Add a `for` Template
40
+
41
+ Add a template for the current IPython session:
42
+
43
+ ```python
44
+ %postfix_template add for "for item in {expr}:\n{indent} "
45
+ ```
46
+
47
+ Use it:
48
+
49
+ ```python
50
+ items.for<Tab>
51
+ ```
52
+
53
+ It expands to:
54
+
55
+ ```python
56
+ for item in items:
57
+
58
+ ```
59
+
60
+ Runtime templates only affect the current IPython session. Put templates in
61
+ `ipython_config.py` if you want them to persist.
62
+
63
+ ## Runtime Magic
64
+
65
+ List effective templates:
66
+
67
+ ```python
68
+ %postfix_template list
69
+ ```
70
+
71
+ Add or override a template for the current session:
72
+
73
+ ```python
74
+ %postfix_template add debug "print({expr}=)"
75
+ %postfix_template add forin "for item in {expr}:\n{indent} "
76
+ ```
77
+
78
+ Disable a template for the current session:
79
+
80
+ ```python
81
+ %postfix_template remove tuple
82
+ ```
83
+
84
+ Reset one runtime change:
85
+
86
+ ```python
87
+ %postfix_template reset forin
88
+ ```
89
+
90
+ Reset all runtime changes:
91
+
92
+ ```python
93
+ %postfix_template reset --all
94
+ ```
95
+
96
+ ## Persistent Config
97
+
98
+ Add persistent templates in `ipython_config.py`:
99
+
100
+ ```python
101
+ c.PostfixCompletionConfig.templates = {
102
+ "debug": "print({expr}=)",
103
+ "forin": "for item in {expr}:\n{indent} ",
104
+ }
105
+
106
+ c.PostfixCompletionConfig.disabled_templates = ["tuple"]
107
+ ```
108
+
109
+ Smart Tab jump is enabled by default. Disable it while keeping postfix
110
+ completion with:
111
+
112
+ ```python
113
+ c.PostfixCompletionConfig.smart_tab_jump = False
114
+ ```
115
+
116
+ Template names must match `[A-Za-z_][A-Za-z0-9_]*`.
117
+
118
+ Templates must include `{expr}` and may also use `{indent}`. No other template
119
+ fields are allowed.
120
+
121
+ ## `.var` Placeholder
122
+
123
+ The built-in `.var` template creates an assignment and selects `key` as an
124
+ editable placeholder:
125
+
126
+ ```text
127
+ "hello".var<Tab> -> key = "hello"
128
+ ^^^ selected
129
+ ```
130
+
131
+ While `key` remains selected:
132
+
133
+ - Tab accepts `key` and moves cursor to the end of the assignment.
134
+ - Enter behaves like Tab for this selection only; press Enter again to submit.
135
+ - Any other typed text replaces `key` with a custom variable name.
136
+
137
+ In 0.1.x, `.var` produced `expr = ` with the cursor after the assignment
138
+ target. Version 0.2.0 changes this to `key = expr` with an editable
139
+ placeholder; use a custom template if you need the old behavior.
140
+
141
+ ## Smart Tab Jump
142
+
143
+ When cursor is immediately before a valid Python closing token, Tab moves over
144
+ it without changing source text. Repeated Tab presses exit nested constructs:
145
+
146
+ ```text
147
+ "hello|" -> "hello"|
148
+ print("hello|") -> print("hello"|) -> print("hello")|
149
+ print(f"{name|}") -> print(f"{name}|") -> print(f"{name}"|) -> print(f"{name}")|
150
+ items[index|] -> items[index]|
151
+ list[dict[str, int|]] -> list[dict[str, int]|] -> list[dict[str, int]]|
152
+ {"name": value|} -> {"name": value}|
153
+ ```
154
+
155
+ `|` marks cursor and is not typed. Supported closers are single and triple
156
+ quotes plus `)`, `]`, and `}`. Detection follows Python tokens, including
157
+ multiline input, string prefixes, and f-string expressions. Tab still accepts
158
+ the `.var` name selection or an exact postfix template first; otherwise it
159
+ falls back to IPython completion or indentation. Ambiguous `< >`, colon, and
160
+ comma are intentionally excluded.
161
+
162
+ ## Built-in Templates
163
+
164
+ Default templates:
165
+
166
+ | Name | Expansion |
167
+ | --- | --- |
168
+ | `print` | `print({expr})` |
169
+ | `len` | `len({expr})` |
170
+ | `not` | `not {expr}` |
171
+ | `par` | `({expr})` |
172
+ | `var` | `key = {expr}`; selects `key`; Tab or Enter accepts it |
173
+ | `await` | `await {expr}` |
174
+ | `return` | `return {expr}` |
175
+ | `if` | `if {expr}:\n{indent} ` |
176
+ | `while` | `while {expr}:\n{indent} ` |
177
+ | `raise` | `raise {expr}` |
178
+ | `yield` | `yield {expr}` |
179
+ | `str` | `str({expr})` |
180
+ | `list` | `list({expr})` |
181
+ | `set` | `set({expr})` |
182
+ | `dict` | `dict({expr})` |
183
+ | `tuple` | `tuple({expr})` |
184
+
185
+ Use `%postfix_template list` in IPython to see the exact effective set, including
186
+ custom and disabled templates.
187
+
188
+ ## Local Validation
189
+
190
+ Run tests:
191
+
192
+ ```bash
193
+ uv run --extra test pytest -q
194
+ uv run --extra dev ruff check .
195
+ uv run --extra dev ruff format --check .
196
+ uv run --isolated --no-project --with "ipython>=9,<10" --with "traitlets>=5.13" --with "pip-audit>=2.7" pip-audit --strict --local
197
+ ```
198
+
199
+ Build and check release artifacts:
200
+
201
+ ```bash
202
+ uv run --extra dev python -m build
203
+ uv run --extra dev python -m twine check dist/*
204
+ ```
205
+
206
+ Validate the wheel in a clean local virtual environment:
207
+
208
+ ```bash
209
+ uv venv .venv-check
210
+ uv pip install --python .venv-check/bin/python dist/*.whl
211
+ .venv-check/bin/ipython
212
+ ```
213
+
214
+ Then inside IPython:
215
+
216
+ ```python
217
+ %load_ext ipython_postfix_completion
218
+ %postfix_template add for "for item in {expr}:\n{indent} "
219
+ %postfix_template list
220
+ ```
221
+
222
+ ## Publish
223
+
224
+ Publishing uses GitHub Actions and PyPI Trusted Publishing. Configure the
225
+ existing PyPI project once under **Manage > Publishing > Add a new publisher**:
226
+
227
+ | Setting | Value |
228
+ | --- | --- |
229
+ | Owner | `fishandsheep` |
230
+ | Repository | `ipython-postfix-completion` |
231
+ | Workflow | `publish.yml` |
232
+ | Environment | `pypi` |
233
+
234
+ For each release, update `project.version` in `pyproject.toml`, commit and push
235
+ the change, then create a matching `v` tag. For this release:
236
+
237
+ ```bash
238
+ git tag v0.2.0
239
+ git push origin v0.2.0
240
+ ```
241
+
242
+ The workflow verifies the tag against `project.version`, runs tests, builds and
243
+ checks both distributions, then publishes them to PyPI using a short-lived OIDC
244
+ credential. PyPI versions are immutable: never reuse a published version or tag;
245
+ fixes require the next version.
246
+
247
+ See [CHANGELOG.md](CHANGELOG.md) for release notes and migration guidance.