#!/usr/bin/env python3
#####
#
# aspy.py
#
# Andy Hammerlindl 2011/09/03
#
# Uses ctypes to interface with the shared library version of Python.
# Asymptote can run and its datatypes inspected via Python.
#
#
# To use the module:
# 1. make asymptote.so
# 2. Ensure that asymptote.so is visable to python, say adding its directory
# to LD_LIBRARY_PATH
# 3. Run this module. (See runExample for an example.)
#
#####
def pyStringFromAsyString(st):
#TODO: Handle strings with null-terminators.
return str(st.buf)
def pyStringFromHandle(h):
#TODO: Handle strings with null-terminators.
st = policy.contents.stringFromHandle(h)
checkForErrors()
return pyStringFromAsyString(st)
def handleFromPyString(s):
st = string_typ(s, len(s))
h = policy.contents.handleFromString(st)
checkForErrors()
return h
def ensureDatum(val):
return val if type(val) is Datum else Datum(val)
# The error detection scheme.
# policyError is set to a string when an error occurs.
policyError = []
def pyErrorCallback(s):
global policyError
policyError.append(pyStringFromAsyString(s))
def checkForErrors():
"""Raises an exception if an error occured."""
global policyError
if policyError != []:
s = policyError[0]
if len(policyError) > 1:
s += ' (and other errors)'
policyError = []
raise AsyException(s)
if type(val) is int:
self._setHandle(policy.contents.handleFromInt(val))
checkForErrors()
elif type(val) is bool:
self._setHandle(policy.contents.handleFromBool(1 if val else 0))
checkForErrors()
elif type(val) is float:
self._setHandle(policy.contents.handleFromDouble(val))
elif type(val) is str:
self._setHandle(handleFromPyString(val))
checkForErrors()
elif type(val) is tuple:
# Could do this more efficiently, and avoid a copyHandle
ret = state.globals()["operator tuple"](*val)
self._setHandle(policy.contents.copyHandle(ret.handle))
checkForErrors()
elif type(val) is Datum:
self._setHandle(policy.contents.copyHandle(val.handle))
checkForErrors()
else:
# TODO: check if val has a toDatum field
raise TypeError("cannot initialize Datum from '%s'" %
type(val).__name__)
def __repr__(self):
# TODO: Add type-checking to policy.
return '<Datum with handle %s>' % hex(self.handle)
def __int__(self):
l = policy.contents.IntFromHandle(self.handle)
checkForErrors()
return int(l)
def __nonzero__(self):
# This will throw an exception for anything but an underlying bool
# type. Perhaps we should be more pythonic.
l = policy.contents.boolFromHandle(self.handle)
checkForErrors()
assert l in [0,1]
return l == 1
def __float__(self):
x = policy.contents.doubleFromHandle(self.handle)
checkForErrors()
return float(x)
def __getattr__(self, name):
field = policy.contents.getField(self.handle, name)
checkForErrors()
return DatumFromHandle(field)
def __getitem__(self, name):
assert type(name) == str
return self.__getattr__(name)
#TODO: raise an IndexError when appropriate.
#TODO: implement array indices
def __setattr__(self, name, val):
# TODO: Resolve setting versus declaring.
# One idea: d.x = f or d["x"] = f sets and d["int x()"] = f declares
# anew.
policy.contents.addField(self.handle,
name, ensureDatum(val).handle)
checkForErrors()
def __setitem__(self, name, val):
assert type(name) == str
self.__setattr__(name, val)
#TODO: raise an IndexError when appropriate.
#TODO: implement array indices
def DatumFromHandle(handle):
"""Initializes a Datum from a given low-level handle. Does not invoke
copyHandle."""
d = Datum(None)
d._setHandle(handle)
return d
class State(object):
def __init__(self, base):
self.base = base