pgwidgets-python 0.4.0__tar.gz → 0.4.1__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 (80) hide show
  1. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/.github/workflows/tests.yml +1 -1
  2. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/PKG-INFO +3 -2
  3. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/WhatsNew.rst +24 -1
  4. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/sync.rst +2 -2
  5. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/sync/text_source.py +46 -7
  6. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets_python.egg-info/PKG-INFO +3 -2
  7. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets_python.egg-info/requires.txt +1 -1
  8. pgwidgets_python-0.4.1/pgwidgets_python.egg-info/scm_version.json +8 -0
  9. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pyproject.toml +10 -8
  10. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/tests/test_text_source.py +55 -0
  11. pgwidgets_python-0.4.0/pgwidgets_python.egg-info/scm_version.json +0 -8
  12. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/.flake8 +0 -0
  13. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/.gitignore +0 -0
  14. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/.readthedocs.yaml +0 -0
  15. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/LICENSE.md +0 -0
  16. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/README.md +0 -0
  17. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/Makefile +0 -0
  18. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/api/async.rst +0 -0
  19. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/api/index.rst +0 -0
  20. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/api/sync.rst +0 -0
  21. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/architecture.rst +0 -0
  22. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/async.rst +0 -0
  23. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/callbacks.rst +0 -0
  24. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/conf.py +0 -0
  25. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/extras.rst +0 -0
  26. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/getting-started.rst +0 -0
  27. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/index.rst +0 -0
  28. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/subclassing.rst +0 -0
  29. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/utilities.rst +0 -0
  30. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/web-servers.rst +0 -0
  31. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/docs/widgets.rst +0 -0
  32. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/examples/README.md +0 -0
  33. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/examples/all_widgets.py +0 -0
  34. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/examples/all_widgets_async.py +0 -0
  35. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/examples/demo_async.py +0 -0
  36. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/examples/demo_sync.py +0 -0
  37. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/examples/demo_treeview.py +0 -0
  38. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/examples/flask-multi-process/README.md +0 -0
  39. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/examples/flask-multi-process/gunicorn.conf.py +0 -0
  40. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/examples/flask-multi-process/nginx.conf +0 -0
  41. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/examples/flask-multi-process/server.py +0 -0
  42. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/examples/flask-multi-process/user_app.py +0 -0
  43. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/__init__.py +0 -0
  44. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/_json.py +0 -0
  45. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/async_/Widgets.py +0 -0
  46. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/async_/__init__.py +0 -0
  47. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/async_/application.py +0 -0
  48. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/async_/widget.py +0 -0
  49. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/buffer.py +0 -0
  50. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/callbacks.py +0 -0
  51. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/defs.py +0 -0
  52. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/extras/__init__.py +0 -0
  53. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/extras/file_browser.py +0 -0
  54. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/icons/pgw-python-logo.png +0 -0
  55. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/method_types.py +0 -0
  56. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/sync/Widgets.py +0 -0
  57. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/sync/__init__.py +0 -0
  58. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/sync/application.py +0 -0
  59. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/sync/widget.py +0 -0
  60. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/text_model.py +0 -0
  61. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets/tree_model.py +0 -0
  62. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets_python.egg-info/SOURCES.txt +0 -0
  63. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets_python.egg-info/dependency_links.txt +0 -0
  64. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets_python.egg-info/scm_file_list.json +0 -0
  65. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/pgwidgets_python.egg-info/top_level.txt +0 -0
  66. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/setup.cfg +0 -0
  67. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/test_pg2.py +0 -0
  68. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/tests/__init__.py +0 -0
  69. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/tests/test_async_session.py +0 -0
  70. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/tests/test_defs.py +0 -0
  71. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/tests/test_extras.py +0 -0
  72. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/tests/test_fonts.py +0 -0
  73. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/tests/test_protocol.py +0 -0
  74. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/tests/test_reconstruct.py +0 -0
  75. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/tests/test_resolve_kwargs.py +0 -0
  76. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/tests/test_session.py +0 -0
  77. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/tests/test_stateful.py +0 -0
  78. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/tests/test_tree_model.py +0 -0
  79. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/tests/test_widget_classes.py +0 -0
  80. {pgwidgets_python-0.4.0 → pgwidgets_python-0.4.1}/tools/sync_async_tree_model.py +0 -0
@@ -11,7 +11,7 @@ jobs:
11
11
  runs-on: ubuntu-latest
12
12
  strategy:
13
13
  matrix:
14
- python-version: ["3.12", "3.13"]
14
+ python-version: ["3.12", "3.13", "3.14"]
15
15
 
