Beispiel #1
0
    def _get_doc(self, name):
        """
        Get the documentation of an Octave procedure or object.

        Parameters
        ----------
        name : str
            Function name to search for.

        Returns
        -------
        out : str
          Documentation string.

        Raises
        ------
        Oct2PyError
           If the procedure or object does not exist.

        """
        if name == 'keyboard':
            return 'Built-in Function: keyboard ()'
        exist = self.eval('exist {0}'.format(name), log=False, verbose=False)
        if exist == 0:
            msg = 'Name: "%s" does not exist on the Octave session path'
            raise Oct2PyError(msg % name)
        doc = 'No documentation for %s' % name

        try:
            doc, _ = self.eval('help {0}'.format(name),
                               log=False,
                               verbose=False,
                               return_both=True)
        except Oct2PyError as e:
            if 'syntax error' in str(e):
                raise (e)
            doc, _ = self.eval('type("{0}")'.format(name),
                               log=False,
                               verbose=False,
                               return_both=True)
            if isinstance(doc, list):
                doc = doc[0]
            doc = '\n'.join(doc.splitlines()[:3])

        default = self._call.__doc__
        doc += '\n' + '\n'.join([line[8:] for line in default.splitlines()])

        return doc
Beispiel #2
0
    def push(self, name, var, verbose=False, timeout=None):
        """
        Put a variable or variables into the Octave session.

        Parameters
        ----------
        name : str or list
            Name of the variable(s).
        var : object or list
            The value(s) to pass.
        timeout : float
            Time to wait for response from Octave (per character).

        Examples
        --------
        >>> from oct2py import octave
        >>> y = [1, 2]
        >>> octave.push('y', y)
        >>> octave.pull('y')
        array([[1, 2]])
        >>> octave.push(['x', 'y'], ['spam', [1, 2, 3, 4]])
        >>> octave.pull(['x', 'y'])  # doctest: +SKIP
        [u'spam', array([[1, 2, 3, 4]])]

        Notes
        -----
        Integer type arguments will be converted to floating point
        unless `convert_to_float=False`.

        """
        if isinstance(name, (str, unicode)):
            vars_ = [var]
            names = [name]
        else:
            vars_ = var
            names = name

        for name in names:
            if name.startswith('_'):
                raise Oct2PyError('Invalid name {0}'.format(name))

        try:
            tempdir = tempfile.mkdtemp(dir=self.temp_dir)
            _, load_line = self._writer.create_file(tempdir, vars_, names)
            self._reader.create_file(tempdir)
            self.eval(load_line, verbose=verbose, timeout=timeout)
        finally:
            shutil.rmtree(tempdir, ignore_errors=True)
Beispiel #3
0
 def readline(self):
     t0 = time.time()
     while 1:
         try:
             val = self.read_queue.get_nowait()
         except queue.Empty:
             pass
         else:
             if val is None:
                 self.close()
                 return
             else:
                 return val
         time.sleep(1e-6)
         if (time.time() - t0) > self.timeout:
             self.interrupt()
             raise Oct2PyError('Timed out, interrupting')
