Skip to content

Commit c03006a

Browse files
committed
Merge pull request #248 in LCL/wolframclientforpython from bugfix/406949-better-traceback to release/B12_3_0
* commit 'd4e084fedf2c8baae2ba7d57a0e0e217756a1f9c': PacletInfo.m edited online with Bitbucket improving error message code lint better low level handling of missing python installation SocketListen disabled but left in place for posterity Use SocketListen to evaluate message wrong color scheme for message name using 12.2 for now bumping version removing stdout proxy implementation increase minor version new ZMQ module lazy starts during the function call. removing unfortunate use of the word slave test should not trigger lib installation updating minor version in paclet info introducing 12.3 functions
2 parents ae31bda + d4e084f commit c03006a

11 files changed

Lines changed: 27 additions & 65 deletions

File tree

PacletInfo.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Paclet[
22
Name -> "WolframClientForPython",
33
Version -> "1.1.5",
4-
MathematicaVersion -> "11.3+",
4+
MathematicaVersion -> "12.3+",
55
Loading -> Automatic,
66
Extensions -> {}
77
]

wolframclient/cli/commands/benchmark.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def report(self):
8282
self.table_line()
8383

8484
# running export to do all lazy loadings
85-
binary_deserialize(export(1, target_format = 'wxf'))
85+
binary_deserialize(export(1, target_format="wxf"))
8686

8787
self.table_line("* Binary deserialize")
8888
self.table_line()

wolframclient/cli/commands/start_externalevaluate.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from __future__ import absolute_import, print_function, unicode_literals
22

33
import os
4+
import sys
45

56
from wolframclient.cli.utils import SimpleCommand
67
from wolframclient.utils.api import externalevaluate as ev
8+
from wolframclient.utils.api import zmq
79

810

911
class Command(SimpleCommand):
@@ -19,4 +21,11 @@ def handle(self, port=None, installpath=None, **opts):
1921
if installpath:
2022
os.environ["WOLFRAM_INSTALLATION_DIRECTORY"] = installpath
2123

24+
try:
25+
zmq.Context
26+
except ImportError as e:
27+
print("Error importing zmq: %s. Please install zmq. https://zeromq.org/languages/python/" % e, file=sys.stderr)
28+
sys.stderr.flush()
29+
sys.exit(1)
30+
2231
ev.start_zmq_loop(port=port)

wolframclient/evaluation/kernel/kernelcontroller.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from wolframclient.utils.api import json, os, time, zmq
2020

2121
if six.WINDOWS:
22-
from subprocess import STARTUPINFO, STARTF_USESHOWWINDOW
22+
from subprocess import STARTF_USESHOWWINDOW, STARTUPINFO
2323

2424
__all__ = ["WolframKernelController"]
2525

wolframclient/tests/deserializers/wxf_deserialize.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from wolframclient.utils.datastructures import immutabledict
2222
from wolframclient.utils.tests import TestCase as BaseTestCase
2323

24+
2425
class TestCase(BaseTestCase):
2526
def test_token_dimensions(self):
2627
token = WXFToken(None)
@@ -200,7 +201,7 @@ def test_compressed_input(self):
200201
self.assertEqual(expr, res)
201202

202203
def test_nested_associations(self):
203-
expr = immutabledict((('a', 2), ('a', 3)))
204+
expr = immutabledict((("a", 2), ("a", 3)))
204205
expr = immutabledict(((expr, expr), (2, 3)))
205206
wxf = export(expr, target_format="wxf", compress=True)
206207
res = binary_deserialize(wxf, consumer=WXFConsumer())

wolframclient/tests/evaluation/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
# The evaluation modules is only supported on python 3.5+, because of asyncio
1010
# We need to prevent the test suite from loading this module containing coroutines.
1111
if six.PY_35:
12+
from wolframclient.tests.evaluation import test_async_cloud as m4
1213
from wolframclient.tests.evaluation import test_cloud as m1
13-
from wolframclient.tests.evaluation import test_kernel as m2
1414
from wolframclient.tests.evaluation import test_coroutine as m3
15-
from wolframclient.tests.evaluation import test_async_cloud as m4
15+
from wolframclient.tests.evaluation import test_kernel as m2
1616

1717
test_modules = (m1, m2, m3, m4)
1818
else:

wolframclient/tests/externalevaluate/ev_loop.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from threading import Thread
44

55
import zmq
6-
76
from wolframclient.language import wl
87
from wolframclient.serializers import export
98
from wolframclient.utils.externalevaluate import EXPORT_KWARGS, StdoutProxy, start_zmq_loop

wolframclient/tests/serializers/pandas.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ def sparse_series_dict(self):
3737
d["b"] = 1
3838
d["a"] = 0
3939
d["c"] = 2
40-
return pandas.Series(d, dtype='Sparse[int]')
40+
return pandas.Series(d, dtype="Sparse[int]")
4141

