# Pycaml

## What is Pycaml

A library written by arty@users.sourceforge.net which follows the Python/C API as closely as possible, while providing equivalent functionality for objective caml. This is built against python 2.x and Ocaml 3.04.

It is intended to allow users to build native ocaml libraries and use them from python, and alternately, in order to allow ocaml users to benefit from linkable libraries provided for python.

I created this library in order to take advantage of python binding for certain native libraries from ocaml. While it is true that I could have written new interfaces specifically for ocaml, the python interface is sufficient for my needs, and this project was easier.

Note: Unfortunately, the symbol `init_exceptions` exists in both compiled ocaml code, and the python runtime. In order to proceed, you must rename this symbol either in the ocaml distribution (in byterun/fail.c, and byterun/startup.c), or in the python distribution, and rebuild the software appropriately.

Please edit the `Makefile` to put in your system's libraries used for compiling programs embedded with python. This library compiles on most linux boxes without modification. The python interpreter is used to determine the path to the python library and must be in your path when you run make.

Get the distribution here:pycaml.tar.gz

Because these are made to closely mirror the python API, the user should become familiar with the python API.

Given Ocaml parameter passing convention, it was convenient to pass multiple arguments as members of a tuple, but single arguments without. Consequently, functions with arity 1, such as pytuple_new are called as

      pytuple_new 3 ;;

And functions with more arguments are called as

      pydict_getitemstring (dict,"keystring") ;;

## Module Pycaml

### Visible Types

type | pyobject
The abstract type of python objects.
type | pyobject_type =
| TupleType
| | StringType
| | IntType
| | FloatType
| | ListType
| | NoneType
| | CallableType
| | ModuleType
| | ClassType
| | TypeType
| | OtherType
The type representing the range of types available to python programs. Values of this type are provided by the pytype function, and identify the python type of opaque pyobject objects.

### Supported Functions from the Python/C API

In each case, the signature of the function is unchanged from the Python/C API except for the case of 'out' pointer to pointer parameters; in the case of a single return, the returned value is copied, otherwise, a tuple is created with copies of all output parameters. In the case of zero parameter, or void return, unit is used.

In python API functions that take a FILE *, an int file descriptor is used instead such as those returned by the Unix library.

#### fun unit -> unit

py_initialize, py_finalize, pyerr_print, pyerr_clear, pyimport_cleanup

#### fun int -> unit

py_exit, pyerr_printex

#### fun string -> unit

py_setprogramname, py_setpythonhome

#### fun unit -> int

py_isinitialized, pyeval_getrestricted

#### fun string -> int

pyrun_simplestring, pyimport_importfrozenmodule,

#### fun (int * string) -> int

pyrun_anyfile, pyrun_simplefile, pyrun_interactiveone, pyrun_interactiveloop, py_fdisinteractive

#### fun (int * string * int) -> int

pyrun_anyfileex, pyrun_simplefileex

#### fun unit -> string

py_getprogramname, py_getpthonhome, py_getprogramfullpath, py_getprefix, py_getexecprefix, py_getpath, py_getversion, py_getplatform, py_getcopyright, py_getcompiler, py_getbuildinfo

#### fun (string * int * pyobject * pyobject) -> pyobject

pyrun_string

#### fun (int * string * int * pyobject * pyobject) -> pyobject

pyrun_file

#### fun (int * string * int * pyobject * pyobject * int) -> pyobject

pyrun_fileex

#### fun (string * string * int) -> pyobject

py_compilestring

#### fun (pyobject * int * int) -> int

pyobject_print, pytuple_getslice, pysequence_getslice

#### fun pyobject -> pyobject

pyobject_repr, pyobject_str, pyobject_unicode, pydict_keys, pydict_values, pydict_items, pydict_copy, pymodule_getdict, pymethod_function, pymethod_self, pymethod_class, pymodule_getdict, pyimport_reloadmodule, pyobject_type, pynumber_negative, pynumber_positive, pynumber_absolute, pynumber_invert, pynumber_int, pynumber_long, pynumber_float, pysequence_tuple, pysequence_list