Beispiel #4
0
    def evaluate(self,
                 cmds,
                 logger=None,
                 out_file='',
                 log=True,
                 timeout=None,
                 pre_call='',
                 post_call=''):
        """Perform the low-level interaction with an Octave Session
        """
        self.logger = logger

        self.set_timeout(timeout)

        if not self.proc:
            raise Oct2PyError('Session Closed, try a restart()')

        expr = '\n'.join(cmds)

        if self.first_run:
            self._handle_first_run()

        # use ascii code 2 for start of text, 3 for end of text, and
        # 24 to signal an error
        output = """
        %(pre_call)s

        clear("ans");
        rehash;
        clear("_");
        clear("a__");
        disp(char(2));

        try
            disp(char(2));
            %(expr)s
            if exist("ans") == 1
               _ = ans;
            end
            disp(char(3))

        catch
            disp(lasterr());
            disp(char(24));
        end

        if exist("_") == 1
            if exist("a__") == 0
                save -v6 %(out_file)s _;
            end
        end

        %(post_call)s

        disp(char(3))
        """ % locals()

        if len(cmds) == 5:
            main_line = cmds[2].strip()
        else:
            main_line = '\n'.join(cmds)

        if 'keyboard' in expr:
            self.write('keyboard\n')
            self.interact()
            return ''

        self.write(output + '\n')

        self.expect(chr(2))

        resp = self.expect('%s|error: |parse error:' % chr(2))

        if 'parse error:' in resp:
            resp = [resp[resp.index('parse error:'):]]
        elif 'error:' in resp:
            resp = [resp[resp.index('error:'):]]
        else:
            resp = []

        while 1:
            line = self.readline()

            if chr(3) in line:
                break

            elif chr(24) in line:
                msg = ('Oct2Py tried to run:\n"""\n{0}\n"""\n'
                       'Octave returned:\n{1}'.format(main_line,
                                                      '\n'.join(resp)))
                self.expect(chr(3))
                raise Oct2PyError(msg)

            elif '\x1b[C' in line or line.strip() == '>>':
                line = ''

            elif line.endswith('> '):
                self.interact(line)

            elif line.startswith(' ') and line.strip() == '^':
                if sys.platform == 'win32':
                    self.close()
                raise Oct2PyError('Syntax Error:\n%s' % '\n'.join(resp))

            elif logger and log:
                logger.debug(line)

            if resp or line:
                resp.append(line)

        self.expect(chr(3))

        return '\n'.join(resp).rstrip()
Beispiel #5
0
    def start(self, executable):
        """
        Start an Octave session in a subprocess.

        Parameters
        ==========
        executable : str
            Name or path to Octave process.

        Returns
        =======
        out : fid
            File descriptor for the Octave subprocess

        Raises
        ======
        Oct2PyError
            If the session is not opened sucessfully.

        Notes
        =====
        Options sent to Octave: -q is quiet startup, --braindead is
        Matlab compatibilty mode.

        """
        errmsg = ('\n\n`octave` not found.  Please see documentation at:\n'
                  'http://blink1073.github.io/oct2py/source/installation.html')
        ON_POSIX = 'posix' in sys.builtin_module_names
        if pty:
            master, slave = pty.openpty()
            self.wfid, self.rfid = master, master
            rpipe, wpipe = slave, slave
        else:
            self.rfid, wpipe = os.pipe()
            rpipe, self.wfid = os.pipe()

        kwargs = dict(close_fds=ON_POSIX,
                      bufsize=0,
                      stdin=rpipe,
                      stderr=wpipe,
                      stdout=wpipe)

        if not executable:
            executable = 'octave'

        if os.name == 'nt':
            CREATE_NO_WINDOW = 0x08000000  # Windows-specific
            flags = subprocess.CREATE_NEW_PROCESS_GROUP + CREATE_NO_WINDOW
            kwargs['creationflags'] = flags

        args = [executable, '-q', '--braindead']

        try:
            info = subprocess.check_output([executable, '--version'])
        except OSError:  # pragma: no cover
            raise Oct2PyError(errmsg)

        if 'version 4' in info.decode('utf-8').lower():
            args += ['--no-gui']

        try:
            proc = subprocess.Popen(args, **kwargs)

        except OSError:  # pragma: no cover
            raise Oct2PyError(errmsg)

        else:
            self.reader = _Reader(self.rfid, self.read_queue)
            return proc
