diff --git a/pymatbridge/matlab/util/pymat_feval.m b/pymatbridge/matlab/util/pymat_feval.m index 0a86282..8aef44b 100644 --- a/pymatbridge/matlab/util/pymat_feval.m +++ b/pymatbridge/matlab/util/pymat_feval.m @@ -31,7 +31,14 @@ arguments = ''; end - [resp{1:req.nargout}] = run_dot_m(func_path, arguments, req.nargout); + try + [resp{1:req.nargout}] = run_dot_m(func_path, arguments, req.nargout); + catch ME + response.message = ME.message; + json_response = json_dump(response); + return + end + if req.nargout == 1 response.result = resp{1}; else diff --git a/pymatbridge/matlab_magic.py b/pymatbridge/matlab_magic.py index ca8c326..f8b441e 100644 --- a/pymatbridge/matlab_magic.py +++ b/pymatbridge/matlab_magic.py @@ -22,8 +22,6 @@ import pymatbridge as pymat from .compat import text_type -ipython_version = int(IPython.__version__[0]) - class MatlabInterperterError(RuntimeError): """ @@ -89,16 +87,6 @@ def __init__(self, shell, self.Matlab.start() self.pyconverter = pyconverter - def __del__(self): - """shut down the Matlab server when the object dies. - - 2FIX: this seems to not be called when ipython terminates. bleah. - """ - try: - self.Matlab.stop() - except: - raise - def eval(self, line): """ Parse and evaluate a single line of matlab @@ -192,11 +180,8 @@ def matlab(self, line, cell=None, local_ns=None): display_data = [] if text_output and not args.silent: - if ipython_version < 3: - display_data.append(('MatlabMagic.matlab', - {'text/plain':text_output})) - else: - display_data.append({'text/plain':text_output}) + display_data.append(('MatlabMagic.matlab', + {'text/plain': text_output})) for imgf in imgfiles: if len(imgf): @@ -204,17 +189,11 @@ def matlab(self, line, cell=None, local_ns=None): # later on: with open(imgf, 'rb') as fid: image = fid.read() - if ipython_version < 3: - display_data.append(('MatlabMagic.matlab', - {'image/png':image})) - else: - display_data.append({'image/png': image}) + display_data.append(('MatlabMagic.matlab', + {'image/png': image})) for disp_d in display_data: - if ipython_version < 3: - publish_display_data(disp_d[0], disp_d[1]) - else: - publish_display_data(disp_d) + publish_display_data(source=disp_d[0], data=disp_d[1]) # Delete the temporary data files created by matlab: if len(data_dir): @@ -237,5 +216,6 @@ def unload_ipython_extension(ip): global _loaded if _loaded: magic = ip.magics_manager.registry.pop('MatlabMagics') + magic.Matlab.stop() _loaded = False diff --git a/pymatbridge/publish.py b/pymatbridge/publish.py index 5843795..35d596e 100644 --- a/pymatbridge/publish.py +++ b/pymatbridge/publish.py @@ -48,10 +48,9 @@ def mfile_to_lines(mfile): Full path to an m file """ # We should only be able to read this file: - f = file(mfile, 'r') - lines = f.readlines() - f.close() - return lines + with open(mfile) as fid: + return fid.readlines() + def lines_to_notebook(lines, name=None): """ @@ -122,13 +121,9 @@ def convert_mfile(mfile, outfile=None): Full path to the output ipynb file """ - f = file(mfile, 'r') - lines = f.readlines() - f.close() + lines = mfile_to_lines(mfile) nb = lines_to_notebook(lines) if outfile is None: outfile = mfile.split('.m')[0] + '.ipynb' - nbfile = file(outfile, 'w') - nbformat.write(nb, nbfile, format='ipynb') - nbfile.close() - + with open(outfile, 'w') as fid: + nbformat.write(nb, fid, format='ipynb') diff --git a/pymatbridge/pymatbridge.py b/pymatbridge/pymatbridge.py index 2e12f47..7659a12 100644 --- a/pymatbridge/pymatbridge.py +++ b/pymatbridge/pymatbridge.py @@ -21,6 +21,7 @@ """ +import atexit import os import time import base64 @@ -30,12 +31,7 @@ import json from uuid import uuid4 -try: - from numpy import ndarray, generic, float64, frombuffer, asfortranarray -except ImportError: - class ndarray: - pass - generic = ndarray +from numpy import ndarray, generic, float64, frombuffer, asfortranarray try: from scipy.sparse import spmatrix @@ -52,7 +48,7 @@ def encode_ndarray(obj): if obj.flags.c_contiguous: obj = obj.T elif not obj.flags.f_contiguous: - obj = asfortranarray(obj) + obj = asfortranarray(obj.T) else: obj = obj.T try: @@ -169,8 +165,9 @@ def __init__(self, executable, socket_addr=None, self.context = None self.socket = None + atexit.register(self.stop) - def _program_name(self): + def _program_name(self): # pragma: no cover raise NotImplemented def _preamble_code(self): @@ -182,7 +179,7 @@ def _preamble_code(self): "warning(old_warning_state)", "clear old_warning_state"] - def _execute_flag(self): + def _execute_flag(self): # pragma: no cover raise NotImplemented def _run_server(self): @@ -227,6 +224,9 @@ def _response(self, **kwargs): # Stop the Matlab server def stop(self): + if not self.started: + return True + # Matlab should respond with "exit" if successful if self._response(cmd='exit') == "exit": print("%s closed" % self._program_name()) diff --git a/pymatbridge/tests/test_magic.py b/pymatbridge/tests/test_magic.py index 3b5d7f8..f9ecb00 100644 --- a/pymatbridge/tests/test_magic.py +++ b/pymatbridge/tests/test_magic.py @@ -1,6 +1,7 @@ import os import pymatbridge as pymat +from pymatbridge.matlab_magic import MatlabInterperterError from IPython.testing.globalipapp import get_ipython import numpy.testing as npt @@ -96,3 +97,7 @@ def test_struct(self): npt.assert_equal(self.ip.user_ns['obj']['num'], self.ip.user_ns['num']) npt.assert_equal(self.ip.user_ns['obj']['num_array'].squeeze(), self.ip.user_ns['num_array']) npt.assert_equal(self.ip.user_ns['obj']['str'], self.ip.user_ns['str']) + + def test_faulty(self): + npt.assert_raises(MatlabInterperterError, + lambda: self.ip.run_line_magic('matlab', '1 = 2')) diff --git a/pymatbridge/tests/test_publish.py b/pymatbridge/tests/test_publish.py index 9f907c7..5c73e0f 100644 --- a/pymatbridge/tests/test_publish.py +++ b/pymatbridge/tests/test_publish.py @@ -1,5 +1,11 @@ import numpy.testing as npt import pymatbridge.publish as publish +import json +import os + + +MFILE = os.path.join(os.path.dirname(__file__), 'test_publish.m') + def test_format_line(): """ @@ -32,3 +38,22 @@ def test_lines_to_notebook(): npt.assert_equal(nb['worksheets'][0]['cells'][1]['source'][0], ' This is a first line\n\n') + + +def test_convert_mfile(): + publish.convert_mfile(MFILE) + nb_file = MFILE.replace('.m', '.ipynb') + with open(nb_file) as fid: + nb = json.load(fid) + npt.assert_equal(nb['worksheets'][0]['cells'][1]['source'][0], + ' Experimenting with conversion from matlab to ipynb\n\n') + os.remove(nb_file) + + +def test_mfile_to_lines(): + lines = publish.mfile_to_lines(MFILE) + + nb = publish.lines_to_notebook(lines) + + npt.assert_equal(nb['worksheets'][0]['cells'][1]['source'][0], + ' Experimenting with conversion from matlab to ipynb\n\n') diff --git a/pymatbridge/tests/test_array.py b/pymatbridge/tests/test_set_variable.py similarity index 62% rename from pymatbridge/tests/test_array.py rename to pymatbridge/tests/test_set_variable.py index af5fc1f..fb44624 100644 --- a/pymatbridge/tests/test_array.py +++ b/pymatbridge/tests/test_set_variable.py @@ -31,4 +31,19 @@ def test_array_content(self): test_array = np.asfortranarray(test_array) self.mlab.set_variable('test', test_array) npt.assert_equal(self.mlab.get_variable('test'), test_array) - + # force non-contiguous + test_array = test_array[::-1] + self.mlab.set_variable('test', test_array) + npt.assert_equal(self.mlab.get_variable('test'), test_array) + + def test_object_array(self): + test_array = np.array(['hello', 1]) + self.mlab.set_variable('test', test_array) + npt.assert_equal(self.mlab.get_variable('test'), test_array) + + def test_others(self): + self.mlab.set_variable('test', np.float(1.5)) + npt.assert_equal(self.mlab.get_variable('test'), 1.5) + self.mlab.set_variable('test', 'hello') + npt.assert_equal(self.mlab.get_variable('test'), 'hello') + diff --git a/pymatbridge/tests/test_utils.py b/pymatbridge/tests/test_utils.py index 3f960fe..ecb7add 100644 --- a/pymatbridge/tests/test_utils.py +++ b/pymatbridge/tests/test_utils.py @@ -6,7 +6,7 @@ def on_octave(): return bool(os.environ.get('USE_OCTAVE', False)) def connect_to_matlab(): - mlab = pymat.Octave() if on_octave() else pymat.Matlab() + mlab = pymat.Octave() if on_octave() else pymat.Matlab(log=True) mlab.start() npt.assert_(mlab.is_connected(), msg = "connect_to_matlab(): Connection failed")