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
@@ -0,0 +1,230 @@
1
+ # Urwid main loop code
2
+ # Copyright (C) 2004-2012 Ian Ward
3
+ # Copyright (C) 2008 Walter Mundt
4
+ # Copyright (C) 2009 Andrew Psaltis
5
+ #
6
+ # This library is free software; you can redistribute it and/or
7
+ # modify it under the terms of the GNU Lesser General Public
8
+ # License as published by the Free Software Foundation; either
9
+ # version 2.1 of the License, or (at your option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ # Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #
20
+ # Urwid web site: https://urwid.org/
21
+
22
+ """Select based urwid EventLoop implementation."""
23
+
24
+ from __future__ import annotations
25
+
26
+ import contextlib
27
+ import heapq
28
+ import logging
29
+ import selectors
30
+ import time
31
+ import typing
32
+ from contextlib import suppress
33
+ from itertools import count
34
+
35
+ from .abstract_loop import EventLoop, ExitMainLoop
36
+
37
+ if typing.TYPE_CHECKING:
38
+ from collections.abc import Callable, Iterator
39
+ from concurrent.futures import Executor, Future
40
+
41
+ from typing_extensions import Literal, ParamSpec
42
+
43
+ _T = typing.TypeVar("_T")
44
+ _Spec = ParamSpec("_Spec")
45
+
46
+ __all__ = ("SelectEventLoop",)
47
+
48
+
49
+ class SelectEventLoop(EventLoop):
50
+ """
51
+ Event loop based on :func:`selectors.DefaultSelector.select`
52
+ """
53
+
54
+ def __init__(self) -> None:
55
+ super().__init__()
56
+ self.logger = logging.getLogger(__name__).getChild(self.__class__.__name__)
57
+ self._alarms: list[tuple[float, int, Callable[[], typing.Any]]] = []
58
+ self._watch_files: dict[int, Callable[[], typing.Any]] = {}
59
+ self._idle_handle: int = 0
60
+ self._idle_callbacks: dict[int, Callable[[], typing.Any]] = {}
61
+ self._tie_break: Iterator[int] = count()
62
+ self._did_something: bool = False
63
+
64
+ def run_in_executor(
65
+ self,
66
+ executor: Executor,
67
+ func: Callable[_Spec, _T],
68
+ *args: _Spec.args,
69
+ **kwargs: _Spec.kwargs,
70
+ ) -> Future[_T]:
71
+ """Run callable in executor.
72
+
73
+ :param executor: Executor to use for running the function
74
+ :type executor: concurrent.futures.Executor
75
+ :param func: function to call
76
+ :type func: Callable
77
+ :param args: positional arguments to function
78
+ :type args: object
79
+ :param kwargs: keyword arguments to function
80
+ :type kwargs: object
81
+ :return: future object for the function call outcome.
82
+ :rtype: concurrent.futures.Future
83
+ """
84
+ return executor.submit(func, *args, **kwargs)
85
+
86
+ def alarm(
87
+ self,
88
+ seconds: float,
89
+ callback: Callable[[], typing.Any],
90
+ ) -> tuple[float, int, Callable[[], typing.Any]]:
91
+ """
92
+ Call callback() a given time from now. No parameters are
93
+ passed to callback.
94
+
95
+ Returns a handle that may be passed to remove_alarm()
96
+
97
+ seconds -- floating point time to wait before calling callback
98
+ callback -- function to call from event loop
99
+ """
100
+ tm = time.time() + seconds
101
+ handle = (tm, next(self._tie_break), callback)
102
+ heapq.heappush(self._alarms, handle)
103
+ return handle
104
+
105
+ def remove_alarm(self, handle: tuple[float, int, Callable[[], typing.Any]]) -> bool:
106
+ """
107
+ Remove an alarm.
108
+
109
+ Returns True if the alarm exists, False otherwise
110
+ """
111
+ try:
112
+ self._alarms.remove(handle)
113
+ heapq.heapify(self._alarms)
114
+
115
+ except ValueError:
116
+ return False
117
+
118
+ return True
119
+
120
+ def watch_file(self, fd: int, callback: Callable[[], typing.Any]) -> int:
121
+ """
122
+ Call callback() when fd has some data to read. No parameters
123
+ are passed to callback.
124
+
125
+ Returns a handle that may be passed to remove_watch_file()
126
+
127
+ fd -- file descriptor to watch for input
128
+ callback -- function to call when input is available
129
+ """
130
+ self._watch_files[fd] = callback
131
+ return fd
132
+
133
+ def remove_watch_file(self, handle: int) -> bool:
134
+ """
135
+ Remove an input file.
136
+
137
+ Returns True if the input file exists, False otherwise
138
+ """
139
+ if handle in self._watch_files:
140
+ del self._watch_files[handle]
141
+ return True
142
+ return False
143
+
144
+ def enter_idle(self, callback: Callable[[], typing.Any]) -> int:
145
+ """
146
+ Add a callback for entering idle.
147
+
148
+ Returns a handle that may be passed to remove_idle()
149
+ """
150
+ self._idle_handle += 1
151
+ self._idle_callbacks[self._idle_handle] = callback
152
+ return self._idle_handle
153
+
154
+ def remove_enter_idle(self, handle: int) -> bool:
155
+ """
156
+ Remove an idle callback.
157
+
158
+ Returns True if the handle was removed.
159
+ """
160
+ try:
161
+ del self._idle_callbacks[handle]
162
+ except KeyError:
163
+ return False
164
+ return True
165
+
166
+ def _entering_idle(self) -> None:
167
+ """
168
+ Call all the registered idle callbacks.
169
+ """
170
+ for callback in self._idle_callbacks.values():
171
+ callback()
172
+
173
+ def run(self) -> None:
174
+ """
175
+ Start the event loop. Exit the loop when any callback raises
176
+ an exception. If ExitMainLoop is raised, exit cleanly.
177
+ """
178
+ with contextlib.suppress(ExitMainLoop):
179
+ self._did_something = True
180
+ while True:
181
+ with suppress(InterruptedError):
182
+ self._loop()
183
+
184
+ def _loop(self) -> None:
185
+ """
186
+ A single iteration of the event loop
187
+ """
188
+ tm: float | Literal["idle"] | None = None
189
+
190
+ with selectors.DefaultSelector() as selector:
191
+ for fd, callback in self._watch_files.items():
192
+ selector.register(fd, selectors.EVENT_READ, callback)
193
+
194
+ if self._alarms or self._did_something:
195
+ timeout = 0.0
196
+
197
+ if self._alarms:
198
+ timeout_ = self._alarms[0][0]
199
+ tm = timeout_
200
+ timeout = max(timeout, timeout_ - time.time())
201
+
202
+ if self._did_something and (not self._alarms or (self._alarms and timeout > 0)):
203
+ timeout = 0.0
204
+ tm = "idle"
205
+
206
+ self.logger.debug(f"Waiting for input: timeout={timeout!r}")
207
+ ready = [event for event, _ in selector.select(timeout)]
208
+
209
+ elif self._watch_files:
210
+ self.logger.debug("Waiting for input: timeout")
211
+ ready = [event for event, _ in selector.select()]
212
+ else:
213
+ ready = []
214
+
215
+ if not ready:
216
+ if tm == "idle":
217
+ self.logger.debug("No input, entering IDLE")
218
+ self._entering_idle()
219
+ self._did_something = False
220
+ elif tm is not None:
221
+ # must have been a timeout
222
+ tm, _tie_break, alarm_callback = heapq.heappop(self._alarms)
223
+ self.logger.debug(f"No input in timeout, calling scheduled {alarm_callback!r}")
224
+ alarm_callback()
225
+ self._did_something = True
226
+
227
+ self.logger.debug("Processing input")
228
+ for record in ready:
229
+ record.data()
230
+ self._did_something = True
@@ -0,0 +1,206 @@
1
+ # Urwid main loop code
2
+ # Copyright (C) 2004-2012 Ian Ward
3
+ # Copyright (C) 2008 Walter Mundt
4
+ # Copyright (C) 2009 Andrew Psaltis
5
+ #
6
+ # This library is free software; you can redistribute it and/or
7
+ # modify it under the terms of the GNU Lesser General Public
8
+ # License as published by the Free Software Foundation; either
9
+ # version 2.1 of the License, or (at your option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ # Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public
17
+ # License along with this library; if not, write to the Free Software
18
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #
20
+ # Urwid web site: https://urwid.org/
21
+
22
+ """Tornado IOLoop based urwid EventLoop implementation.
23
+
24
+ Tornado library is required.
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ import functools
30
+ import logging
31
+ import typing
32
+ from contextlib import suppress
33
+
34
+ from tornado import ioloop
35
+
36
+ from .abstract_loop import EventLoop, ExitMainLoop
37
+
38
+ if typing.TYPE_CHECKING:
39
+ import asyncio
40
+ from collections.abc import Callable
41
+ from concurrent.futures import Executor
42
+
43
+ from typing_extensions import Literal, ParamSpec
44
+
45
+ _Spec = ParamSpec("_Spec")
46
+ _T = typing.TypeVar("_T")
47
+
48
+ __all__ = ("TornadoEventLoop",)
49
+
50
+
51
+ class TornadoEventLoop(EventLoop):
52
+ """This is an Urwid-specific event loop to plug into its MainLoop.
53
+ It acts as an adaptor for Tornado's IOLoop which does all
54
+ heavy lifting except idle-callbacks.
55
+ """
56
+
57
+ def __init__(self, loop: ioloop.IOLoop | None = None) -> None:
58
+ super().__init__()
59
+ self.logger = logging.getLogger(__name__).getChild(self.__class__.__name__)
60
+ if loop:
61
+ self._loop: ioloop.IOLoop = loop
62
+ else:
63
+ self._loop = ioloop.IOLoop.current() # TODO(Aleksei): Switch to the asyncio.EventLoop as tornado >= 6.0 !
64
+
65
+ self._pending_alarms: dict[object, int] = {}
66
+ self._watch_handles: dict[int, int] = {} # {<watch_handle> : <file_descriptor>}
67
+ self._max_watch_handle: int = 0
68
+ self._exc: BaseException | None = None
69
+
70
+ self._idle_asyncio_handle: object | None = None
71
+ self._idle_handle: int = 0
72
+ self._idle_callbacks: dict[int, Callable[[], typing.Any]] = {}
73
+
74
+ def _also_call_idle(self, callback: Callable[_Spec, _T]) -> Callable[_Spec, _T]:
75
+ """
76
+ Wrap the callback to also call _entering_idle.
77
+ """
78
+
79
+ @functools.wraps(callback)
80
+ def wrapper(*args: _Spec.args, **kwargs: _Spec.kwargs) -> _T:
81
+ if not self._idle_asyncio_handle:
82
+ self._idle_asyncio_handle = self._loop.call_later(0, self._entering_idle)
83
+ return callback(*args, **kwargs)
84
+
85
+ return wrapper
86
+
87
+ def _entering_idle(self) -> None:
88
+ """
89
+ Call all the registered idle callbacks.
90
+ """
91
+ try:
92
+ for callback in self._idle_callbacks.values():
93
+ callback()
94
+ finally:
95
+ self._idle_asyncio_handle = None
96
+
97
+ def run_in_executor(
98
+ self,
99
+ executor: Executor,
100
+ func: Callable[_Spec, _T],
101
+ *args: _Spec.args,
102
+ ) -> asyncio.Future[_T]:
103
+ """Run callable in executor.
104
+
105
+ :param executor: Executor to use for running the function
106
+ :type executor: concurrent.futures.Executor
107
+ :param func: function to call
108
+ :type func: Callable
109
+ :param args: arguments to function (positional only)
110
+ :type args: object
111
+ :return: future object for the function call outcome.
112
+ :rtype: asyncio.Future
113
+ """
114
+ return self._loop.run_in_executor(executor, func, *args)
115
+
116
+ def alarm(self, seconds: float, callback: Callable[[], typing.Any]):
117
+ @self._also_call_idle
118
+ @functools.wraps(callback)
119
+ def wrapped() -> None:
120
+ with suppress(KeyError):
121
+ del self._pending_alarms[handle]
122
+
123
+ self.handle_exit(callback)()
124
+
125
+ handle = self._loop.add_timeout(self._loop.time() + seconds, wrapped)
126
+ self._pending_alarms[handle] = 1
127
+ return handle
128
+
129
+ def remove_alarm(self, handle: object) -> bool:
130
+ self._loop.remove_timeout(handle)
131
+ try:
132
+ del self._pending_alarms[handle]
133
+ except KeyError:
134
+ return False
135
+
136
+ return True
137
+
138
+ def watch_file(self, fd: int, callback: Callable[[], _T]) -> int:
139
+ @self._also_call_idle
140
+ def handler(_fd: int, _events: int) -> None:
141
+ self.handle_exit(callback)()
142
+
143
+ self._loop.add_handler(fd, handler, ioloop.IOLoop.READ)
144
+ self._max_watch_handle += 1
145
+ handle = self._max_watch_handle
146
+ self._watch_handles[handle] = fd
147
+ return handle
148
+
149
+ def remove_watch_file(self, handle: int) -> bool:
150
+ fd = self._watch_handles.pop(handle, None)
151
+ if fd is None:
152
+ return False
153
+
154
+ self._loop.remove_handler(fd)
155
+ return True
156
+
157
+ def enter_idle(self, callback: Callable[[], typing.Any]) -> int:
158
+ """
159
+ Add a callback for entering idle.
160
+
161
+ Returns a handle that may be passed to remove_idle()
162
+ """
163
+ # XXX there's no such thing as "idle" in most event loops; this fakes
164
+ # it by adding extra callback to the timer and file watch callbacks.
165
+ self._idle_handle += 1
166
+ self._idle_callbacks[self._idle_handle] = callback
167
+ return self._idle_handle
168
+
169
+ def remove_enter_idle(self, handle: int) -> bool:
170
+ """
171
+ Remove an idle callback.
172
+
173
+ Returns True if the handle was removed.
174
+ """
175
+ try:
176
+ del self._idle_callbacks[handle]
177
+ except KeyError:
178
+ return False
179
+ return True
180
+
181
+ def handle_exit(self, f: Callable[_Spec, _T]) -> Callable[_Spec, _T | Literal[False]]:
182
+ @functools.wraps(f)
183
+ def wrapper(*args: _Spec.args, **kwargs: _Spec.kwargs) -> _T | Literal[False]:
184
+ try:
185
+ return f(*args, **kwargs)
186
+ except ExitMainLoop:
187
+ pass # handled later
188
+ except Exception as exc:
189
+ self._exc = exc
190
+
191
+ if self._idle_asyncio_handle:
192
+ # clean it up to prevent old callbacks
193
+ # from messing things up if loop is restarted
194
+ self._loop.remove_timeout(self._idle_asyncio_handle)
195
+ self._idle_asyncio_handle = None
196
+
197
+ self._loop.stop()
198
+ return False
199
+
200
+ return wrapper
201
+
202
+ def run(self) -> None:
203
+ self._loop.start()
204
+ if self._exc:
205
+ exc, self._exc = self._exc, None
206
+ raise exc.with_traceback(exc.__traceback__)