Information
Dynamic Functions
Oct2Py will create methods for you on the fly, which correspond to Octave functions. For example:
>>> from oct2py import octave
>>> octave.ones(3)
array([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
If you pass keyword arguments to the function, they will be treated as
Octave keywords, for example, octave.plot(x, y, linewidth=3) becomes
plot(x, y, 'linewidth', 3). Arguments that are integer type will be
converted to floats unless you set convert_to_float=False.
Additionally, you can look up the documentation for one of these methods
using help()
>>> from oct2py import octave
>>> help(octave.ones) # doctest: +SKIP
'ones' is a built-in function
...
Interactivity
Oct2Py supports code completion in IPython, so once you have created a
method, you can recall it on the fly, so octave.one<TAB> would give
you ones. Structs (mentioned below) also support code completion for
attributes.
You can share data with an Octave session explicitly using the push
and pull methods. When using other Oct2Py methods, the variable names
in Octave start with underscores because they are temporary (you would
only see this if you were using logging).
>>> from oct2py import octave
>>> octave.push("a", 1)
>>> octave.pull("a")
1.0
Workspace Access
The workspace attribute provides a dict-like interface to the Octave base
workspace, mirroring the eng.workspace API in MATLAB's Python engine:
>>> from oct2py import octave
>>> octave.eval("x = 5", nout=0)
>>> octave.workspace["x"]
5.0
>>> octave.workspace["y"] = [1, 2, 3]
>>> octave.pull("y")
array([[1., 2., 3.]])
>>> del octave.workspace["y"]
This is equivalent to using push and pull directly, but can be more
natural when porting code from MATLAB's Python engine.
Expression Pointers
Some Octave values — such as cell arrays of function handles — cannot be
converted to Python objects. Use get_pointer with expr=True to hold a
reference to such an expression and pass it directly to Octave functions
without a round-trip through Python:
>>> from oct2py import octave
>>> ptr = octave.get_pointer('{@cos @sin}', expr=True)
>>> type(ptr).__name__
'OctaveVariablePtr'
>>> # Pass the cell of function handles to an Octave function unchanged
>>> octave.feval('cellfun', '@(f) f(0)', ptr) # doctest: +SKIP
array([1., 0.])
get_pointer(expr_str, expr=True) assigns the expression to a uniquely
named temporary variable in the Octave workspace and returns a pointer to
it. The pointer's address is the internal variable name; the temporary
variable persists for the life of the session.
This is different from get_pointer(name) (without expr=True), which
looks up an existing named variable or function.
Using M-Files
In order to use an m-file in Oct2Py you must first call addpath for
the directory containing the script. You can then use it as a dynamic
function or use the eval function to call it. Alternatively, you can
call feval with the full path.
>>> from oct2py import octave
>>> octave.addpath("/path/to/") # doctest: +SKIP
>>> octave.myscript(1, 2) # doctest: +SKIP
>>> # or
>>> octave.eval("myscript(1, 2)") # doctest: +SKIP
>>> # as feval
>>> octave.feval("/path/to/myscript", 1, 2) # doctest: +SKIP
Running Scripts and Accessing Their Variables
Octave scripts (as opposed to functions) assign variables directly into
the caller's workspace. When you call a script through the dynamic
dispatch mechanism (e.g. octave.myscript()), oct2py evaluates it
inside a temporary function scope, so any variables the script creates
are discarded when it returns and are not accessible via pull.
Use Oct2Py.run() instead. It executes the script in Octave's base
workspace, so variables it assigns persist and can be retrieved with
pull:
>>> from oct2py import Oct2Py
>>> oc = Oct2Py()
>>> # myscript.m contains: result = [1, 2, 3];
>>> oc.run("/path/to/myscript.m") # doctest: +SKIP
>>> oc.pull("result") # doctest: +SKIP
array([1., 2., 3.])
run accepts the same optional keyword arguments as eval (verbose,
timeout, stream_handler, etc.).
Note: This limitation does not apply to Octave functions — a function's return values are passed back to Python normally via
feval. If you need to share data between Python and Octave in a flexible way, prefer writing a function that accepts arguments and returns results rather than relying on side-effects in the base workspace.
Suppressing Output Capture
By default, eval and feval capture and return the Octave ans value.
Passing quiet=True executes the command but discards the result entirely,
returning None. This is useful in three situations:
- Inspecting struct fields in Jupyter — without
quiet=True, the value is both printed by Octave and returned to the cell output, causing it to appear twice. - Non-serialisable types — some Octave values (custom class objects, large
sparse arrays, etc.) cannot be serialised to a MAT file.
quiet=Truelets you run the command for its side effects without triggering a serialisation error. - Fire-and-forget calls — when you only care about the side effect (e.g.
setting a variable, calling
disp) and do not need the return value.
>>> from oct2py import octave
>>> octave.push("s", {"field": [1, 2, 3]})
>>> result = octave.eval("s.field", quiet=True) # prints once, returns None
>>> result is None
True
>>> result = octave.feval("max", [3, 1, 2], quiet=True) # no return value
>>> result is None
True
Direct Interaction
Oct2Py supports the Octave keyboard function which drops you into an
interactive Octave prompt in the current session. This also works in the
IPython Notebook. Note: If you use the keyboard command and the
session hangs, try opening an Octave session from your terminal and see
if the keyboard command hangs there too. You may need to update your
version of Octave.
Logging
Oct2Py uses the standard Python logging module under the logger name
"oct2py". Following Python library best practices, oct2py installs no
handlers and sets no log levels. This means:
- WARNING and above propagate to the root logger. If your application has
not configured logging, Python's built-in
lastResorthandler will print them tostderr. - DEBUG and INFO are invisible until you configure logging, since the root logger's default level is WARNING.
To see oct2py INFO output (e.g. commands sent to Octave), configure the
"oct2py" logger or the root logger in your application:
import logging
# Show INFO and above from oct2py only
logging.getLogger("oct2py").setLevel(logging.INFO)
logging.getLogger("oct2py").addHandler(logging.StreamHandler())
# Or configure the root logger (affects all loggers):
logging.basicConfig(level=logging.INFO)
To enable DEBUG output (useful for troubleshooting), use logging.DEBUG:
import logging
logging.basicConfig(level=logging.DEBUG)
When using pytest, pass --log-cli-level=DEBUG on the command line or add
to pyproject.toml:
[tool.pytest.ini_options]
log_cli = true
log_cli_level = "DEBUG"
You can also pass a logger directly to the Oct2Py constructor or replace
it at any time:
>>> import logging
>>> from oct2py import Oct2Py, get_log
>>> oc = Oct2Py(logger=get_log())
>>> oc.logger = get_log("new_log")
All Oct2Py methods support a verbose keyword. If True, the commands
are logged at the INFO level, otherwise they are logged at the DEBUG
level.
Warnings
Oct2Py uses Oct2PyWarning (a subclass of UserWarning) for deprecation
notices and other advisory conditions. Because it has its own type, you can
handle oct2py warnings independently of warnings from other libraries.
Catch oct2py warnings in tests with pytest.warns:
import pytest
from oct2py import Oct2PyWarning
with pytest.warns(Oct2PyWarning):
oc.eval("1 + 1", log=False) # log= kwarg is deprecated
Silence oct2py warnings without affecting other UserWarnings:
import warnings
from oct2py import Oct2PyWarning
warnings.filterwarnings("ignore", category=Oct2PyWarning)
Turn oct2py warnings into errors (useful in CI):
import warnings
from oct2py import Oct2PyWarning
warnings.filterwarnings("error", category=Oct2PyWarning)
Debugging
When troubleshooting an installation or unexpected behaviour, use
oct2py.check() to print a snapshot of your environment:
>>> import oct2py
>>> oct2py.check() # doctest: +SKIP
Platform: Linux 6.8.0 (x86_64)
Python: 3.11.9 (main, Apr 2 2024, 08:55:17) [GCC 11.4.0]
Python path: /usr/bin/python3
oct2py: 5.8.0
numpy: 2.2.6
scipy: 1.15.3
octave_kernel:0.39.0
Octave exe: /usr/bin/octave-cli
Connecting to Octave...
Octave: 9.2.0
Graphics: qt (available: gnuplot, qt)
Connection OK
The output includes:
- Platform / Python — OS, architecture, Python version, and executable path, useful for confirming which environment is active.
- Dependency versions —
oct2py,numpy,scipy, andoctave_kernel. Version mismatches here are a common source of serialisation errors. - Octave executable — the resolved path to the Octave binary. If this
shows
(not found), Octave is not onPATHand you need to install it or set theOCTAVE_EXECUTABLEenvironment variable. - Live connection test — starts an Octave session and reports the Octave
version plus the active and available graphics toolkits. A
Connection failedline here points to a problem with the Octave installation itself rather than the Python side.
You can also run it directly from the command line:
python -m oct2py.check
Include the full output when filing a bug report.
Shadowed Function Names
If you'd like to call an Octave function that is also an Oct2Py method, you must add a trailing underscore. For example:
>>> from oct2py import octave
>>> octave.eval_("a=1")
1.0
The methods that shadow Octave builtins are: exit and eval.
Timeout
Oct2Py sessions have a timeout attribute that determines how long to
wait for a command to complete. The default is 1e6 seconds (indefinite).
You may either set the timeout for the session, or as a keyword argument
to an individual command. The session is closed in the event of a
timeout.
>>> from oct2py import octave
>>> octave.timeout = 3
>>> octave.sleep(2) # doctest: +SKIP
>>> octave.sleep(2, timeout=1) # doctest: +SKIP
Traceback (most recent call last):
...
oct2py.utils.Oct2PyError: Session timed out
Configuration & Settings
All session defaults — timeout, executable, plot format, backend, and
more — can be set in one place using Oct2PySettings and read from
environment variables automatically. See the
Configuration & Settings page for the full guide,
including env var names, .env file support, and common recipes for
headless, sandboxed, and CI environments.
from oct2py import Oct2Py, Oct2PySettings
s = Oct2PySettings(backend="disable", timeout=30, plot_format="png")
oc = Oct2Py(settings=s)
Use oct2py.configure() to reconfigure the default global instance:
import oct2py
oct2py.configure(backend="disable", timeout=60)
Octave Executable
By default, oct2py uses octave as the Octave executable. To use a
different binary, pass it directly or set the OCTAVE_EXECUTABLE
environment variable:
oc = Oct2Py(executable="/path/to/octave")
export OCTAVE_EXECUTABLE=/path/to/octave
When using IPython or Jupyter, you can also change it at runtime via the
OctaveMagics config trait without restarting the kernel:
%config OctaveMagics.executable = "/path/to/octave"
Graphics Toolkit
In some cases, the qt graphics toolkit is only available when running
with a display enabled.
On a remote system without a display, you can use xvfb-run to provide
a virtual framebuffer. For example:
export OCTAVE_EXECUTABLE="xvfb-run octave"
Or in the config file:
c.OctaveMagics.executable = "xvfb-run octave"
To inspect or change the active toolkit at runtime:
>>> from oct2py import octave
>>> octave.available_graphics_toolkits() # doctest: +SKIP
['qt', 'gnuplot']
>>> octave.graphics_toolkit("gnuplot") # doctest: +SKIP
'gnuplot'
PyCharm and IDE Integration
PyCharm's interactive console (and similar IDEs) displays matplotlib figures
inline but cannot capture Octave's native figure windows. As a result,
octave.plot([1, 2, 3]) produces no visible output even though the figure
exists in Octave.
Oct2Py bridges this gap with two mechanisms:
Automatic (auto_show): When PYCHARM_HOSTED is set in the environment
(i.e. when running inside PyCharm), oct2py automatically renders open Octave
figures as PNG images and displays them via matplotlib.pyplot.imshow() after
every eval or feval call. No code changes are required — just install
matplotlib and run your plotting code as normal:
>>> from oct2py import octave
>>> octave.plot([1, 2, 3]) # figure appears inline automatically in PyCharm
Manual (show()): In other environments, or to trigger display on demand,
call show() explicitly:
>>> from oct2py import Oct2Py
>>> oc = Oct2Py()
>>> oc.plot([1, 2, 3])
>>> oc.show() # renders and displays the figure via matplotlib
You can also enable or disable auto_show explicitly regardless of the
environment:
>>> oc = Oct2Py(auto_show=True) # always auto-display figures
>>> oc = Oct2Py(auto_show=False) # never auto-display figures
show() requires matplotlib to be installed. If it is not available the
method returns silently, so it is safe to call unconditionally.
Context Manager
Oct2Py can be used as a Context Manager. The session will be closed and the temporary m-files will be deleted when the Context Manager exits.
>>> from oct2py import Oct2Py
>>> with Oct2Py() as oc: # doctest:+ELLIPSIS
... oc.ones(10)
...
array([[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
...
Pandas
Oct2Py supports pandas.Series and pandas.DataFrame objects directly.
They are converted to their underlying NumPy array via .values before
being sent to Octave, so the Octave side always receives a plain numeric
array or matrix. The round-trip type is ndarray, not the original pandas
type.
>>> import numpy as np
>>> import pandas as pd
>>> from oct2py import Oct2Py
>>> oc = Oct2Py()
>>> series = pd.Series([1.0, 2.0, 3.0])
>>> oc.push("s", series)
>>> oc.pull("s")
array([[1., 2., 3.]])
>>> data = np.array([[1.0, 2.0], [3.0, 4.0]])
>>> df = pd.DataFrame(data, columns=["a", "b"])
>>> oc.push("df", df)
>>> oc.pull("df")
array([[1., 2.],
[3., 4.]])
>>> oc.exit()
Structs
Struct is a convenience class that mimics an Octave structure variable type. It is a dictionary with attribute lookup, and it creates sub-structures on the fly of arbitrary nesting depth. It can be pickled. You can also use tab completion for attributes when in IPython.
>>> from oct2py import Struct
>>> test = Struct()
>>> test["foo"] = 1
>>> test.bizz["buzz"] = "bar"
>>> test
{'foo': 1, 'bizz': {'buzz': 'bar'}}
>>> import pickle
>>> p = pickle.dumps(test)
Unicode
Oct2Py supports Unicode characters, so you may feel free to use m-files that contain them.
Speed
There is a performance penalty for passing information using MAT files. If you have a lot of calculations, it is probably better to make an m-file that does the looping and data aggregation, and pass that back to Python for further processing. To see an example of the speed penalty on your machine, run:
>>> import oct2py
>>> oct2py.speed_check() # doctest:+ELLIPSIS
Oct2Py speed test
...
Reducing MAT-file overhead with a RAM-backed temp directory
Oct2py exchanges data with Octave by writing and reading MAT files in a temporary directory. Keeping that directory in RAM eliminates disk I/O entirely and can meaningfully improve throughput for workloads that make many short calls.
Linux — /dev/shm (a kernel-managed tmpfs) is used automatically
whenever it is available and writable. No configuration is required.
macOS — opt-in RAM disk (managed by oct2py)
Pass ramdisk_size_mb to have oct2py create, use, and destroy a HFS+
RAM disk for the duration of the session:
from oct2py import Oct2Py
oc = Oct2Py(ramdisk_size_mb=256) # 256 MiB RAM disk
You can also set it via the environment variable OCT2PY_RAMDISK_SIZE_MB.
Choose a size large enough to hold the largest single argument or return
value you expect to exchange. The disk is unmounted automatically when
oc.exit() is called or when the Python process exits.
macOS — existing RAM disk (user-managed)
If you already have a RAM disk mounted (for example via a login-item
script), pass its path directly as temp_dir:
# Create a 256 MiB RAM disk and mount it at /Volumes/ramdisk
diskutil erasevolume HFS+ "ramdisk" $(hdiutil attach -nomount ram://524288)
from oct2py import Oct2Py
oc = Oct2Py(temp_dir="/Volumes/ramdisk")
oct2py will create a subdirectory inside that path and will not unmount the disk when the session exits — lifetime management is left to you.
Threading
If you want to use threading, you must create a new Oct2Py instance
for each thread. The octave convenience instance is in itself not
threadsafe. Each Oct2Py instance has its own dedicated Octave session
and will not interfere with any other session.
IPython Notebook
Oct2Py provides OctaveMagic for IPython, including inline plotting in notebooks. This requires IPython >= 1.0.0.