Skip to content

Commit e1d95af

Browse files
committed
Replaces tabs with spaces in tests, and updates the terminal.py file.
1 parent 4ef8c10 commit e1d95af

File tree

8 files changed

+739
-823
lines changed

8 files changed

+739
-823
lines changed

flika/app/syntax.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,14 +112,12 @@ def highlightBlock(self, text):
112112
"""
113113
# Do other syntax formatting
114114
for expression, nth, format in self.rules:
115-
index = expression.indexIn(text, 0)
116-
117-
while index >= 0:
118-
# We actually want the index of the nth match
119-
index = expression.pos(nth)
120-
length = len(expression.cap(nth))
115+
match = expression.match(text, 0)
116+
while match.hasMatch():
117+
index = match.capturedStart()
118+
length = match.capturedLength()
121119
self.setFormat(index, length, format)
122-
index = expression.indexIn(text, index + length)
120+
match = expression.match(text, index + length)
123121

124122
self.setCurrentBlockState(0)
125123

flika/app/terminal.py

Lines changed: 79 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,49 @@
22
import sys
33
import atexit
44
from contextlib import contextmanager
5-
from distutils.version import LooseVersion
6-
from qtpy import QtCore, QtWidgets # must import these first, to set up Qt properly
5+
from typing import Any, Dict, Optional, Type, Union
6+
7+
# Import Qt functionality through qtpy for abstraction
8+
from qtpy import QtCore, QtWidgets
9+
10+
# IPython imports
711
import IPython
812
from IPython.core.usage import default_banner
13+
from IPython import get_ipython
14+
15+
# ZMQ imports
916
from zmq import ZMQError
1017
from zmq.eventloop import ioloop
1118
from zmq.eventloop.zmqstream import ZMQStream
12-
from ..version import __version__
13-
1419

15-
from IPython import get_ipython
20+
# Import version
21+
from ..version import __version__
1622

23+
# Import traitlets
1724
from traitlets import TraitError
1825

26+
# Import ipykernel components
1927
from ipykernel.connect import _find_connection_file as find_connection_file
2028
from ipykernel.kernelbase import Kernel
2129
from ipykernel.kernelapp import IPKernelApp
2230
from ipykernel.iostream import OutStream
2331
from ipykernel.inprocess.ipkernel import InProcessInteractiveShell
2432
from ipykernel.connect import get_connection_file
2533

34+
# Import qtconsole components
2635
from qtconsole.client import QtKernelClient
2736
from qtconsole.manager import QtKernelManager
2837
from qtconsole.inprocess import QtInProcessKernelManager
2938
from qtconsole.rich_jupyter_widget import RichJupyterWidget as RichIPythonWidget
3039

3140

32-
33-
34-
def in_process_console(console_class=RichIPythonWidget, **kwargs):
41+
def in_process_console(console_class: Type[RichIPythonWidget] = RichIPythonWidget, **kwargs: Any) -> RichIPythonWidget:
3542
"""Create a console widget, connected to an in-process Kernel
3643
37-
This only works on IPython v 0.13 and above
38-
3944
Parameters:
40-
console_class : The class of the console widget to create
41-
kwargs : Extra variables to put into the namespace
45+
console_class: The class of the console widget to create
46+
kwargs: Extra variables to put into the namespace
4247
"""
43-
4448
km = QtInProcessKernelManager()
4549
km.start_kernel()
4650

@@ -58,15 +62,13 @@ def in_process_console(console_class=RichIPythonWidget, **kwargs):
5862
return control
5963

6064

61-
def connected_console(console_class=RichIPythonWidget, **kwargs):
65+
def connected_console(console_class: Type[RichIPythonWidget] = RichIPythonWidget, **kwargs: Any) -> RichIPythonWidget:
6266
"""Create a console widget, connected to another kernel running in
6367
the current process
6468
65-
This only works on IPython v1.0 and above
66-
6769
Parameters:
68-
console_class : The class of the console widget to create
69-
kwargs : Extra variables to put into the namespace
70+
console_class: The class of the console widget to create
71+
kwargs: Extra variables to put into the namespace
7072
"""
7173
shell = get_ipython()
7274
if shell is None:
@@ -84,89 +86,27 @@ def connected_console(console_class=RichIPythonWidget, **kwargs):
8486

8587

8688
class Terminal(RichIPythonWidget):
87-
def __init__(self, **kwargs):
88-
super(Terminal, self).__init__(**kwargs)
89-
89+
"""IPython terminal widget for embedding in the application."""
90+
91+
def __init__(self, **kwargs: Any) -> None:
92+
super().__init__(**kwargs)
9093
self.setAcceptDrops(True)
9194
self.shell = None
9295

9396
@property
94-
def namespace(self):
97+
def namespace(self) -> Optional[Dict[str, Any]]:
98+
"""Return the namespace dictionary of the shell."""
9599
return self.shell.user_ns if self.shell is not None else None
96100

97-
def update_namespace(self, kwargs):
101+
def update_namespace(self, kwargs: Dict[str, Any]) -> None:
102+
"""Update the namespace with the given variables."""
98103
if self.shell is not None:
99104
self.shell.push(kwargs)
100105

101106

102-
103-
# Works for IPython 0.12, 0.13
104-
def default_kernel_app():
105-
""" Return a configured IPKernelApp """
106-
107-
def event_loop(kernel):
108-
""" Non-blocking qt event loop."""
109-
kernel.timer = QtCore.QTimer()
110-
kernel.timer.timeout.connect(kernel.do_one_iteration)
111-
kernel.timer.start(1000 * kernel._poll_interval)
112-
113-
app = IPKernelApp.instance()
114-
try:
115-
app.initialize(['python', '--pylab=qt'])
116-
except ZMQError:
117-
pass # already set up
118-
119-
app.kernel.eventloop = event_loop
120-
121-
try:
122-
app.start()
123-
except RuntimeError: # already started
124-
pass
125-
126-
return app
127-
128-
129-
def default_manager(kernel):
130-
""" Return a configured QtKernelManager
131-
132-
Parameters:
133-
kernel: An IPKernelApp instance
134-
"""
135-
connection_file = find_connection_file(kernel.connection_file)
136-
manager = QtKernelManager(connection_file=connection_file)
137-
manager.load_connection_file()
138-
manager.start_channels()
139-
atexit.register(manager.cleanup_connection_file)
140-
return manager
141-
142-
143-
def _ipython_terminal_1(**kwargs):
144-
""" Used for IPython v0.13, v0.12
145-
"""
146-
kernel_app = default_kernel_app()
147-
manager = default_manager(kernel_app)
148-
149-
try: # IPython v0.13
150-
widget = Terminal(gui_completion='droplist')
151-
except TraitError: # IPython v0.12
152-
widget = Terminal(gui_completion=True)
153-
widget.kernel_manager = manager
154-
widget.shell = kernel_app.shell
155-
156-
# update namespace
157-
widget.update_namespace(kwargs)
158-
159-
# IPython v0.12 turns on MPL interactive. Turn it back off
160-
import matplotlib
161-
matplotlib.interactive(False)
162-
return widget
163-
164-
165-
# works on IPython v0.13, v0.14
166107
@contextmanager
167-
def redirect_output(session, pub_socket):
168-
"""Prevent any of the widgets from permanently hijacking stdout or
169-
stderr"""
108+
def redirect_output(session: Any, pub_socket: Any) -> None:
109+
"""Prevent any of the widgets from permanently hijacking stdout or stderr"""
170110
sys.stdout = OutStream(session, pub_socket, u'stdout')
171111
sys.stderr = OutStream(session, pub_socket, u'stderr')
172112
try:
@@ -176,144 +116,122 @@ def redirect_output(session, pub_socket):
176116
sys.stderr = sys.__stderr__
177117

178118

179-
def non_blocking_eventloop(kernel):
119+
def non_blocking_eventloop(kernel: Kernel) -> None:
120+
"""Set up a non-blocking event loop for the kernel."""
180121
kernel.timer = QtCore.QTimer()
181122
kernel.timer.timeout.connect(kernel.do_one_iteration)
182123
kernel.timer.start(1000 * kernel._poll_interval)
183124

184125

185126
class EmbeddedQtKernel(Kernel):
127+
"""Kernel class that embeds the Qt event loop."""
186128

187-
def __init__(self, *args, **kwargs):
188-
super(EmbeddedQtKernel, self).__init__(*args, **kwargs)
129+
def __init__(self, *args: Any, **kwargs: Any) -> None:
130+
super().__init__(*args, **kwargs)
189131
self.eventloop = non_blocking_eventloop
190132

191-
def do_one_iteration(self):
133+
def do_one_iteration(self) -> None:
192134
with redirect_output(self.session, self.iopub_socket):
193-
super(EmbeddedQtKernel, self).do_one_iteration()
135+
super().do_one_iteration()
194136

195-
def execute_request(self, stream, ident, parent):
137+
def execute_request(self, stream: Any, ident: Any, parent: Any) -> None:
196138
with redirect_output(self.session, self.iopub_socket):
197-
super(EmbeddedQtKernel, self).execute_request(
198-
stream, ident, parent)
139+
super().execute_request(stream, ident, parent)
199140

200141

201142
class EmbeddedQtKernelApp(IPKernelApp):
143+
"""Application class for embedded Qt kernel."""
202144

203-
def init_kernel(self):
145+
def init_kernel(self) -> None:
204146
shell_stream = ZMQStream(self.shell_socket)
205-
kernel = EmbeddedQtKernel(config=self.config, session=self.session,
206-
shell_streams=[shell_stream],
207-
iopub_socket=self.iopub_socket,
208-
stdin_socket=self.stdin_socket,
209-
log=self.log,
210-
profile_dir=self.profile_dir,
211-
)
147+
kernel = EmbeddedQtKernel(
148+
config=self.config,
149+
session=self.session,
150+
shell_streams=[shell_stream],
151+
iopub_socket=self.iopub_socket,
152+
stdin_socket=self.stdin_socket,
153+
log=self.log,
154+
profile_dir=self.profile_dir,
155+
)
212156
self.kernel = kernel
213157
kernel.record_ports(self.ports)
214158

215-
def start(self):
216-
# handoff between IOLoop and QApplication event loops
159+
def start(self) -> None:
160+
# Handoff between IOLoop and QApplication event loops
217161
loop = ioloop.IOLoop.instance()
218-
# We used to have a value of 0ms as the second argument
219-
# (callback_time) in the following call, but this caused the
220-
# application to hang on certain setups, so use 1ms instead.
162+
# Use 1ms callback time to prevent application hanging
221163
stopper = ioloop.PeriodicCallback(loop.stop, 1, loop)
222164
self.timer = QtCore.QTimer()
223165
self.timer.timeout.connect(loop.start)
224166
self.timer.start(100)
225167
stopper.start()
226-
super(EmbeddedQtKernelApp, self).start()
168+
super().start()
227169

228170

229171
class EmbeddedIPythonWidget(Terminal):
172+
"""Modern embedded IPython widget."""
173+
230174
gui_completion = 'droplist'
231175

232-
def __init__(self, **kwargs):
233-
super(EmbeddedIPythonWidget, self).__init__(**kwargs)
176+
def __init__(self, **kwargs: Any) -> None:
177+
super().__init__(**kwargs)
234178
self._init_kernel_app()
235179
self._init_kernel_manager()
236180
self.update_namespace(kwargs)
237181

238-
def _init_kernel_app(self):
182+
def _init_kernel_app(self) -> None:
239183
app = EmbeddedQtKernelApp.instance()
240184
try:
241185
app.initialize([])
242186
except ZMQError:
243-
pass # already set up
187+
pass # Already set up
244188
try:
245189
app.start()
246-
except RuntimeError: # already started
190+
except RuntimeError: # Already started
247191
pass
248192
self.app = app
249193
self.shell = app.shell
250194

251-
def _init_kernel_manager(self):
195+
def _init_kernel_manager(self) -> None:
252196
connection_file = find_connection_file(self.app.connection_file)
253197
manager = QtKernelManager(connection_file=connection_file)
254198
manager.load_connection_file()
255199
manager.start_channels()
256200
atexit.register(manager.cleanup_connection_file)
257201
self.kernel_manager = manager
258202

259-
def update_namespace(self, ns):
203+
def update_namespace(self, ns: Dict[str, Any]) -> None:
260204
self.app.shell.user_ns.update(ns)
261205

262206

263-
def _ipython_terminal_2(**kwargs):
264-
"""Used for IPython v0.13, v0.14"""
265-
return EmbeddedIPythonWidget(**kwargs)
266-
207+
def ipython_terminal(banner: str = '', **kwargs: Any) -> Terminal:
208+
"""Return a qt widget which embeds an IPython interpreter.
267209
268-
def _ipython_terminal_3(**kwargs):
269-
"""Used for IPython v1.0 and beyond
210+
Extra keywords will be added to the namespace of the shell.
270211
271212
Parameters:
272-
kwargs: Keywords which are passed to Widget init,
273-
and which are also passed to the current namespace
213+
banner: Text to display at the top of the terminal
214+
kwargs: Extra variables to be added to the namespace
215+
216+
Returns:
217+
Terminal widget with embedded IPython interpreter
274218
"""
275-
# see IPython/docs/examples/frontends/inprocess_qtconsole.p
219+
Terminal.banner = f"""flika version {__version__}
220+
221+
{banner}
222+
223+
"""
276224

