urwid 2.6.0.post0__py3-none-any.whl

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.

Potentially problematic release.


This version of urwid might be problematic. Click here for more details.

Files changed (75) hide show
  1. urwid/__init__.py +333 -0
  2. urwid/canvas.py +1413 -0
  3. urwid/command_map.py +137 -0
  4. urwid/container.py +59 -0
  5. urwid/decoration.py +65 -0
  6. urwid/display/__init__.py +97 -0
  7. urwid/display/_posix_raw_display.py +413 -0
  8. urwid/display/_raw_display_base.py +914 -0
  9. urwid/display/_web.css +12 -0
  10. urwid/display/_web.js +462 -0
  11. urwid/display/_win32.py +171 -0
  12. urwid/display/_win32_raw_display.py +269 -0
  13. urwid/display/common.py +1219 -0
  14. urwid/display/curses.py +690 -0
  15. urwid/display/escape.py +624 -0
  16. urwid/display/html_fragment.py +251 -0
  17. urwid/display/lcd.py +518 -0
  18. urwid/display/raw.py +37 -0
  19. urwid/display/web.py +636 -0
  20. urwid/event_loop/__init__.py +55 -0
  21. urwid/event_loop/abstract_loop.py +175 -0
  22. urwid/event_loop/asyncio_loop.py +231 -0
  23. urwid/event_loop/glib_loop.py +294 -0
  24. urwid/event_loop/main_loop.py +721 -0
  25. urwid/event_loop/select_loop.py +230 -0
  26. urwid/event_loop/tornado_loop.py +206 -0
  27. urwid/event_loop/trio_loop.py +302 -0
  28. urwid/event_loop/twisted_loop.py +269 -0
  29. urwid/event_loop/zmq_loop.py +275 -0
  30. urwid/font.py +695 -0
  31. urwid/graphics.py +96 -0
  32. urwid/highlight.css +19 -0
  33. urwid/listbox.py +1899 -0
  34. urwid/monitored_list.py +522 -0
  35. urwid/numedit.py +376 -0
  36. urwid/signals.py +330 -0
  37. urwid/split_repr.py +130 -0
  38. urwid/str_util.py +358 -0
  39. urwid/text_layout.py +632 -0
  40. urwid/treetools.py +515 -0
  41. urwid/util.py +557 -0
  42. urwid/version.py +16 -0
  43. urwid/vterm.py +1806 -0
  44. urwid/widget/__init__.py +181 -0
  45. urwid/widget/attr_map.py +161 -0
  46. urwid/widget/attr_wrap.py +140 -0
  47. urwid/widget/bar_graph.py +649 -0
  48. urwid/widget/big_text.py +77 -0
  49. urwid/widget/box_adapter.py +126 -0
  50. urwid/widget/columns.py +1145 -0
  51. urwid/widget/constants.py +574 -0
  52. urwid/widget/container.py +227 -0
  53. urwid/widget/divider.py +110 -0
  54. urwid/widget/edit.py +718 -0
  55. urwid/widget/filler.py +403 -0
  56. urwid/widget/frame.py +539 -0
  57. urwid/widget/grid_flow.py +539 -0
  58. urwid/widget/line_box.py +194 -0
  59. urwid/widget/overlay.py +829 -0
  60. urwid/widget/padding.py +597 -0
  61. urwid/widget/pile.py +971 -0
  62. urwid/widget/popup.py +170 -0
  63. urwid/widget/progress_bar.py +141 -0
  64. urwid/widget/scrollable.py +597 -0
  65. urwid/widget/solid_fill.py +44 -0
  66. urwid/widget/text.py +354 -0
  67. urwid/widget/widget.py +852 -0
  68. urwid/widget/widget_decoration.py +166 -0
  69. urwid/widget/wimp.py +792 -0
  70. urwid/wimp.py +23 -0
  71. urwid-2.6.0.post0.dist-info/COPYING +504 -0
  72. urwid-2.6.0.post0.dist-info/METADATA +332 -0
  73. urwid-2.6.0.post0.dist-info/RECORD +75 -0
  74. urwid-2.6.0.post0.dist-info/WHEEL +5 -0
  75. urwid-2.6.0.post0.dist-info/top_level.txt +1 -0