#### fun (pyobject * pyobject * int) -> pyobject

pyobject_richcompare

#### fun (pyobject * string) -> pyobject

pyobject_getattrstring, pydict_getitemstring, pysequence_fast, pymapping_haskeystring, pymapping_getitemstring

#### fun (pyobject * pyobject) -> pyobject

pyobject_getattr, pystring_format, pydict_getitem, pyinstance_newraw, pyeval_callobject, pyobject_getitem, pyobject_delitem, pynumber_add, pynumber_subtract, pynumber_multiply, pynumber_divide, pynumber_remainder, pynumber_divmod, pynumber_lshift, pynumber_rshift, pynumber_and, pynumber_xor, pynumber_or, pynumber_inplaceadd, pynumber_inplacesubtract, pynumber_inplacemultiply, pynumber_inplacedivide, pynumber_inplaceremainder, pynumber_inplacelshift, pynumber_inplacershift, pynumber_inplaceand, pynumber_inplacexor, pynumber_inplaceor, pysequence_concat, pysequence_inplaceconcat

#### fun pyobject -> int

pyobject_istrue, pyobject_not, pycalable_check, pystring_size, pydict_size, pytuple_new, pyerr_exceptionmatches, pyobject_size, pynumber_check, pysequence_check, pysequence_size, pysequence_length, pymapping_check, pymapping_size, pymapping_length, pyint_asint

#### fun (pyobject * pyobject) -> int

pyobject_compare, pyobject_hasattr, pydict_delitem, pyerr_givenexceptionmatches, pysequence_count, pysequence_contains, pysequence_in, pysequence_index, pymapping_haskey

#### fun (pyobject * pyobject * int) -> int

pyobject_richcomparebool, pysequence_delitem

#### fun (pyobject * string * pyobject) -> int

pyobject_setattrstring, pydict_setitemstring

#### fun (pyobject * string) -> int

pyobject_hasattrstring, pydict_delitemstring, pysequence_inplacerepeat

#### fun (pyobject * pyobject) -> (pyobject * pyobject)

pynumber_coerce, pynumber_coerceex

#### fun (pyobject * pyobject * pyobject) -> int

pyobject_setattr, pydict_setitem, pyobject_setitem

#### fun pyobject -> int64

pyobject_hash, pyint_aslong

#### fun pyobject -> string

pystring_asstring, pymodule_getname, pymodule_getfilename

#### fun (pyobject * pyobject) -> pyobject

pystring_concat, pystring_concatanddel

#### fun string -> pyobject

pystring_fromstring, pymodule_new, pyimport_addmodule, pyimport_importmodule, pyimport_import

#### fun unit -> pyobject

pydict_new, pyerr_occurred, pyimport_getmoduledict, pyeval_getbuiltins, pyeval_getglobals, pyeval_getlocals, pyeval_getframe

#### fun pyobject -> unit

pydict_clear, pyerr_setnone

#### fun (pyobject * int) -> (pyobject * pyobject * int)

pydict_next

#### fun int64 -> pyobject

pyint_fromlong

#### fun unit -> int64

pyint_getmax

#### fun float -> pyobject

pyfloat_fromdouble

#### fun pyobject -> float

pyfloat_asdouble

#### fun int -> pyobject

pytuple_new, pyint_fromint

#### fun (pyobject * int) -> pyobject

pytuple_getitem, pysequence_repeat, pysequence_getitem

#### fun (pyobject * int * pyobject) -> int

pytuple_setitem, pysequence_setitem, pymapping_setitem

#### fun (pyobject * pyobject * pyobject) -> pyobject

pyslice_new, pyclass_new, pyinstance_new, pymethod_new, pyeval_callobjectwithkeywords, pynumber_power, pynumber_inplacepower