Beispiel #6
0
    def _call(self, func, *inputs, **kwargs):
        """
        Oct2Py Parameters
        --------------------------
        inputs : array_like
            Variables to pass to the function.
        verbose : bool, optional
             Log Octave output at INFO level.  If False, log at DEBUG level.
        nout : int, optional
            Number of output arguments.
            This is set automatically based on the number of return values
            requested.
            You can override this behavior by passing a different value.
        timeout : float, optional
            Time to wait for response from Octave (per character).
        plot_dir: str, optional
            If specificed, save the session's plot figures to the plot
            directory instead of displaying the plot window.
        plot_name : str, optional
            Saved plots will start with `plot_name` and
            end with "_%%.xxx' where %% is the plot number and
            xxx is the `plot_format`.
        plot_format: str, optional
            The format in which to save the plot.
        plot_width: int, optional
            The plot with in pixels.
        plot_height: int, optional
            The plot height in pixels.
        kwargs : dictionary, optional
            Key - value pairs to be passed as prop - value inputs to the
            function.  The values must be strings or numbers.

        Returns
        -----------
        out : value
            Value returned by the function.

        Raises
        ----------
        Oct2PyError
            If the function call is unsucessful.

        Notes
        -----
        Integer type arguments will be converted to floating point
        unless `convert_to_float=False`.

        """
        nout = kwargs.pop('nout', get_nout())

        argout_list = ['_']

        # these three lines will form the commands sent to Octave
        # load("-v6", "infile", "invar1", ...)
        # [a, b, c] = foo(A, B, C)
        # save("-v6", "out_file", "outvar1", ...)
        load_line = call_line = save_line = ''

        prop_vals = []
        eval_kwargs = {}
        for (key, value) in kwargs.items():
            if key in ['verbose', 'timeout'] or key.startswith('plot_'):
                eval_kwargs[key] = value
                continue
            if isinstance(value, (str, unicode, int, float)):
                prop_vals.append('"%s", %s' % (key, repr(value)))
            else:
                msg = 'Keyword arguments must be a string or number: '
                msg += '%s = %s' % (key, value)
                raise Oct2PyError(msg)
        prop_vals = ', '.join(prop_vals)

        try:
            temp_dir = tempfile.mkdtemp(dir=self.temp_dir)
            self._reader.create_file(temp_dir)
            if nout:
                # create a dummy list of var names ("a", "b", "c", ...)
                # use ascii char codes so we can increment
                argout_list, save_line = self._reader.setup(nout)
                call_line = '[{0}] = '.format(', '.join(argout_list))

            call_line += func + '('

            if inputs:
                argin_list, load_line = self._writer.create_file(
                    temp_dir, inputs)
                call_line += ', '.join(argin_list)

            if prop_vals:
                if inputs:
                    call_line += ', '
                call_line += prop_vals

            call_line += ');'

            # create the command and execute in octave
            cmd = [load_line, call_line, save_line]
            data = self.eval(cmd, temp_dir=temp_dir, **eval_kwargs)
        finally:
            try:
                shutil.rmtree(temp_dir)
            except OSError:
                pass

        if isinstance(data, dict) and not isinstance(data, Struct):
            data = [data.get(v, None) for v in argout_list]
            if len(data) == 1 and data.values()[0] is None:
                data = None

        return data