225+
# In modern Python with recent IPython, we only need the in-process console
226+
# (version checking logic simplified for Python 3.13)
277227
shell = get_ipython()
278228
if shell is None or isinstance(shell, InProcessInteractiveShell):
279229
return in_process_console(console_class=Terminal, **kwargs)
280230
return connected_console(console_class=Terminal, **kwargs)
281231

282232

283-
def ipython_terminal(banner='', **kwargs):
284-
""" Return a qt widget which embed an IPython interpreter.
285-
286-
Extra keywords will be added to the namespace of the shell
287-
288-
Parameters:
289-
kwargs (QWidget): Extra variables to be added to the namespace
290-
291-
"""
292-
Terminal.banner = '''flika version {}
293-
294-
{}
295-
296-
'''.format(__version__, banner)
297-
298-
from distutils.version import LooseVersion
299-
import IPython
300-
ver = LooseVersion(IPython.__version__)
301-
v1_0 = LooseVersion('1.0')
302-
v0_12 = LooseVersion('0.12')
303-
v0_13 = LooseVersion('0.13')
304-
305-
if ver >= v1_0:
306-
return _ipython_terminal_3(**kwargs)
307-
if ver >= v0_13:
308-
return _ipython_terminal_2(**kwargs)
309-
if ver >= v0_12:
310-
return _ipython_terminal_1(**kwargs)
311-
312-
raise RuntimeError("Terminal requires IPython >= 0.12")
313-
314-
315233
if __name__ == '__main__':
316234
app = QtWidgets.QApplication([])
317235
new_widget = ipython_terminal()
318236
new_widget.show()
319-
app.exec_()
237+
app.exec() # Using exec() in Python 3 (not exec_())

0 commit comments

Comments
 (0)