class compas.utilities.XFunc(funcname, basedir='.', tmpdir=None, delete_files=True, verbose=True, callback=None, callback_args=None, python=None, paths=None, serializer='json', argtypes=None, kwargtypes=None, restypes=None)[source]

Bases: object

Wrapper for functions that turns them into externally run processes.

  • funcname (str) – The full name of the function.

  • basedir (str, optional) – A directory that should be added to the PYTHONPATH such that the function can be found. Default is the curent directory.

  • tmpdir (str, optional) – A directory that should be used for storing the IO files. Default is the current directory.

  • delete_files (bool, optional) – Set to False if the IO files should not be deleted afterwards. Default is True.

  • verbose (bool, optional) – Set to False if no information about the process should be displayed to the user. Default is True.

  • callback (callable, optional) – A function to be called eveytime the wrapped function prints output. The first parameter passed to this function is the line printed by the wrapped function. Additional parameters can be defined using callback_args. Default is None.

  • callback_args (tuple, optional) – Additional parameter for the callback function. Default is None.

  • python (str, optional) – The Python executable. This can be a path to a specific executable (e.g. '/opt/local/bin/python') or the name of an executable registered on the system PATH (e.g. 'pythonw'). Default is 'pythonw'.

  • paths (list, optional) – A list of paths to be added to the PYTHONPATH by the subprocess. Default is None.

  • serializer ({‘json’, ‘pickle’}, optional) – The serialisation mechnanism to be used to pass data between the caller and the subprocess. Default is 'json'.

  • data (object) – The object returned by the wrapped function. This is None if something went wrong.

  • profile (str) – A profile of the call to the wrapped function. This is None if something went wrong.

  • error (str) – A traceback of the exception raised during the wrapped function call. This is None if nothing went wrong.

__call__(*args, **kwargs)[source]

Call the wrapped function with the apropriate/related arguments and keyword arguments.


To use the Python executable of a virtual environment, simply assign the path to that executable to the python parameter. For example

fd_numpy = XFunc('compas.numerical.fd_numpy', python='/Users/brg/environments/py2/python')


compas.numerical provides an implementation of the Force Density Method that is based on Numpy and Scipy. This implementation is not directly available in Rhino because Numpy and Scipy are not available for IronPython.

With compas.utilities.XFunc, compas.numerical.fd_numpy can be easily wrapped in an external process and called as if it would be directly available.

import compas
import compas_rhino

from compas_rhino.artists import MeshArtist
from compas.datastructures import Mesh
from compas.utilities import XFunc

# make the function available as a wrapped function with the same call signature and return value as the original.
fd_numpy = XFunc('compas.numerical.fd_numpy')

mesh = Mesh.from_obj(compas.get('faces.obj'))

mesh.update_default_vertex_attributes({'is_fixed': False, 'px': 0.0, 'py': 0.0, 'pz': 0.0})
mesh.update_default_edge_attributes({'q': 1.0})

for key, attr in mesh.vertices(True):
    attr['is_fixed'] = mesh.vertex_degree(key) == 2

key_index = mesh.key_index()
vertices  = mesh.get_vertices_attributes('xyz')
edges     = [(key_index[u], key_index[v]) for u, v in mesh.edges()]
fixed     = [key_index[key] for key in mesh.vertices_where({'is_fixed': True})]
q         = mesh.get_edges_attribute('q', 1.0)
loads     = mesh.get_vertices_attributes(('px', 'py', 'pz'), (0.0, 0.0, 0.0))

xyz, q, f, l, r = fd_numpy(vertices, edges, fixed, q, loads)

for key, attr in mesh.vertices(True):
    attr['x'] = xyz[key][0]
    attr['y'] = xyz[key][1]
    attr['z'] = xyz[key][2]

artist = MeshArtist(mesh)


__init__(funcname[, basedir, tmpdir, …])

Initialize self.