Beispiel #7
0
    def eval(self,
             cmds,
             verbose=True,
             timeout=None,
             log=True,
             temp_dir=None,
             plot_dir=None,
             plot_name='plot',
             plot_format='svg',
             plot_width=None,
             plot_height=None,
             return_both=False):
        """
        Evaluate an Octave command or commands.

        Parameters
        ----------
        cmds : str or list
            Commands(s) to pass to Octave.
        verbose : bool, optional
             Log Octave output at INFO level.  If False, log at DEBUG level.
        log : bool, optional
            Whether to log at all.
        timeout : float, optional
            Time to wait for response from Octave (per character).
        plot_dir: str, optional
            If specificed, save the session's plot figures to the plot
            directory instead of displaying the plot window.
        plot_name : str, optional
            Saved plots will start with `plot_name` and
            end with "_%%.xxx' where %% is the plot number and
            xxx is the `plot_format`.
        plot_format: str, optional
            The format in which to save the plot (PNG by default).
        plot_width: int, optional
            The plot with in pixels.
        plot_height: int, optional
            The plot height in pixels.
        return_both: bool, optional
            If True, return a (text, value) tuple with the response
            and the return value.

        Returns
        -------
        out : object
            Octave "ans" variable, or None.

        Raises
        ------
        Oct2PyError
            If the command(s) fail.

        """
        if not self._session:
            raise Oct2PyError('No Octave Session')
        if isinstance(cmds, (str, unicode)):
            cmds = [cmds]

        if log:
            [self.logger.debug(line) for line in cmds]

        if timeout is None:
            timeout = self.timeout

        pre_call, post_call = self._get_plot_commands(plot_dir, plot_format,
                                                      plot_width, plot_height,
                                                      plot_name)

        try:
            if not temp_dir:
                temp_dir = tempfile.mkdtemp(dir=self.temp_dir)
                self._reader.create_file(temp_dir)
            try:
                resp = self._session.evaluate(cmds,
                                              logger=self.logger,
                                              log=log,
                                              timeout=timeout,
                                              out_file=self._reader.out_file,
                                              pre_call=pre_call,
                                              post_call=post_call)
            except KeyboardInterrupt:
                self._session.interrupt()
                if os.name == 'nt':
                    self.restart()
                    return 'Octave Session Interrupted, Restarting Session'
                return 'Octave Session Interrupted'

            out_file = self._reader.out_file

            data = None
            if os.path.exists(out_file) and os.stat(out_file).st_size:
                try:
                    data = self._reader.extract_file()
                except (TypeError, IOError) as e:
                    self.logger.debug(e)
        finally:
            shutil.rmtree(temp_dir)

        resp = resp.strip()

        if resp:
            if verbose:
                print(resp)
            self.logger.info(resp)

        if return_both:
            return resp, data
        else:
            return data
Beispiel #8
0
    def start(self, executable):
        """
        Start an Octave session in a subprocess.

        Parameters
        ==========
        executable : str
            Name or path to Octave process.

        Returns
        =======
        out : fid
            File descriptor for the Octave subprocess

        Raises
        ======
        Oct2PyError
            If the session is not opened sucessfully.

        Notes
        =====
        Options sent to Octave: -q is quiet startup.

        """
        errmsg = ('\n\n`octave` not found.  Please see documentation at:\n'
                  'http://blink1073.github.io/oct2py/source/installation.html')
        ON_POSIX = 'posix' in sys.builtin_module_names
        if pty:
            master, slave = pty.openpty()
            self.wfid, self.rfid = master, master
            rpipe, wpipe = slave, slave
        else:
            self.rfid, wpipe = os.pipe()
            rpipe, self.wfid = os.pipe()

        kwargs = dict(close_fds=ON_POSIX,
                      bufsize=0,
                      stdin=rpipe,
                      stderr=wpipe,
                      stdout=wpipe)

        executable = executable or os.environ.get('OCTAVE', None)
        executable = executable or os.environ.get('OCTAVE_EXECUTABLE', None)
        msg = ('Octave Executable not found, please add to path or set'
               '"OCTAVE_EXECUTABLE" environment variable')

        if not executable or not which(executable.split()[0]):
            if which('octave-cli'):
                executable = 'octave-cli'
            elif which('octave'):
                executable = 'octave'
            else:
                raise OSError(msg)

        if os.name == 'nt':
            CREATE_NO_WINDOW = 0x08000000  # Windows-specific
            flags = subprocess.CREATE_NEW_PROCESS_GROUP + CREATE_NO_WINDOW
            kwargs['creationflags'] = flags

        args = executable.split()
        args.append('-q')

        if 'octave-cli' not in executable:
            try:
                info = subprocess.check_output([executable[0], '--version'])
            except OSError:  # pragma: no cover
                raise Oct2PyError(errmsg)

            if 'version 4' in info.decode('utf-8').lower():
                args += ['--no-gui']

        try:
            proc = subprocess.Popen(args, **kwargs)

        except OSError:  # pragma: no cover
            raise Oct2PyError(errmsg)

        else:
            if not pty:
                self.reader = _Reader(self.rfid, self.read_queue)
            else:
                self.reader = _PtyReader(self.rfid, self.read_queue)
            return proc