16
16
  steps:
17
17
  - uses: actions/checkout@v4
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pgwidgets-python
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: Python bindings for the pgwidgets JavaScript widget library
5
5
  Author: PGWidgets Developers
6
6
  License-Expression: BSD-3-Clause
@@ -12,11 +12,12 @@ Classifier: Intended Audience :: Developers
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
15
16
  Classifier: Topic :: Software Development :: User Interfaces
16
17
  Requires-Python: >=3.12
17
18
  Description-Content-Type: text/markdown
18
19
  License-File: LICENSE.md
19
- Requires-Dist: pgwidgets-js>=0.4.0
20
+ Requires-Dist: pgwidgets-js>=0.4.1
20
21
  Requires-Dist: websockets>=12
21
22
  Provides-Extra: dev
22
23
  Requires-Dist: sphinx; extra == "dev"
@@ -1,6 +1,29 @@
1
1
  What's New
2
2
  ==========
3
3
 
4
+ Recent changes — since ``v0.4.0``
5
+ ---------------------------------
6
+
7
+ TextSource: scroll alignment and caret styling
8
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9
+
10
+ ``scroll_to_ref(ref, align)`` and ``scroll_to_lineno(lineno, align)``
11
+ take an alignment -- ``'nearest'`` (the default, as before),
12
+ ``'center'`` or ``'top'`` -- and pass it to the browser alongside the
13
+ offset. A search that scrolls to its match can now put the match in
14
+ the middle of the view rather than merely bringing it into sight.
15
+
16
+ ``set_cursor_style(style, color)`` picks a ``'line'`` or ``'block'``
17
+ caret in any colour, and ``get_cursor_style()`` reads the pair back.
18
+ The choice is part of the model, replayed from
19
+ ``_reconstruct_model()``, so a browser that (re)connects gets the caret
20
+ along with everything else. It is styled through the browser's own
21
+ ``caret-color`` / ``caret-shape``, so it shows only while the editor
22
+ has the focus.
23
+
24
+ These need the matching methods in pgwidgets-js 0.4.1, which the
25
+ dependency floor now requires.
26
+
4
27
  Recent changes — since ``v0.3.5``
5
28
  ---------------------------------
6
29
 
@@ -156,7 +179,7 @@ the 4th argument, so handlers that double-click a file can see
156
179
  which column they hit. Existing handlers (3-arg) keep working.
157
180
 
158
181
  ``_resolve_kwargs``: skipped-positional kwargs
159
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
182
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
160
183
 
161
184
  The kwarg resolver used by every generated widget method now
162
185
  allows a caller to skip a positional argument and supply the
@@ -114,8 +114,8 @@ Bytes are served from ``/_pgwidgets/font/<id>`` by the built-in
114
114
  HTTP server with ``Cache-Control: immutable``; behind Flask /
115
115
  nginx the same route is served from the Python process.
116
116
 
117
- See also the JS-side write-up at :ref:`custom-fonts` in the
118
- pgwidgets-js documentation.
117
+ See also the "Custom fonts" section of the pgwidgets-js
118
+ documentation for the browser side of this.
119
119
 
120
120
  Opening a URL in the browser
121
121
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -29,6 +29,13 @@ from pgwidgets.text_model import TextModel
29
29
  _GeneratedTextSource = build_widget_class("TextSource", WIDGETS["TextSource"])
30
30
 
31
31
 
32
+ def _check_align(align):
33
+ if align not in ('nearest', 'center', 'top'):
34
+ raise ValueError("align should be one of 'nearest', 'center' "
35
+ "or 'top'")
36
+ return align
37
+
38
+
32
39
  class _BrowserTextModel(TextModel):
33
40
  """A TextModel whose render hooks push offset-based operations to the
34
41
  browser via the owning widget. When no browser is connected the calls
@@ -118,6 +125,8 @@ class TextSource(_GeneratedTextSource):
118
125
  text = self._state.get("text")
119
126
  self._model._text = "" if text is None else str(text)
120
127
  self._state.pop("text", None)
128
+ # caret appearance (see set_cursor_style); replayed on reconnect
129
+ self._cursor_style = ('line', None)
121
130
 
122
131
  def create_tag(self, name, attrs=None, **kwdargs):
123
132
  """Define a display tag locally and push its styling to the browser."""
@@ -126,18 +135,46 @@ class TextSource(_GeneratedTextSource):
126
135
  self._model.create_tag(name, merged)
127
136
  self._call("create_tag", name, merged)
128
137
 
129
- def scroll_to_ref(self, ref):
130
- """Scroll the view to a ref, addressed by its current offset."""
131
- self._call("_scrollToOffset", self._model._offset_of(ref))
138
+ def scroll_to_ref(self, ref, align='nearest'):
139
+ """Scroll the view to a ref, addressed by its current offset.
132
140
 