urwid/signals.py ADDED
@@ -0,0 +1,330 @@
1
+ # Urwid signal dispatching
2
+ # Copyright (C) 2004-2012 Ian Ward
3
+ #
4
+ # This library is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU Lesser General Public
6
+ # License as published by the Free Software Foundation; either
7
+ # version 2.1 of the License, or (at your option) any later version.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+ #
18
+ # Urwid web site: https://urwid.org/
19
+
20
+
21
+ from __future__ import annotations
22
+
23
+ import itertools
24
+ import typing
25
+ import warnings
26
+ import weakref
27
+
28
+ if typing.TYPE_CHECKING:
29
+ from collections.abc import Callable, Collection, Container, Hashable, Iterable
30
+
31
+
32
+ class MetaSignals(type):
33
+ """
34
+ register the list of signals in the class variable signals,
35
+ including signals in superclasses.
36
+ """
37
+
38
+ def __init__(cls, name: str, bases: tuple[type, ...], d: dict[str, typing.Any]) -> None:
39
+ signals = d.get("signals", [])
40
+ for superclass in cls.__bases__:
41
+ signals.extend(getattr(superclass, "signals", []))
42
+ signals = list(dict.fromkeys(signals).keys())
43
+ d["signals"] = signals
44
+ register_signal(cls, signals)
45
+ super().__init__(name, bases, d)
46
+
47
+
48
+ def setdefaultattr(obj, name, value):
49
+ # like dict.setdefault() for object attributes
50
+ if hasattr(obj, name):
51
+ return getattr(obj, name)
52
+ setattr(obj, name, value)
53
+ return value
54
+
55
+
56
+ class Key:
57
+ """
58
+ Minimal class, whose only purpose is to produce objects with a
59
+ unique hash
60
+ """
61
+
62
+ __slots__ = ()
63
+
64
+
65
+ class Signals:
66
+ _signal_attr = "_urwid_signals" # attribute to attach to signal senders
67
+
68
+ def __init__(self):
69
+ self._supported = {}
70
+
71
+ def register(self, sig_cls, signals: Container[Hashable]) -> None:
72
+ """
73
+ :param sig_cls: the class of an object that will be sending signals
74
+ :type sig_cls: class
75
+ :param signals: a list of signals that may be sent, typically each
76
+ signal is represented by a string
77
+ :type signals: signal names
78
+
79
+ This function must be called for a class before connecting any
80
+ signal callbacks or emitting any signals from that class' objects
81
+ """
82
+ self._supported[sig_cls] = signals
83
+
84
+ def connect(
85
+ self,
86
+ obj,
87
+ name: Hashable,
88
+ callback: Callable[..., typing.Any],
89
+ user_arg: typing.Any = None,
90
+ *,
91
+ weak_args: Iterable[typing.Any] = (),
92
+ user_args: Iterable[typing.Any] = (),
93
+ ) -> Key:
94
+ """
95
+ :param obj: the object sending a signal
96
+ :type obj: object
97
+ :param name: the signal to listen for, typically a string
98
+ :type name: signal name
99
+ :param callback: the function to call when that signal is sent
100
+ :type callback: function
101
+ :param user_arg: deprecated additional argument to callback (appended
102
+ after the arguments passed when the signal is
103
+ emitted). If None no arguments will be added.
104
+ Don't use this argument, use user_args instead.
105
+ :param weak_args: additional arguments passed to the callback
106
+ (before any arguments passed when the signal
107
+ is emitted and before any user_args).
108
+
109
+ These arguments are stored as weak references
110
+ (but converted back into their original value
111
+ before passing them to callback) to prevent
112
+ any objects referenced (indirectly) from
113
+ weak_args from being kept alive just because
114
+ they are referenced by this signal handler.
115
+
116
+ Use this argument only as a keyword argument,
117
+ since user_arg might be removed in the future.
118
+ :type weak_args: iterable
119
+ :param user_args: additional arguments to pass to the callback,
120
+ (before any arguments passed when the signal
121
+ is emitted but after any weak_args).
122
+
123
+ Use this argument only as a keyword argument,
124
+ since user_arg might be removed in the future.
125
+ :type user_args: iterable
126
+
127
+ When a matching signal is sent, callback will be called. The
128
+ arguments it receives will be the user_args passed at connect
129
+ time (as individual arguments) followed by all the positional
130
+ parameters sent with the signal.
131
+
132
+ As an example of using weak_args, consider the following snippet:
133
+
134
+ >>> import urwid
135
+ >>> debug = urwid.Text('')
136
+ >>> def handler(widget, newtext):
137
+ ... debug.set_text("Edit widget changed to %s" % newtext)
138
+ >>> edit = urwid.Edit('')
139
+ >>> key = urwid.connect_signal(edit, 'change', handler)
140
+
141
+ If you now build some interface using "edit" and "debug", the
142
+ "debug" widget will show whatever you type in the "edit" widget.
143
+ However, if you remove all references to the "debug" widget, it
144
+ will still be kept alive by the signal handler. This because the
145
+ signal handler is a closure that (implicitly) references the
146
+ "edit" widget. If you want to allow the "debug" widget to be
147
+ garbage collected, you can create a "fake" or "weak" closure
148
+ (it's not really a closure, since it doesn't reference any
149
+ outside variables, so it's just a dynamic function):
150
+
151
+ >>> debug = urwid.Text('')
152
+ >>> def handler(weak_debug, widget, newtext):
153
+ ... weak_debug.set_text("Edit widget changed to %s" % newtext)
154
+ >>> edit = urwid.Edit('')
155
+ >>> key = urwid.connect_signal(edit, 'change', handler, weak_args=[debug])
156
+
157
+ Here the weak_debug parameter in print_debug is the value passed
158
+ in the weak_args list to connect_signal. Note that the
159
+ weak_debug value passed is not a weak reference anymore, the
160
+ signals code transparently dereferences the weakref parameter
161
+ before passing it to print_debug.
162
+
163
+ Returns a key associated by this signal handler, which can be
164
+ used to disconnect the signal later on using
165
+ urwid.disconnect_signal_by_key. Alternatively, the signal
166
+ handler can also be disconnected by calling
167
+ urwid.disconnect_signal, which doesn't need this key.
168
+ """
169
+ if user_arg is not None:
170
+ warnings.warn(
171
+ "Don't use user_arg argument, use user_args instead.",
172
+ DeprecationWarning,
173
+ stacklevel=2,
174
+ )
175
+
176
+ sig_cls = obj.__class__
177
+ if name not in self._supported.get(sig_cls, ()):
178
+ raise NameError(f"No such signal {name!r} for object {obj!r}")
179
+
180
+ # Just generate an arbitrary (but unique) key
181
+ key = Key()
182
+
183
+ handlers = setdefaultattr(obj, self._signal_attr, {}).setdefault(name, [])
184
+
185
+ # Remove the signal handler when any of the weakref'd arguments
186
+ # are garbage collected. Note that this means that the handlers
187
+ # dictionary can be modified _at any time_, so it should never
188
+ # be iterated directly (e.g. iterate only over .keys() and
189
+ # .items(), never over .iterkeys(), .iteritems() or the object
190
+ # itself).
191
+ # We let the callback keep a weakref to the object as well, to
192
+ # prevent a circular reference between the handler and the
193
+ # object (via the weakrefs, which keep strong references to
194
+ # their callbacks) from existing.
195
+ obj_weak = weakref.ref(obj)
196
+
197
+ def weakref_callback(weakref): # pylint: disable=redefined-outer-name # bad, but not changing API
198
+ o = obj_weak()
199
+ if o:
200
+ self.disconnect_by_key(o, name, key)
201
+
202
+ user_args = self._prepare_user_args(weak_args, user_args, weakref_callback)
203
+ handlers.append((key, callback, user_arg, user_args))
204
+
205
+ return key
206
+
207
+ def _prepare_user_args(
208
+ self,
209
+ weak_args: Iterable[typing.Any] = (),
210
+ user_args: Iterable[typing.Any] = (),
211
+ callback: Callable[..., typing.Any] | None = None,
212
+ ) -> tuple[Collection[weakref.ReferenceType], Collection[typing.Any]]:
213
+ # Turn weak_args into weakrefs and prepend them to user_args
214
+ w_args = tuple(weakref.ref(w_arg, callback) for w_arg in weak_args)
215
+ args = tuple(user_args) or ()
216
+ return (w_args, args)
217
+
218
+ def disconnect(
219
+ self,
220
+ obj,
221
+ name: Hashable,
222
+ callback: Callable[..., typing.Any],
223
+ user_arg: typing.Any = None,
224
+ *,
225
+ weak_args: Iterable[typing.Any] = (),
226
+ user_args: Iterable[typing.Any] = (),
227
+ ) -> None:
228
+ """
229
+ :param obj: the object to disconnect the signal from
230
+ :type obj: object
231
+ :param name: the signal to disconnect, typically a string
232
+ :type name: signal name
233
+ :param callback: the callback function passed to connect_signal
234
+ :type callback: function
235
+ :param user_arg: the user_arg parameter passed to connect_signal
236
+ :param weak_args: the weak_args parameter passed to connect_signal
237
+ :param user_args: the weak_args parameter passed to connect_signal
238
+
239
+ This function will remove a callback from the list connected
240
+ to a signal with connect_signal(). The arguments passed should
241
+ be exactly the same as those passed to connect_signal().
242
+
243
+ If the callback is not connected or already disconnected, this
244
+ function will simply do nothing.
245
+ """
246
+ signals = setdefaultattr(obj, self._signal_attr, {})
247
+ if name not in signals:
248
+ return None
249
+
250
+ handlers = signals[name]
251
+
252
+ # Do the same processing as in connect, so we can compare the
253
+ # resulting tuple.
254
+ user_args = self._prepare_user_args(weak_args, user_args)
255
+
256
+ # Remove the given handler
257
+ for h in handlers:
258
+ if h[1:] == (callback, user_arg, user_args):
259
+ return self.disconnect_by_key(obj, name, h[0])
260
+ return None
261
+
262
+ def disconnect_by_key(self, obj, name: Hashable, key: Key) -> None:
263
+ """
264
+ :param obj: the object to disconnect the signal from
265
+ :type obj: object
266
+ :param name: the signal to disconnect, typically a string
267
+ :type name: signal name
268
+ :param key: the key for this signal handler, as returned by
269
+ connect_signal().
270
+ :type key: Key
271
+
272
+ This function will remove a callback from the list connected
273
+ to a signal with connect_signal(). The key passed should be the
274
+ value returned by connect_signal().
275
+
276
+ If the callback is not connected or already disconnected, this
277
+ function will simply do nothing.
278
+ """
279
+ handlers = setdefaultattr(obj, self._signal_attr, {}).get(name, [])
280
+ handlers[:] = [h for h in handlers if h[0] is not key]
281
+
282
+ def emit(self, obj, name: Hashable, *args) -> bool:
283
+ """
284
+ :param obj: the object sending a signal
285
+ :type obj: object
286
+ :param name: the signal to send, typically a string
287
+ :type name: signal name
288
+ :param args: zero or more positional arguments to pass to the signal callback functions
289
+
290
+ This function calls each of the callbacks connected to this signal
291
+ with the args arguments as positional parameters.
292
+
293
+ This function returns True if any of the callbacks returned True.
294
+ """
295
+ result = False
296
+ handlers = getattr(obj, self._signal_attr, {}).get(name, [])
297
+ for _key, callback, user_arg, (weak_args, user_args) in handlers:
298
+ result |= self._call_callback(callback, user_arg, weak_args, user_args, args)
299
+ return result
300
+
301
+ def _call_callback(
302
+ self,
303
+ callback,
304
+ user_arg: typing.Any,
305
+ weak_args: Collection[weakref.ReferenceType],
306
+ user_args: Collection[typing.Any],
307
+ emit_args: Iterable[typing.Any],
308
+ ) -> bool:
309
+ args_to_pass = []
310
+ for w_arg in weak_args:
311
+ real_arg = w_arg()
312
+ if real_arg is not None:
313
+ args_to_pass.append(real_arg)
314
+ else:
315
+ # de-referenced
316
+ return False
317
+
318
+ # The deprecated user_arg argument was added to the end
319
+ # instead of the beginning.
320
+ args = itertools.chain(args_to_pass, user_args, emit_args, (user_arg,) if user_arg is not None else ())
321
+
322
+ return bool(callback(*args))
323
+
324
+
325
+ _signals = Signals()
326
+ emit_signal = _signals.emit
327
+ register_signal = _signals.register
328
+ connect_signal = _signals.connect
329
+ disconnect_signal = _signals.disconnect
330
+ disconnect_signal_by_key = _signals.disconnect_by_key
urwid/split_repr.py ADDED
@@ -0,0 +1,130 @@
1
+ # Urwid split_repr helper functions
2
+ # Copyright (C) 2004-2011 Ian Ward
3
+ #
4
+ # This library is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU Lesser General Public
6
+ # License as published by the Free Software Foundation; either
7
+ # version 2.1 of the License, or (at your option) any later version.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+ #
18
+ # Urwid web site: https://urwid.org/
19
+
20
+
21
+ from __future__ import annotations
22
+
23
+ from inspect import getfullargspec
24
+
25
+
26
+ def split_repr(self):
27
+ """
28
+ Return a helpful description of the object using
29
+ self._repr_words() and self._repr_attrs() to add
30
+ to the description. This function may be used by
31
+ adding code to your class like this:
32
+
33
+ >>> class Foo(object):
34
+ ... __repr__ = split_repr
35
+ ... def _repr_words(self):
36
+ ... return ["words", "here"]
37
+ ... def _repr_attrs(self):
38
+ ... return {'attrs': "appear too"}
39
+ >>> Foo()
40
+ <Foo words here attrs='appear too'>
41
+ >>> class Bar(Foo):
42
+ ... def _repr_words(self):
43
+ ... return Foo._repr_words(self) + ["too"]
44
+ ... def _repr_attrs(self):
45
+ ... return dict(Foo._repr_attrs(self), barttr=42)
46
+ >>> Bar()
47
+ <Bar words here too attrs='appear too' barttr=42>
48
+ """
49
+ alist = sorted((str(k), normalize_repr(v)) for k, v in self._repr_attrs().items())
50
+
51
+ words = self._repr_words()
52
+ if not words and not alist:
53
+ # if we're just going to print the classname fall back
54
+ # to the previous __repr__ implementation instead
55
+ return super(self.__class__, self).__repr__()
56
+ if words and alist:
57
+ words.append("")
58
+ return f"<{self.__class__.__name__} {' '.join(words) + ' '.join([f'{k}={v}' for k, v in alist])}>"
59
+
60
+
61
+ def normalize_repr(v):
62
+ """
63
+ Return dictionary repr sorted by keys, leave others unchanged
64
+
65
+ >>> normalize_repr({1:2,3:4,5:6,7:8})
66
+ '{1: 2, 3: 4, 5: 6, 7: 8}'
67
+ >>> normalize_repr('foo')
68
+ "'foo'"
69
+ """
70
+ if isinstance(v, dict):
71
+ items = sorted((repr(k), repr(v)) for k, v in v.items())
72
+
73
+ return f"{{{', '.join(f'{k}: {v}' for k, v in items)}}}"
74
+
75
+ return repr(v)
76
+
77
+
78
+ def remove_defaults(d, fn):
79
+ """
80
+ Remove keys in d that are set to the default values from
81
+ fn. This method is used to unclutter the _repr_attrs()
82
+ return value.
83
+
84
+ d will be modified by this function.
85
+
86
+ Returns d.
87
+
88
+ >>> class Foo(object):
89
+ ... def __init__(self, a=1, b=2):
90
+ ... self.values = a, b
91
+ ... __repr__ = split_repr
92
+ ... def _repr_words(self):
93
+ ... return ["object"]
94
+ ... def _repr_attrs(self):
95
+ ... d = dict(a=self.values[0], b=self.values[1])
96
+ ... return remove_defaults(d, Foo.__init__)
97
+ >>> Foo(42, 100)
98
+ <Foo object a=42 b=100>
99
+ >>> Foo(10, 2)
100
+ <Foo object a=10>
101
+ >>> Foo()
102
+ <Foo object>
103
+ """
104
+ args, varargs, varkw, defaults, _, _, _ = getfullargspec(fn)
105
+
106
+ # ignore *varargs and **kwargs
107
+ if varkw:
108
+ del args[-1]
109
+ if varargs:
110
+ del args[-1]
111
+
112
+ # create a dictionary of args with default values
113
+ ddict = dict(zip(args[len(args) - len(defaults) :], defaults))
114
+
115
+ for k in list(d.keys()):
116
+ if k in ddict and ddict[k] == d[k]:
117
+ # remove values that match their defaults
118
+ del d[k]
119
+
120
+ return d
121
+
122
+
123
+ def _test():
124
+ import doctest
125
+
126
+ doctest.testmod()
127
+
128
+
129
+ if __name__ == "__main__":
130
+ _test()