@@ -121,7 +121,7 @@ class _Session(object):
121121 """
122122
123123 def __init__ (self , executable = None , socket_addr = None ,
124- id = 'python-matlab-bridge' , log = False , maxtime = 15 ,
124+ id = 'python-matlab-bridge' , log = "" , maxtime = 15 ,
125125 platform = None , startup_options = None ,
126126 loglevel = logging .WARNING ):
127127 """
@@ -141,7 +141,7 @@ def __init__(self, executable=None, socket_addr=None,
141141 id : str
142142 An identifier for this instance of the pymatbridge.
143143
144- log : str | None
144+ log : str
145145 Location to log to, defaults to sys.stdout
146146
147147 maxtime : float
@@ -174,7 +174,7 @@ def __init__(self, executable=None, socket_addr=None,
174174 self .socket_addr = socket_addr
175175 self .context = None
176176 self .socket = None
177- self .logger = logging .getLogger ("pymatbridge" )
177+ self .logger = logging .getLogger (self . id )
178178 self .logger .setLevel (self .loglevel )
179179 if self .log :
180180 self .loghandler = logging .FileHandler (self .log )
@@ -188,26 +188,15 @@ def __init__(self, executable=None, socket_addr=None,
188188 def _program_name (self ): # pragma: no cover
189189 raise NotImplementedError
190190
191- def _preamble_code (self ):
192- # suppress warnings while loading the path, in the case of
193- # overshadowing a built-in function on a newer version of
194- # Matlab (e.g. isrow)
195- return ["old_warning_state = warning('off','all');" ,
196- "addpath(genpath('%s'));" % MATLAB_FOLDER ,
197- "warning(old_warning_state);" ,
198- "clear('old_warning_state');" ,
199- "cd('%s');" % os .getcwd ()]
200-
201191 def _execute_flag (self ): # pragma: no cover
202192 raise NotImplementedError
203193
204194 def _run_server (self ):
205- code = self ._preamble_code ()
206- code .extend ([
207- "matlabserver('%s')" % self .socket_addr
208- ])
195+ code = "cd('{}'); matlabserver('{}', true);" .format (
196+ MATLAB_FOLDER , self .socket_addr )
209197 command = '%s %s %s "%s"' % (self .executable , self .startup_options ,
210- self ._execute_flag (), ',' .join (code ))
198+ self ._execute_flag (), code )
199+ self .logger .info ("Running: %s" , command )
211200 subprocess .Popen (command , shell = True , stdin = subprocess .PIPE ,
212201 stdout = subprocess .PIPE )
213202
@@ -221,13 +210,12 @@ def start(self):
221210 self .socket_addr = self .socket_addr + ":%s" % rndport
222211
223212 # Start the MATLAB server in a new process
224- self .logger .info ("Starting ZMQ socket %s" \
225- % (self .socket_addr , ))
226- self .logger .info ("Send 'exit' command to kill the server" )
213+ self .logger .info ("Starting ZMQ socket %s" , self .socket_addr )
214+ #self.logger.info("Run _Session.stop/separate to kill the server.")
227215
228216 if self .executable is not None :
229- self .logger .info ("Launching %s, sending ZMQ 'exit' will kill it." \
230- % ( self ._program_name (), ))
217+ self .logger .info ("Launching %s, sending ZMQ 'exit' will kill it." , \
218+ self ._program_name ())
231219 self ._run_server ()
232220
233221 # Start the client
@@ -239,7 +227,7 @@ def start(self):
239227 if not self .is_connected ():
240228 raise ValueError ("%s failed to start" % self ._program_name ())
241229
242- self .logger .info ("%s started and connected!" % self ._program_name ())
230+ self .logger .info ("%s started and connected!" , self ._program_name ())
243231 self .set_plot_settings ()
244232 return self
245233
@@ -249,14 +237,23 @@ def _response(self, **kwargs):
249237 resp = self .socket .recv_string ()
250238 return resp
251239
240+ # open desktop matlab and disconnect
241+ def separate (self ):
242+ if not self .started :
243+ raise ValueError ('Session not started, use start()' )
244+ if self ._response (cmd = 'separate' ) == 'exit' :
245+ self .logger .info ("%s split off" , self ._program_name ())
246+ self .started = False
247+ return True
248+
252249 # Stop the Matlab server
253250 def stop (self ):
254251 if not self .started :
255252 return True
256253
257254 # Matlab should respond with "exit" if successful
258255 if self ._response (cmd = 'exit' ) == "exit" :
259- self .logger .info ("%s closed" % self ._program_name ())
256+ self .logger .info ("%s closed" , self ._program_name ())
260257
261258 self .started = False
262259 return True
@@ -337,6 +334,12 @@ def run_code(self, code):
337334 """
338335 return self .run_func ('evalin' , 'base' , code , nargout = 0 )
339336
337+ def _init_run_code (self ):
338+ """Code to run at start of headless session to ensure sane
339+ environment."""
340+ code = "cd('%s')" % os .getcwd ()
341+ return self .run_code (code )
342+
340343 def get_variable (self , varname , default = None ):
341344 resp = self .run_func ('evalin' , 'base' , varname )
342345 return resp ['result' ] if resp ['success' ] else default
@@ -445,13 +448,14 @@ def __init__(self, executable='matlab', socket_addr=None,
445448
446449 socket_addr : str
447450 A string that represents a valid ZMQ socket address, such as
448- "ipc:///tmp/pymatbridge", "tcp://127.0.0.1:55555", etc.
451+ "ipc:///tmp/pymatbridge", "tcp://127.0.0.1:55555", etc. Default is
452+ to choose a random IPC file name, or a random socket (for TCP).
449453
450454 id : str
451455 An identifier for this instance of the pymatbridge.
452456
453- log : bool
454- Whether to save a log file in some known location.
457+ log : str
458+ Location to log to, defaults to sys.stdout
455459
456460 maxtime : float
457461 The maximal time to wait for a response from matlab (optional,
@@ -473,7 +477,7 @@ def __init__(self, executable='matlab', socket_addr=None,
473477 else :
474478 startup_options = ' -nodesktop -nosplash'
475479 if log :
476- startup_options += ' -logfile ./pymatbridge/logs/matlablog_%s.txt' % id
480+ startup_options += ' -logfile "{}"' . format ( log )
477481 super (Matlab , self ).__init__ (executable , socket_addr , id , log , maxtime ,
478482 platform , startup_options , loglevel )
479483
@@ -497,7 +501,7 @@ def __init__(self, executable='octave', socket_addr=None,
497501
498502 executable : str
499503 A string that would start Octave at the terminal. Per default, this
500- is set to 'octave', so that you can alias in your bash setup
504+ is set to 'octave'.
501505
502506 socket_addr : str
503507 A string that represents a valid ZMQ socket address, such as
@@ -529,12 +533,12 @@ def __init__(self, executable='octave', socket_addr=None,
529533 def _program_name (self ):
530534 return 'Octave'
531535
532- def _preamble_code (self ):
533- code = super (Octave , self )._preamble_code ()
534- if self .log :
535- code .append ("diary('./pymatbridge/logs/octavelog_%s.txt')" % self .id )
536+ def _init_run_code (self ):
537+ code = super (Octave , self )._init_run_code ()
536538 code .append ("graphics_toolkit('gnuplot')" )
537- return code
539+ if self .log :
540+ code .append ("diary('{}')" .format (self .id ))
541+ self .run_code (code )
538542
539543 def _execute_flag (self ):
540544 return '--eval'
0 commit comments