#### fun (pyobject * int) -> (int * int * int)

pyslice_getindices

#### fun (int * int * int * int) -> pyobject

pyrange_new

#### fun (pyobject * pyobject) -> unit

pyerr_setobject

#### fun (pyobject * string) -> unit

pyerr_setstring

#### fun (pyobject * pyobject * pyobject) -> (pyobject * pyobject * pyobject)

pyerr_fetch, pyerr_normalizeexception

#### fun (pyobject * pyobject * pyobject) -> unit

pyerr_restore

#### fun (pyobject * string) -> pyobject

pyimport_execcodemodule

#### fun (string * pyobject * string) -> pyobject

pyimport_execcodemoduleex

#### fun (string * pyobject * pyobject * pyobject) -> pyobject

pyimport_importmoduleex

#### fun pyobject -> string

pyobject_ascharbuffer, pyobject_asreadbuffer, pyobject_aswritebuffer

#### fun (pyobject * int * int * pyobject) -> int

pysequence_setslice

#### fun (pyobject * int * int) -> int

pysequence_delslice

### Unique Functions Needed for Ocaml

In addition to the functions in the usual library, several new functions are provided which give specific support for ocaml.

pytuple_toarray | pyobject -> pyobject array
Convert a python tuple to an ocaml array containing the same items.
pywrap_closure | (pyobject -> pyobject) -> pyobject
Create a python callable object from a closure. The closure receives the argument tuple from the invocation and returns a pyobject.
pywrap_value | 'a -> pyobject
Create a simple void * style wrapping around an ocaml object. The object may be retrieved with `pyunwrap_value : pyobject -> 'a`. Use this to enclose an ocaml data structure in python to be used later.
pynull | unit -> pyobject
Generate the null PyObject * and return it. This may sound dangerous, but it is used by library calls to indicate errors to the python system.
pynone | unit -> pyobject
Generate a reference to the Py_None object.
pytuple_fromarray | pyobject array -> pyobject
Create a pytuple (as would be used for a function call) from the given array. This may be used to implement varargs calls on python functions, and for other purposes.
pytuple_empty | pyobject array -> pyobject
Shortcut for `pytuple_new 0`
pytuple_fromsingle | pyobject -> pyobject
Create a tuple with the single given object inside. Use this to create single element tuples as for a function call with one argument.
pytuple1-5 | (pyobject * ...) -> pyobject
Create a python tuple that has the same contents as the given ocaml tuple.
pytype | pyobject -> pyobject_type
Determine roughly which type family the given value belongs to. For example, `pytype (pystring_fromstring "hi")` yields `StringType`.

### Sample Application

This is the sample application that I developed the library with. It illustrates a python function call, as well as a call back into ocaml. The first form is used in cases where python libraries are to be used from ocaml, and the second would be used to produce native libraries in ocaml.

    open Pycaml ;;

    let colorsys = pyimport_importmodule "colorsys"
    let dict = pymodule_getdict colorsys

    let triplet = pytuple3 (pyfloat_fromdouble 1.0,
    			pyfloat_fromdouble 0.5,
    			pyfloat_fromdouble 0.2) ;;

    let rgbtoyiq = pydict_getitemstring (dict,"rgb_to_yiq")
    let triplet = pyeval_callobject (rgbtoyiq,triplet)

    let _ = print_endline ((string_of_float
    			  (pyfloat_asdouble (pytuple_getitem (triplet,0)))) ^
    		       " " ^
    		       (string_of_float
    			  (pyfloat_asdouble (pytuple_getitem (triplet,1)))) ^
    		       " " ^
    		       (string_of_float
    			  (pyfloat_asdouble (pytuple_getitem (triplet,2))))) ;;

    let x = pywrap_closure
        (fun x -> print_string (pystring_asstring (pytuple_getitem (x,0))) ;
          pynone ())

    let _ = pyeval_callobject
        (x,pytuple_fromsingle (pystring_fromstring "hi there"))