# mirpyidl

A library to call IDL (Interactive Data Language) from python. Allows trasparent wrapping of IDL routines and objects as well as arbitrary execution of IDL code.

mirpyidl requires a licenced installation of IDL . Data is transfered back and forth using either the CallableIDL (idl_export.h) or the IDLRPC (idl_rpc.h) APIs, both of which are distrbuted with IDL.

All standard IDL and python/numpy datatypes are supported, and mirpyidl transparently handles translating between equivilent datatypes. This includes translation between IDL structures and python dictionaries.

mirpyidl is hosted at:
https://bitbucket.org/amicitas/mirpyidl
Documentation can be found at:
http://amicitas.bitbucket.io/mirpyidl

mirpyidl was written by Novimir A. Pablant, and is released under an MIT licence.

## Dependencies

• IDL (8.0 or later)
• python (2.7, 3.0 or later)
• numpy
• psutil
• cython
• openmotif

mirpyidl requires a licenced installation of IDL. Currently only IDL 8.0 or later is spported due to the additon of the HASH and LIST types. Older versions may be compatible but are untested.

mirpyidl is currently only supported on linux and OS X. It should also work fine on windows, but the setup.py script has not been setup to find the IDL installation directory. If you want to give this a try on windows, just add the appropriate directories to setup.py. (If it works submit a pull reqeust so that I can update the public package.)

## Installation

mirpyidl can be installed from pypi.python.org using pip:

pip install mirpyidl


Alternatively mirpyidl can be alse be installed from source using the following command:

python setup.py install


To do a user-local installaiton (which does not required root privalages) add the --user flag to the installation command. For more control over the installation, all standard distutils commands are available. If setuputils is installed, then the extended commands will also work.

If only a local copy is desired, rather than a full installation, the mirpyidl module can be built in place using:

python setup.py build_ext --inplace


This will build mirpyidl in place and create the mirpyidl.so shared library and mirpyidlrpc.py module both of which can then be imported from python.

Warning:
On Mac OS X the setup script will change the installation names of the libidl.dylib, libidl_rpc.dylib and related IDL libraries to be prefixed with @rpath/. This is the OS X standard way to specify run-path dependent libraries and is not known to have any side effects.
Note:
Compilation with gcc should generally work without any issues. Compilation with the intel compiler, icc is also possible, however the intel linker will also need to be used. For compilation with icc make sure to set the following environmental variables: CC='icc -pthread' and LDSHARED='icc -pthread -shared'.

## Examples

Here are a few simple examples. A full set of examples and tutorials is included in the documentation.

### executing idl code

Here is a simple example for executing arbitrary IDL code from python:

# Import mirpyidl.
import mirpyidl as idl

# Execute a command in IDL.
# This will print 'Hello mom!' from IDL.
idl.execute("PRINT, 'Hello mom!'")


As a more complex example, we will now send some data back and forth between IDL and python.

import numpy as np
import mirpyidl as idl

# Create a numpy array in python.
py_array = np.random.normal(size=1000)

# Copy this data to IDL.
idl.setVariable('idl_array', py_array)

# Calculate the standard devation and the mean in IDL.
idl.execute('idl_stddev = STDDEV(idl_array)')
idl.execute('idl_mean = MEAN(idl_array)')

# Copy the results back to python.
py_stddev = idl.getVariable('idl_stddev')
py_mean = idl.getVariable('idl_mean')

# Print out the results.
print('Mean: {}, StdDev: {}'.format(py_mean, py_stddev))


### calling functions and procedures

In the examples above we used just the most basic mirpyidl commands to control an IDL session and pass data between IDL and python. In these next examples we use the mirpyidl wrapping routines to do simplify the code in the previous example significantly.

import numpy as np
import mirpyidl as idl

# Create a numpy array in python.
py_array = np.random.normal(size=1000)

# Calculate the standard devication and mean using IDL.
py_stddev = idl.callFunction('STDDEV', [py_array])
py_mean = idl.callFunction('MEAN', [py_array])

# Print out the results.
print('Mean: {}, StdDev: {}'.format(py_mean, py_stddev))


### wraping functions and procedures

Wrapping functions or procedures looks very similar to the example above. Let say we want to wrap the IDL STDDEV and MEAN functions in a python module named idlmath.

# idlmath.py

import mirpyidl as idl

def stddev(*args, **kwargs):
return idl.callFunction('STDDEV', args, kwargs)

def mean(*args, **kwargs):
return idl.callFunction('MEAN', args, kwargs)


That's all there is to it. Now we can call these functions as though they were native python funcitons.

import numpy as np
import idlmath

array = np.random.normal(size=1000)

# Here we transparently call the wrapped IDL functions.
mean = idlmath.mean(array)
stddev = idlmath.stddev(array)


### wrapping objects

mirpyidl also has the ability to fully wrap IDL objects.

Python wrapping objects should all inherit from PyIDLObject. Here is an example of wrapping a hypothetical Gaussian object.

# _IdlGaussain.py

from mirpyidl import PyIDLObject

class IdlGaussian(PyIDLObject):

# Define the the IDL command needed to create the object.
_creation_command = "OBJ_NEW"
_creation_params = ['GAUSSIAN']
_creation_keywords = None

def evaluate(self, *args, **kwargs):
return, self.callMethodFunction('EVALUATE', args, kwargs)

def setParam(self, *args, **kwargs):
return, self.callMethodPro('SET_PARAM', args, kwargs)

def getParam(self, *args, **kwargs):
return, self.callMethodFunction('GET_PARAM', args, kwargs)


This wrapped object can now be used just like a normal Python object.

from _IdlGaussian import IdlGaussian

obj = IdlGaussian()
obj.setParam(location=0.0, width=1.0, area=1.0)

y = obj.evaluate(0.0)


## Using an idlrpc server

mirpyidl can also connect to a running idlrpc instance rather than starting an IDL interpreter internally. To use an idlrpc connection simply use import mirpyidl instead of import mirpyidlrpc. All of the examples above will work equivalently with this change.

# Import mirpyidlrpc to use the idlrpc interface.
import mirpyidlrpc

# We can also import individual classes as before.
from mirpyidlrpc import PyIdl


Advanced usage can be found in the documentation.

When using the idlrpc interface an idlrpc server will need to be started in a separate process. This can be done using the following command (which is part of any standard IDL installation):

idlrpc