Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 211ab13

Browse files
committed
Merge pull request #139 from blink1073/travis-nose
Add Travis Testing against Octave
2 parents 8233a0f + ef4ec95 commit 211ab13

File tree

11 files changed

+97
-68
lines changed

11 files changed

+97
-68
lines changed

.travis.yml

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
language: python
2-
sudo: false
32
deploy:
43
provider: pypi
54
user: arokem
@@ -10,5 +9,35 @@ deploy:
109
repo: arokem/python-matlab-bridge
1110
# until this is fixed: https://github.com/travis-ci/travis-ci/issues/1675
1211
all_branches: true
12+
env:
13+
- CONDA="python=2.7 numpy=1.7"
14+
- CONDA="python=3.3 numpy"
15+
before_install:
16+
- sudo apt-add-repository -y ppa:octave/stable;
17+
- sudo apt-get update -qq;
18+
- sudo apt-get install -qq octave liboctave-dev default-jdk;
19+
- wget http://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh;
20+
- bash miniconda.sh -b -p $HOME/miniconda
21+
- export PATH="$HOME/miniconda/bin:$PATH"
22+
- hash -r
23+
- conda config --set always_yes yes
24+
- conda update conda
25+
- conda info -a
26+
- travis_retry conda create -n test $CONDA IPython pip nose pyzmq
27+
- source activate test
28+
- travis_retry pip install coveralls
29+
30+
install:
31+
- export USE_OCTAVE=True
32+
- python setup.py install
33+
1334
script:
14-
- true
35+
# run coverage on py2.7, regular on others
36+
- if [[ $CONDA == python=2.7* ]]; then
37+
nosetests --exe -v --with-cov --cover-package pymatbridge;
38+
else
39+
nosetests --exe -v pymatbridge;
40+
fi
41+
42+
after_success:
43+
- coveralls

README.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -115,17 +115,7 @@ Rather than looking for `matlab` at the shell, this will look for `octave`.
115115
As with `pymatbridge.Matlab`, you can override this by specifying the
116116
`executable` keyword argument.
117117

118-
There are a few caveats to note about Octave support:
119-
120-
* The zmq messenger used to communicate with the Octave session is written in C
121-
and needs to be compiled. For MATLAB various prebuilt binaries are provided
122-
and added to MATLAB's runtime path, but as of this writing the same isn't
123-
true for Octave. You'll need to compile the messenger (in
124-
`messenger/src/messenger.c`) using an incantation like
125-
`mkoctfile --mex -lzmq messenger.c` and place the resulting `messenger.mex`
126-
file somewhere in Octave's runtime path.
127-
128-
Finally, rather than `~/startup.m`, Octave looks for an `~/.octaverc` file for
118+
Rather than `~/startup.m`, Octave looks for an `~/.octaverc` file for
129119
commands to execute before every session. (This is a good place to manipulate
130120
the runtime path, for example).
131121

