Skip to content

Commit 6a31b9f

Browse files
committed
Update docs
1 parent 4250732 commit 6a31b9f

3 files changed

Lines changed: 39 additions & 89 deletions

File tree

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44

55
Generate Python bindings with [pyml](https://github.com/thierry-martinez/pyml) directly from OCaml value specifications.
66

7-
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!! 💖
7+
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!! 💖
88

99
## Quick start
1010

11-
First, install `pyml_bindgen`. It is available on [Opam](https://opam.ocaml.org/packages/pyml_bindgen/).
11+
First, install `pyml_bindgen`. It is available on [Opam](https://opam.ocaml.org/packages/pyml_bindgen/).
1212

1313
```
1414
$ opam install pyml_bindgen
1515
```
1616

17-
Say you have a Python class you want to bind and use in OCaml. (Filename: `adder.py`)
17+
Say you have a Python class you want to bind and use in OCaml. (Filename: `adder.py`)
1818

1919
```python
2020
class Adder:
@@ -23,7 +23,7 @@ class Adder:
2323
return x + y
2424
```
2525

26-
To do so, you write OCaml value specifications for the class and methods you want to bind. (Filename: `val_specs.txt`)
26+
To do so, you write OCaml value specifications for the class and methods you want to bind. (Filename: `val_specs.txt`)
2727

2828
```ocaml
2929
val add : x:int -> y:int -> unit -> int
@@ -35,7 +35,7 @@ Then, you run `pyml_bindgen`.
3535
$ pyml_bindgen val_specs.txt adder Adder --caml-module Adder > lib.ml
3636
```
3737

38-
Now you can use your generated functions in your OCaml code. (Filename: `run.ml`)
38+
Now you can use your generated functions in your OCaml code. (Filename: `run.ml`)
3939

4040
```ocaml
4141
open Lib
@@ -63,13 +63,13 @@ $ dune exec ./run.exe
6363

6464
For information on installing and using `pyml_bindgen`, check out the [docs](https://mooreryan.github.io/ocaml_python_bindgen/).
6565

66-
Additionally, you can find examples in the [examples](https://github.com/mooreryan/ocaml_python_bindgen/tree/main/examples) directory. One neat thing about these examples is that you can see how to write Dune [rules](https://dune.readthedocs.io/en/stable/dune-files.html#rule) to automatically generate your `pyml` bindings.
66+
Additionally, you can find examples in the [examples](https://github.com/mooreryan/ocaml_python_bindgen/tree/main/examples) directory. One neat thing about these examples is that you can see how to write Dune [rules](https://dune.readthedocs.io/en/stable/dune-files.html#rule) to automatically generate your `pyml` bindings.
6767

6868
## License
6969

7070
[![license MIT or Apache
7171
2.0](https://img.shields.io/badge/license-MIT%20or%20Apache%202.0-blue)](https://github.com/mooreryan/pasv)
7272

73-
Copyright (c) 2021 Ryan M. Moore.
73+
Copyright (c) 2021 - 2022 Ryan M. Moore.
7474

7575
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.

_docs_src/src/tuples.md

Lines changed: 8 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,14 @@
11
# Handling Tuples
22

3-
*Note: You can find in-depth examples of binding dictionaries [here](dictionaries.md) and [here](dictionaries-2.md). A lot of the same ideas apply to tuples, and they are currently better explained in those links!*
3+
As of version 0.3.0, you can handle certain types of tuples directly.
44

5-
Tuples are sort of weird....As of now, `pyml_bindgen` can't handle tuples directly :(
5+
- You can now bind tuples with 2, 3, 4, or 5 elements.
6+
- They can be passed in as arguments, or returned from functions.
7+
- Only basic types and Python objects are allowed in tuples.
8+
- You can also put tuples inside of collections, e.g., `(int * string) list`, but not Options or Or_errors.
69

7-
For now what you need to do is to create a little helper module that "wraps" the tuple you need to pass in to Python or return from Python. *(Or just write the binding by hand...)*
10+
If you need something more complicated then that, you will have to use some of the same tricks I talk about in the [dictionaries](dictionaries.md) or [dictionaries-2](dictionaries-2.md) help pages.
811

9-
Say you need to get an `int * string` tuple in and out of Python. You should make a module something like this:
12+
## Examples
1013

11-
```ocaml
12-
module rec Tuple_int_string : sig
13-
type t
14-
15-
val make : int -> string -> t
16-
17-
val to_pyobject : t -> Pytypes.pyobject
18-
val of_pyobject : Pytypes.pyobject -> t
19-
20-
val print_endline : t -> unit
21-
end = struct
22-
type t = int * string
23-
24-
let make i s = (i, s)
25-
26-
let to_pyobject (i, s) =
27-
Py.Tuple.of_tuple2 (Py.Int.of_int i, Py.String.of_string s)
28-
29-
let of_pyobject pyo =
30-
let i, s = Py.Tuple.to_tuple2 pyo in
31-
(Py.Int.to_int i, Py.String.to_string s)
32-
33-
let print_endline (i, s) = print_endline @@ string_of_int i ^ " " ^ s
34-
end
35-
```
36-
37-
Then you can put that with the code that `pyml_bindgen` generates for whatever class you're actually trying to bind. Perhaps something like this...
38-
39-
```ocaml
40-
module rec Tuple_int_string : sig
41-
...
42-
end = struct
43-
...
44-
end
45-
46-
and My_cool_thing : sig
47-
48-
...
49-
50-
val foo : x:Tuple_int_string.t -> unit -> Tuple_int_string.t
51-
52-
...
53-
54-
end
55-
```
56-
57-
(You get the idea.)
58-
59-
In the val specs that you write, just refer to the `Tuple_int_string` module like any other:
60-
61-
```ocaml
62-
val foo : x:Tuple_int_string.t -> unit -> Tuple_int_string.t
63-
```
64-
65-
The key here is to have a module that has working `to_pyobject` and `of_pyobject` functions. If these two functions know how to properly get your type/module into and out of Python-land, then it should work :)
66-
67-
There is a Cram test [here](https://github.com/mooreryan/pyml_bindgen/tree/main/test/binding_tuples.t) that illustrates this idea. Just note that some of the bash stuff in the `run.t` file is to automate it, but you'd probably do that part by hand.
68-
69-
*Note: At some point, I will work up a full example with tuples and other types that you can't yet deal with directly in `pyml_bindgen`.
14+
You can find examples of binding tuples [here](https://github.com/mooreryan/ocaml_python_bindgen/tree/main/examples/tuples).

_docs_src/src/types.md

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,19 @@ There are a lot of [tests](https://github.com/mooreryan/pyml_bindgen/tree/main/t
88

99
For function arguments, you can use
1010

11-
* `float`
12-
* `string`
13-
* `bool`
14-
* `t` (i.e., the main type of the current module)
15-
* Other module types (e.g., `Span.t`, `Doc.t`, `Apple_pie.t`)
16-
* Arrays of any of the above types
17-
* Lists of any of the above types
18-
* Seq.t of any of the above types
19-
* `'a option`, `'a option array`, `'a option list`, `'a option Seq.t`
20-
* `Pytypes.pyobject` or `Py.Object.t` if you need to deal with `pytypes` directly
21-
22-
Note that your types must be newly minted modules. E.g.,
11+
- `float`
12+
- `string`
13+
- `bool`
14+
- `t` (i.e., the main type of the current module)
15+
- Other module types (e.g., `Span.t`, `Doc.t`, `Apple_pie.t`)
16+
- Arrays of any of the above types
17+
- Lists of any of the above types
18+
- Seq.t of any of the above types
19+
- `'a option`, `'a option array`, `'a option list`, `'a option Seq.t`
20+
- `Pytypes.pyobject` or `Py.Object.t` if you need to deal with `pytypes` directly
21+
- Certain kinds of tuples
22+
23+
Note that your custom types must be newly minted modules. E.g.,
2324

2425
```ocaml
2526
(* This is okay *)
@@ -38,35 +39,39 @@ let doc_to_pyobject ...
3839

3940
## Return types
4041

41-
For return types, you can use all of the above types plus `unit`, and `'a Or_error.t` for types `'a` other than `unit`. However, you cannot use `unit array`, `unit list`, or `unit Seq.t`. This is because I haven't decided the best way to handle `unit` and `None` (that's Python's `None`) quite yet!
42+
For return types, you can use all of the above types plus `unit`, and `'a Or_error.t` for types `'a` other than `unit`. However, you cannot use `unit array`, `unit list`, or `unit Seq.t`. This is because I haven't decided the best way to handle `unit` and `None` (that's Python's `None`) quite yet!
43+
44+
You can also return many kinds of tuples directly. See [here](tuples.md).
4245

4346
## Nesting
4447

45-
Note: currently, you're not allowed to have **nested** `array`, `list`, `Seq.t`, or `Or_error.t`. If you need them, you will have to bind those functions by hand :)
48+
Note: currently, you're not allowed to have **nested** `array`, `list`, `Seq.t`, or `Or_error.t`. If you need them, you will have to bind those functions by hand :)
4649

4750
E.g., `'a array list` will fail.
4851

4952
You are allowed to nest `'a option` in arrays, lists, and `Seq.t`s (e.g., `'a option list`); however, this will not work with `Or_error.t`.
5053

5154
## Pytypes
5255

53-
Sometimes you may want to deal directly with `Pytypes.pyobject` (a.k.a. `Py.Object.t`). Maybe you have a Python function that is truly polymorphic, or you just don't feel like giving a function a specific OCaml type for whatever reason. Regardless, you can use `Pytypes.pyobject` or `Py.Object.t` for this. Of course, you will be leaking a bit of the `pyml` implementation into your API, but sometimes that is unavoidable, or just more convenient than dealing with it in another way.
56+
Sometimes you may want to deal directly with `Pytypes.pyobject` (a.k.a. `Py.Object.t`). Maybe you have a Python function that is truly polymorphic, or you just don't feel like giving a function a specific OCaml type for whatever reason. Regardless, you can use `Pytypes.pyobject` or `Py.Object.t` for this. Of course, you will be leaking a bit of the `pyml` implementation into your API, but sometimes that is unavoidable, or just more convenient than dealing with it in another way.
5457

5558
Note that you currently are not allowed to nest `pytypes` in any of the containers or monads.
5659

57-
## Dictionaries & Tuples
60+
## Tuples
5861

59-
See [here](dictionaries.md) and [here](dictionaries-2.md) for examples of binding dictionaries.
62+
You can handle many kinds of tuples directly. See [here](tuples.md).
6063

61-
If you need to pass or return tuples to Python functions, see [here](tuples.md); however, the same ideas apply to tuples as are covered in the above links for dictionaries.
64+
## Dictionaries
65+
66+
See [here](dictionaries.md) and [here](dictionaries-2.md) for examples of binding dictionaries.
6267

6368
Alternatively, you could mark them as `Pytypes.pyobject` or `Py.Object.t` and let the caller deal with them in some way.
6469

6570
## Placeholders
6671

6772
There are two placeholders you can use: `todo` and `not_implemented`.
6873

69-
If you're binding a large library and you aren't planning on implementing a function, but you want it in the signature for whatever reason, you can use `not_implemented`. If you are planning to come back and implement a function later, you can use `todo`.
74+
If you're binding a large library and you aren't planning on implementing a function, but you want it in the signature for whatever reason, you can use `not_implemented`. If you are planning to come back and implement a function later, you can use `todo`.
7075

7176
```ocaml
7277
val f : 'a todo

0 commit comments

Comments
 (0)