OCaml-Python Bindings Generator
Generate Python bindings with pyml directly from OCaml value specifications.
While you could write all your Python bindings by hand, it can be tedious and it gets old real quick. While
pyml_bindgen can't yet auto-generate all the bindings you may need, it can definitely take care of a lot of the tedious and repetitive work you need to do when writing bindings for a big Python library!! 💖
How to get started
Getting started with a new package or library and going through lots of docs can be frustrating. Here's the order I would suggest you look at these docs
- Read the installing and quick start sections of this page.
- Then read through the getting started tutorial. If you only read one page in the docs, make it this one! It explains most of what you need to know to get started with a simple example, while not getting bogged down in too much details.
- Next, you can either peruse the rules for writing value specifications that
pyml_bindgencan understand, or check out more examples.
If you have any questions or issues, please let me know about it on GitHub!
pyml_bindgen is available on Opam. You can install it in the normal way:
$ opam install pyml_bindgen
You can also install from source.
pyml_bindgen is a Dune project, so you should be able to clone the repository and build it with
dune as long as you have the proper dependencies installed 🤞
$ git clone https://github.com/mooreryan/pyml_bindgen.git $ cd pyml_bindgen $ opam install . --deps-only --with-doc --with-test $ dune test && dune build --profile=release && dune install $ pyml_bindgen --help ... help screen should show up ...
pyml_bindgen is a CLI program that generates OCaml modules that bind Python classes via pyml.
Here's a small example. Take a Python class,
Thing. (Put it in a file called
thing.py...this means the Python module will be called
class Thing: def __init__(self, x): self.x = x def add(self, y): return self.x + y
Now, look at your Python class and decide how you would like to use this class on the OCaml side.
For now, we will just do a direct translation, keeping in mind the rules for writing value specs that
pyml_bindgen can process. Maybe something like this. (Put it in a file called
val __init__ : x:int -> unit -> t val x : t -> int val add : t -> y:int -> unit -> int
Finally, to generate the OCaml code, run the
pyml_bindgen program. There are a couple of options you can choose, but let's just keep it simple for now.
$ pyml_bindgen val_specs.txt thing Thing --caml-module=Thing > lib.ml $ ocamlformat --enable-outside-detected-project lib.ml
And here's the output of the
module Thing : sig type t val of_pyobject : Pytypes.pyobject -> t option val to_pyobject : t -> Pytypes.pyobject val __init__ : x:int -> unit -> t val x : t -> int val add : t -> y:int -> unit -> int end = struct let filter_opt l = List.filter_map Fun.id l let import_module () = Py.Import.import_module "thing" type t = Pytypes.pyobject let is_instance pyo = let py_class = Py.Module.get (import_module ()) "Thing" in Py.Object.is_instance pyo py_class let of_pyobject pyo = if is_instance pyo then Some pyo else None let to_pyobject x = x let __init__ ~x () = let callable = Py.Module.get (import_module ()) "Thing" in let kwargs = filter_opt [ Some ("x", Py.Int.of_int x) ] in of_pyobject @@ Py.Callable.to_function_with_keywords callable [||] kwargs let x t = Py.Int.to_int @@ Py.Object.find_attr_string t "x" let add t ~y () = let callable = Py.Object.find_attr_string t "add" in let kwargs = filter_opt [ Some ("y", Py.Int.of_int y) ] in Py.Int.to_int @@ Py.Callable.to_function_with_keywords callable [||] kwargs end
Check out the examples for more info about using and running
pyml_bindgen. Then, check out the rules that you have to follow when writing value specifications that
pyml_bindgen can read.
Copyright (c) 2021 Ryan M. Moore.
Licensed under the Apache License, Version 2.0 or the MIT license, at your option. This program may not be copied, modified, or distributed except according to those terms.
Copyright (c) 2021 Ryan M. Moore.
This documentation is licensed under a Creative Commons Attribution 4.0 International License.