@@ -154,11 +144,11 @@ More examples are provided in the `examples` directory
154144
The installation of `pymatbridge` includes a binary of a mex function to communicate between
155145
Python and Matlab using the [0MQ](http://zeromq.org/) messaging library. This should work
156146
without any need for compilation on most computers. However, in some cases, you might want
157-
to build the pymatbridge messenger from source. To do so, you will need to follow the
147+
to build the pymatbridge messenger from source. To do so, you will need to follow the instructions below:
158148

159149
### Install zmq library
160150
Please refer to the [official guide](http://zeromq.org/intro:get-the-software) on how to
161-
build and install zmq. After zmq is installed, make sure you can find the location where
151+
build and install zmq. On Ubuntu, it is as simple as `sudo apt-get install libzmq3-dev`. After zmq is installed, make sure you can find the location where
162152
libzmq is installed. The library extension name and default location on different systems
163153
are listed below.
164154

@@ -215,12 +205,23 @@ be supported. If you have an old version of pyzmq, please update it.
215205

216206
### Install pymatbridge
217207
After the steps above are done, you can install pymatbridge. Download the zip file of the
218-
latest release. Unzip it somewhere on your machine and then issue:
208+
latest release. Unzip it somewhere on your machine.
209+
210+
For Matlab:
219211

220212
cd messenger
221213
python make.py
222214
cd ..
223215
python setup.py install
216+
217+
218+
For Octave:
219+
220+
cd messenger/octave
221+
# edit make.py if not using Ubuntu-derivative
222+
python make.py
223+
cd ..
224+
python setup.py
224225

225226
This should make the python-matlab-bridge import-able.
226227

messenger/octave/make.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
import os
3+
4+
os.system('sudo apt-get install libzmq3-dev liboctave-dev')
5+
os.system('cd ../src; mkoctfile --mex -lzmq messenger.c')
6+
os.system('mv ../src/messenger.mex .')
7+
os.system('cp messenger.mex ../pymatbridge/matlab')

messenger/octave/messenger.mex

20.6 KB
Binary file not shown.

pymatbridge/matlab/util/isrow.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
%
88
%
99

10-
if ndims(X)==2 & size(X,1)==1 & size(X,2)>=1
10+
if ndims(X)==2 && size(X,1)==1 && size(X,2)>=1
1111
Y = logical(1);
1212
else
1313
Y = logical(0);
14-
end
14+
end

pymatbridge/matlab/util/json_v0.2.2/json/json_dump.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@
143143
end
144144
elseif isnumeric(value)
145145
if isreal(value)
146-
obj = javaObject('java.lang.Double', value);
146+
obj = value;
147147
% Encode complex number as a struct
148148
else
149149
complex_struct = struct;

pymatbridge/matlab/util/pymat_get_variable.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
else
3535
response.exists = true;
3636
response.var = evalin('base', varname);
37+
response.success = 'true';
3738
end
3839

3940
json_response = json_dump(response);

pymatbridge/matlab_magic.py

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,23 @@
77
88
"""
99

10-
import sys, os
11-
import tempfile
12-
from glob import glob
1310
from shutil import rmtree
14-
from getopt import getopt
1511

1612
import numpy as np
17-
try:
18-
import scipy.io as sio
19-
has_io = True
20-
except ImportError:
21-
has_io = False
22-
no_io_str = "Must have scipy.io to perform i/o"
23-
no_io_str += "operations with the Matlab session"
24-
2513
import IPython
2614

27-
ipython_version = int(IPython.__version__[0])
28-
2915
from IPython.core.displaypub import publish_display_data
30-
from IPython.core.magic import (Magics, magics_class, cell_magic, line_magic,
16+
from IPython.core.magic import (Magics, magics_class,
3117
line_cell_magic, needs_local_scope)
32-
from IPython.testing.skipdoctest import skip_doctest
3318
from IPython.core.magic_arguments import (argument, magic_arguments,
3419
parse_argstring)
35-
from IPython.utils.py3compat import str_to_unicode, unicode_to_str, PY3
20+
from IPython.utils.py3compat import unicode_to_str, PY3
3621

3722
import pymatbridge as pymat
3823
from .compat import text_type
3924

25+
ipython_version = int(IPython.__version__[0])
26+
4027

4128
class MatlabInterperterError(RuntimeError):
4229
"""
@@ -95,7 +82,10 @@ def __init__(self, shell,
9582
super(MatlabMagics, self).__init__(shell)
9683
self.cache_display_data = cache_display_data
9784

98-
self.Matlab = pymat.Matlab(matlab, maxtime=maxtime)
85+
if 'octave' in matlab.lower():
86+
self.Matlab = pymat.Octave(matlab, maxtime=maxtime)
87+
else:
88+
self.Matlab = pymat.Matlab(matlab, maxtime=maxtime)
9989
self.Matlab.start()
10090
self.pyconverter = pyconverter
10191

@@ -173,19 +163,15 @@ def matlab(self, line, cell=None, local_ns=None):
173163
self.Matlab.set_default_plot_size(width, height)
174164

175165
if args.input:
176-
if has_io:
177-
for input in ','.join(args.input).split(','):
178-
try:
179-
val = local_ns[input]
180-
except KeyError:
181-
val = self.shell.user_ns[input]
182-
# The _Session.set_variable function which this calls
183-
# should correctly detect numpy arrays and serialize them
184-
# as json correctly.
185-
self.set_matlab_var(input, val)
186-
187-
else:
188-
raise RuntimeError(no_io_str)
166+
for input in ','.join(args.input).split(','):
167+
try:
168+
val = local_ns[input]
169+
except KeyError:
170+
val = self.shell.user_ns[input]
171+
# The _Session.set_variable function which this calls
172+
# should correctly detect numpy arrays and serialize them
173+
# as json correctly.
174+
self.set_matlab_var(input, val)
189175

190176
try:
191177
result_dict = self.eval(code)
@@ -216,7 +202,8 @@ def matlab(self, line, cell=None, local_ns=None):
216202
if len(imgf):
217203
# Store the path to the directory so that you can delete it
218204
# later on:
219-
image = open(imgf, 'rb').read()
205+
with open(imgf, 'rb') as fid:
206+
image = fid.read()
220207
if ipython_version < 3:
221208
display_data.append(('MatlabMagic.matlab',
222209
{'image/png':image}))
@@ -234,11 +221,8 @@ def matlab(self, line, cell=None, local_ns=None):
234221
rmtree(data_dir)
235222

236223
if args.output:
237-
if has_io:
238-
for output in ','.join(args.output).split(','):
239-
self.shell.push({output:self.Matlab.get_variable(output)})
240-
else:
241-
raise RuntimeError(no_io_str)
224+
for output in ','.join(args.output).split(','):
225+
self.shell.push({output:self.Matlab.get_variable(output)})
242226

243227

244228
_loaded = False
@@ -253,6 +237,5 @@ def unload_ipython_extension(ip):
253237
global _loaded
254238
if _loaded:
255239
magic = ip.magics_manager.registry.pop('MatlabMagics')
256-
magic.Matlab.stop()
257240
_loaded = False
258241

pymatbridge/pymatbridge.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
import os
2525
import time
26-
import codecs
26+
import base64
2727
import zmq
2828
import subprocess
2929
import sys
@@ -60,7 +60,7 @@ def encode_ndarray(obj):
6060
except AttributeError:
6161
data = obj.astype(float64).tostring()
6262

63-
data = codecs.encode(data, 'base64').decode('utf-8')
63+
data = base64.b64encode(data).decode('utf-8')
6464
return data, shape
6565

6666

@@ -89,19 +89,19 @@ def default(self, obj):
8989
def decode_arr(data):
9090
"""Extract a numpy array from a base64 buffer"""
9191
data = data.encode('utf-8')
92-
return frombuffer(codecs.decode(data, 'base64'), float64)
92+
return frombuffer(base64.b64decode(data), float64)
9393

9494

9595
# JSON decoder for arrays and complex numbers
9696
def decode_pymat(dct):
9797
if 'ndarray' in dct and 'data' in dct:
9898
value = decode_arr(dct['data'])
99-
shape = decode_arr(dct['shape'])
99+
shape = decode_arr(dct['shape']).astype(int)
100100
return value.reshape(shape, order='F')
101101
elif 'ndarray' in dct and 'imag' in dct:
102102
real = decode_arr(dct['real'])
103103
imag = decode_arr(dct['imag'])
104-
shape = decode_arr(dct['shape'])
104+
shape = decode_arr(dct['shape']).astype(int)
105105
data = real + 1j * imag
106106
return data.reshape(shape, order='F')
107107
elif 'real' in dct and 'imag' in dct:
@@ -428,6 +428,7 @@ def _preamble_code(self):
428428
if self.log:
429429
code.append("diary('./pymatbridge/logs/octavelog_%s.txt')" % self.id)
430430
code.append("set(0, 'defaultfigurevisible', 'off');")
431+
code.append("graphics_toolkit('gnuplot')")
431432
return code
432433

433434
def _execute_flag(self):

pymatbridge/tests/test_magic.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,30 @@
1+
import os
2+
13
import pymatbridge as pymat
2-
import IPython
4+
from IPython.testing.globalipapp import get_ipython
35

46
import numpy.testing as npt
57

8+
69
class TestMagic:
710

811
# Create an IPython shell and load Matlab magic
912
@classmethod
1013
def setup_class(cls):
11-
cls.ip = IPython.InteractiveShell()
14+
cls.ip = get_ipython()
1215
cls.ip.run_cell('import random')
1316
cls.ip.run_cell('import numpy as np')
14-
pymat.load_ipython_extension(cls.ip)
17+
if 'USE_OCTAVE' in os.environ:
18+
matlab = 'octave'
19+
else:
20+
matlab = 'matlab'
21+
pymat.load_ipython_extension(cls.ip, matlab=matlab)
1522

16-
# Unload the magic, shut down Matlab
23+
# Unload the magic
1724
@classmethod
1825
def teardown_class(cls):
1926
pymat.unload_ipython_extension(cls.ip)
2027

21-
2228
# Test single operation on different data structures
2329
def test_cell_magic_number(self):
2430
# A double precision real number

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ def copy_bin(bin_path):
3030

3131
for copy_this in ["./messenger/mexmaci64/messenger.mexmaci64",
3232
"./messenger/mexa64/messenger.mexa64",
33-
"./messenger/mexw64/messenger.mexw64"]:
33+
"./messenger/mexw64/messenger.mexw64",
34+
"./messenger/octave/messenger.mex"]:
3435
copy_bin(copy_this)
3536

3637
# Get version and release info, which is all stored in pymatbridge/version.py

0 commit comments

Comments
 (0)