4242
def sparse_series_dict_indexed(self):
4343
constructor_dict = {1: 1.0}
4444
index = [0, 1, 2]
4545
# Series with index passed in
46-
series = pandas.Series(constructor_dict, dtype='Sparse[float]')
46+
series = pandas.Series(constructor_dict, dtype="Sparse[float]")
4747
return pandas.Series(series, index=index)
4848

4949
def multiindex_series(self):

wolframclient/tests/serializers/wxf_pythonarray.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def test_python_array(self):
3333

3434
def test_generators(self):
3535

36-
array = NumericArray((i for i in range(10)), "Integer8", shape=(10, ))
36+
array = NumericArray((i for i in range(10)), "Integer8", shape=(10,))
3737

3838
self.assertEqual(
3939
export(numpy.arange(10).astype(numpy.int8), target_format="wxf"),
@@ -49,4 +49,4 @@ def test_generators(self):
4949
export(array, target_format="wxf"),
5050
)
5151

52-
self.assertEqual(len(array), 10)
52+
self.assertEqual(len(array), 10)

wolframclient/utils/externalevaluate.py

Lines changed: 6 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -94,59 +94,18 @@ def execute_from_string(code, globals={}, **opts):
9494
return env[last_expr.name]
9595

9696

97-
class SideEffectSender(logging.Handler):
98-
def emit(self, record):
99-
if isinstance(sys.stdout, StdoutProxy):
100-
sys.stdout.send_side_effect(record.msg)
97+
class SocketWriter:
10198

99+
keep_listening = wl.ExternalEvaluate.Private.ExternalEvaluateKeepListening
102100

103-
class SocketWriter:
104101
def __init__(self, socket):
105102
self.socket = socket
106103

107104
def write(self, bytes):
108105
self.socket.send(zmq.Frame(bytes))
109106

110-
111-
class StdoutProxy:
112-
113-
keep_listening = wl.ExternalEvaluate.Private.ExternalEvaluateKeepListening
114-
115-
def __init__(self, stream):
116-
self.stream = stream
117-
self.clear()
118-
119-
def clear(self):
120-
self.current_line = []
121-
self.lines = []
122-
123-
def write(self, message):
124-
messages = force_text(message).split("\n")
125-
126-
if len(messages) == 1:
127-
self.current_line.extend(messages)
128-
else:
129-
self.current_line.append(messages.pop(0))
130-
rest = messages.pop(-1)
131-
132-
self.lines.extend(messages)
133-
self.flush()
134-
if rest:
135-
self.current_line.append(rest)
136-
137-
def flush(self):
138-
if self.current_line or self.lines:
139-
self.send_lines("".join(self.current_line), *self.lines)
140-
self.clear()
141-
142-
def send_lines(self, *lines):
143-
if len(lines) == 1:
144-
return self.send_side_effect(wl.Print(*lines))
145-
elif lines:
146-
return self.send_side_effect(wl.CompoundExpression(*map(wl.Print, lines)))
147-
148107
def send_side_effect(self, expr):
149-
self.stream.write(export(self.keep_listening(expr), **EXPORT_KWARGS))
108+
self.write(export(self.keep_listening(expr), **EXPORT_KWARGS))
150109

151110

152111
def evaluate_message(input=None, return_type=None, args=None, **opts):
@@ -201,7 +160,6 @@ def start_zmq_instance(port=None, write_to_stdout=True, **opts):
201160

202161
def start_zmq_loop(
203162
message_limit=float("inf"),
204-
redirect_stdout=True,
205163
export_kwargs=EXPORT_KWARGS,
206164
evaluate_message=evaluate_message,
207165
exception_class=None,
@@ -210,22 +168,17 @@ def start_zmq_loop(
210168
):
211169

212170
handler = to_wl(exception_class=exception_class, **export_kwargs)(handle_message)
213-
214171
socket = start_zmq_instance(**opts)
215-
216172
stream = SocketWriter(socket)
217-
218173
messages = 0
219174

220-
if redirect_stdout:
221-
sys.stdout = StdoutProxy(stream)
175+
class SideEffectSender(logging.Handler):
176+
def emit(self, record):
177+
stream.send_side_effect(record.msg)
222178

223179
side_effect_logger.addHandler(SideEffectSender())
224180

225181
# now sit in a while loop, evaluating input
226182
while messages < message_limit:
227183
stream.write(handler(socket, evaluate_message=evaluate_message, consumer=consumer))
228184
messages += 1
229-
230-
if redirect_stdout:
231-
sys.stdout = sys.__stdout__

0 commit comments

Comments
 (0)