133
- def scroll_to_lineno(self, lineno):
134
- """Scroll so that line ``lineno`` is visible."""
141
+ ``align`` says where the line should end up: 'nearest' scrolls the
142
+ least amount that brings it into view (the default), 'center' puts
143
+ it in the middle of the view and 'top' at the top.
144
+ """
145
+ self._call("_scrollToOffset", self._model._offset_of(ref),
146
+ _check_align(align))
147
+
148
+ def scroll_to_lineno(self, lineno, align='nearest'):
149
+ """Scroll so that line ``lineno`` is visible; see
150
+ ``scroll_to_ref`` for ``align``."""
135
151
  self._call("_scrollToOffset",
136
- self._model._offset_of_line_start(lineno))
152
+ self._model._offset_of_line_start(lineno),
153
+ _check_align(align))
137
154
 
138
155
  def scroll_to_end(self):
139
156
  """Scroll to the end of the buffer."""
140
- self._call("_scrollToOffset", self._model.get_length())
157
+ self._call("_scrollToOffset", self._model.get_length(), 'nearest')
158
+
159
+ def set_cursor_style(self, style='line', color=None):
160
+ """Set the appearance of the text caret.
161
+
162
+ ``style`` is 'line' (a thin vertical bar, the default) or 'block';
163
+ ``color`` is any CSS color, or None for the browser default.
164
+
165
+ NOTE: this styles the browser's own caret, so it is only drawn
166
+ while the editor has the keyboard focus, and the block shape needs
167
+ a browser that supports the CSS 'caret-shape' property (elsewhere
168
+ the caret keeps its color but stays a thin bar).
169
+ """
170
+ if style not in ('line', 'block'):
171
+ raise ValueError("style should be one of 'line' or 'block'")
172
+ self._cursor_style = (style, color)
173
+ self._call("set_cursor_style", style, color)
174
+
175
+ def get_cursor_style(self):
176
+ """Return the caret appearance as a ``(style, color)`` pair."""
177
+ return self._cursor_style
141
178
 
142
179
  def show_tooltip(self, text, x, y):
143
180
  """Show a hover tooltip (``text``) near viewport point (x, y), or
@@ -182,6 +219,8 @@ class TextSource(_GeneratedTextSource):
182
219
  self._call("_setSelectionOffsets", m._sel_start, m._sel_end)
183
220
  else:
184
221
  self._call("_setCursorOffset", m._cursor)
222
+ if self._cursor_style != ('line', None):
223
+ self._call("set_cursor_style", *self._cursor_style)
185
224
 
186
225
 
187
226
  def _install_delegators():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pgwidgets-python
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: Python bindings for the pgwidgets JavaScript widget library
5
5
  Author: PGWidgets Developers
6
6
  License-Expression: BSD-3-Clause
@@ -12,11 +12,12 @@ Classifier: Intended Audience :: Developers
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
15
16
  Classifier: Topic :: Software Development :: User Interfaces
16
17
  Requires-Python: >=3.12
17
18
  Description-Content-Type: text/markdown
18
19
  License-File: LICENSE.md
19
- Requires-Dist: pgwidgets-js>=0.4.0
20
+ Requires-Dist: pgwidgets-js>=0.4.1
20
21
  Requires-Dist: websockets>=12
21
22
  Provides-Extra: dev
22
23
  Requires-Dist: sphinx; extra == "dev"
@@ -1,4 +1,4 @@
1
- pgwidgets-js>=0.4.0
1
+ pgwidgets-js>=0.4.1
2
2
  websockets>=12
3
3
 
4
4
  [dev]
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.4.1",
3
+ "distance": 0,
4
+ "node": "gba8f2928171144dd56a747a75fb45722db1bd4d7",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-08-22"
8
+ }
@@ -14,14 +14,15 @@ authors = [
14
14
  {name = "PGWidgets Developers"},
15
15
  ]
