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.
- ipython_postfix_completion-0.2.0/CHANGELOG.md +32 -0
- {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/MANIFEST.in +1 -0
- ipython_postfix_completion-0.2.0/PKG-INFO +282 -0
- ipython_postfix_completion-0.2.0/README.md +247 -0
- {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/ipython_postfix_completion/__init__.py +378 -22
- ipython_postfix_completion-0.2.0/ipython_postfix_completion.egg-info/PKG-INFO +282 -0
- {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/ipython_postfix_completion.egg-info/SOURCES.txt +1 -0
- {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/ipython_postfix_completion.egg-info/requires.txt +3 -1
- {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/pyproject.toml +11 -2
- {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/tests/test_postfix_completion.py +254 -23
- ipython_postfix_completion-0.1.0/PKG-INFO +0 -150
- ipython_postfix_completion-0.1.0/README.md +0 -122
- ipython_postfix_completion-0.1.0/ipython_postfix_completion.egg-info/PKG-INFO +0 -150
- {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/LICENSE +0 -0
- {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/ipython_postfix_completion.egg-info/dependency_links.txt +0 -0
- {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/ipython_postfix_completion.egg-info/top_level.txt +0 -0
- {ipython_postfix_completion-0.1.0 → ipython_postfix_completion-0.2.0}/setup.cfg +0 -0
- {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.
|
|
@@ -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.
|