16
16
  dependencies = [
17
- # Tests and runtime expect the incremental TreeView/TableView updates
18
- # and the "batch" / set_colors protocol messages — introduced in
19
- # pgwidgets-js 0.4.0. (Earlier requirements — the TextSource
20
- # selection/tag-region and tooltip/scroll APIs, Separator,
21
- # Button.set_hover, ButtonBox.min_button_width, Dialog.set_title
22
- # date to 0.3.4; set_min_size/set_max_size, the dict-tree TreeView,
23
- # the binary Image protocol, TopLevel window-control options to 0.2.0.)
24
- "pgwidgets-js>=0.4.0",
17
+ # TextSource's scroll alignment and set_cursor_style() need the
18
+ # matching browser-side methods, introduced in pgwidgets-js 0.4.1.
19
+ # (Earlier requirements — the incremental TreeView/TableView updates
20
+ # and the "batch" / set_colors protocol messages date to 0.4.0; the
21
+ # TextSource selection/tag-region and tooltip/scroll APIs, Separator,
22
+ # Button.set_hover, ButtonBox.min_button_width, Dialog.set_title to
23
+ # 0.3.4; set_min_size/set_max_size, the dict-tree TreeView, the
24
+ # binary Image protocol, TopLevel window-control options to 0.2.0.)
25
+ "pgwidgets-js>=0.4.1",
25
26
  "websockets>=12",
26
27
  ]
27
28
  keywords = ["widgets", "ui", "gui", "websocket", "browser"]
@@ -31,6 +32,7 @@ classifiers = [
31
32
  "Programming Language :: Python :: 3",
32
33
  "Programming Language :: Python :: 3.12",
33
34
  "Programming Language :: Python :: 3.13",
35
+ "Programming Language :: Python :: 3.14",
34
36
  "Topic :: Software Development :: User Interfaces",
35
37
  ]
36
38
 
@@ -5,6 +5,8 @@ replayed on connect), which is exactly the case that used to crash callers
5
5
  that queried refs during construction.
6
6
  """
7
7
 
8
+ import pytest
9
+
8
10
  from pgwidgets.sync.Widgets import TextSource
9
11
  from pgwidgets.text_model import TextBufferRef
10
12
 
@@ -159,3 +161,56 @@ def test_reconstruct_pushes_full_state():
159
161
  assert sess.sent[0][1][0] == "abcdef"
160
162
  assert "create_tag" in methods
161
163
  assert "_restoreTagIntervals" in methods
164
+
165
+
166
+ def test_scroll_alignment_rides_along_with_the_offset():
167
+ """A caller can ask for the target line to be centered rather than
168
+ merely brought into view."""
169
+ tw = _ts()
170
+ tw.insert_text(tw.get_ref_end(), "l0\nl1\nl2")
171
+ sess = tw._session
172
+ sess.sent.clear()
173
+
174
+ tw.scroll_to_lineno(2, align='center')
175
+ tw.scroll_to_ref(tw.get_ref_line_start(1), align='top')
176
+ tw.scroll_to_lineno(0)
177
+
178
+ calls = [m[1] for m in sess.sent if m[0] == "_scrollToOffset"]
179
+ assert calls == [[6, 'center'], [3, 'top'], [0, 'nearest']]
180
+
181
+
182
+ def test_an_unknown_alignment_is_rejected():
183
+ tw = _ts()
184
+ with pytest.raises(ValueError):
185
+ tw.scroll_to_lineno(0, align='middle')
186
+
187
+
188
+ def test_cursor_style_is_pushed_and_remembered():
189
+ tw = _ts()
190
+ sess = tw._session
191
+ assert tw.get_cursor_style() == ('line', None)
192
+ sess.sent.clear()
193
+
194
+ tw.set_cursor_style('block', color='indianred')
195
+
196
+ assert ("set_cursor_style", ['block', 'indianred']) in [
197
+ (m[0], m[1]) for m in sess.sent]
198
+ assert tw.get_cursor_style() == ('block', 'indianred')
199
+
200
+
201
+ def test_cursor_style_is_replayed_to_a_reconnecting_browser():
202
+ tw = _ts()
203
+ tw.set_cursor_style('block', color='indianred')
204
+ sess = tw._session
205
+ sess.sent.clear()
206
+
207
+ tw._reconstruct_model()
208
+
209
+ assert ("set_cursor_style", ['block', 'indianred']) in [
210
+ (m[0], m[1]) for m in sess.sent]
211
+
212
+
213
+ def test_an_unknown_cursor_style_is_rejected():
214
+ tw = _ts()
215
+ with pytest.raises(ValueError):
216
+ tw.set_cursor_style('underline')
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "0.4.0",
3
- "distance": 0,
4
- "node": "g5481e84d4ee1d988cdd6d7afbf05f4072640d67f",
5
- "dirty": false,
6
- "branch": "main",
7
- "node_date": "2026-08-17"
8
- }