Skip to content
Draft

v1 #673

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
branches:
- main
- v1
tags:
- '*'
pull_request:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
pull_request:
branches:
- main
- v1
push:
branches:
- main
Expand Down
20 changes: 11 additions & 9 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
UnsafePointers = "e17b2a0c-0bdf-430a-bd0c-3a23cae4ff39"

[weakdeps]
CategoricalArrays = "324d7699-5711-5eae-9e2f-1d82baa6b597"
PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"

[extensions]
CategoricalArraysExt = "CategoricalArrays"
PyCallExt = "PyCall"

[compat]
Aqua = "0 - 999"
CategoricalArrays = "0.10, 1"
Expand All @@ -24,27 +32,21 @@ MacroTools = "0.5"
Markdown = "1"
Pkg = "1"
PyCall = "1"
REPL = "1"
Serialization = "1"
Tables = "1"
Test = "1"
TestItemRunner = "0 - 999"
UnsafePointers = "1"
julia = "1.9"

[extensions]
PyCallExt = "PyCall"
CategoricalArraysExt = "CategoricalArrays"

[extras]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
CategoricalArrays = "324d7699-5711-5eae-9e2f-1d82baa6b597"
PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TestItemRunner = "f8b46487-2199-4994-9208-9a1283c18c0a"

[targets]
test = ["Aqua", "PyCall", "Test", "TestItemRunner"]

[weakdeps]
CategoricalArrays = "324d7699-5711-5eae-9e2f-1d82baa6b597"
PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
test = ["Aqua", "PyCall", "Test", "TestItemRunner", "REPL"]
2 changes: 1 addition & 1 deletion docs/src/conversion-to-julia.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ From Python, the arguments to a Julia function will be converted according to th
| From | To |
| :----------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------- |
| **Top priority (wrapped values).** | |
| `juliacall.AnyValue` | `Any` |
| `juliacall.Jl` | `Any` |
| **Very high priority (arrays).** | |
| Objects satisfying the buffer or array interface (inc. `bytes`, `bytearray`, `array.array`, `numpy.ndarray`) | `PyArray` |
| **High priority (canonical conversions).** | |
Expand Down
23 changes: 6 additions & 17 deletions docs/src/conversion-to-python.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,13 @@ From Python, this occurs when converting the return value of a Julia function.
| `Dates.Time` | `datetime.time` |
| `Dates.DateTime` | `datetime.datetime` |
| `Dates.Second`, `Dates.Millisecond`, `Dates.Microsecond`, `Dates.Nanosecond` | `datetime.timedelta` |
| `Number` | `juliacall.NumberValue`, `juliacall.ComplexValue`, etc. |
| `AbstractArray` | `juliacall.ArrayValue`, `juliacall.VectorValue` |
| `AbstractDict` | `juliacall.DictValue` |
| `AbstractSet` | `juliacall.SetValue` |
| `IO` | `juliacall.BufferedIOValue` |
| `Module` | `juliacall.ModuleValue` |
| `Type` | `juliacall.TypeValue` |
| Anything else | `juliacall.AnyValue` |
| `AbstractArray` | `juliacall.JlArray`, `juliacall.JlVector` |
| `AbstractDict` | `juliacall.JlDict` |
| `AbstractSet` | `juliacall.JlSet` |
| `IO` | `juliacall.JlBinaryIO` |
| Anything else | `juliacall.Jl` |

See [here](@ref julia-wrappers) for an explanation of the `juliacall.*Value` wrapper types.
See [here](@ref julia-wrappers) for an explanation of the `juliacall.Jl*` wrapper types.

## [Custom rules](@id jl2py-conversion-custom)

Expand All @@ -47,11 +44,3 @@ object, then also define `ispy(::T) = true`.
```@docs
PythonCall.ispy
```

Alternatively, if you define a wrapper type (a subtype of
[`juliacall.AnyValue`](#juliacall.AnyValue)) then you may instead define `pyjltype(::T)` to
be that type.

```@docs
PythonCall.pyjltype
```
2 changes: 1 addition & 1 deletion docs/src/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Related issues:

## Issues when Numpy arrays are expected

When a Julia array is passed to Python, it is wrapped as a [`ArrayValue`](#juliacall.ArrayValue).
When a Julia array is passed to Python, it is wrapped as a [`JlArray`](#juliacall.JlArray).
This type satisfies the Numpy array interface and the buffer protocol, so can be used in
most places where a numpy array is valid.

Expand Down
165 changes: 52 additions & 113 deletions docs/src/juliacall-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
`````@customdoc
juliacall.Main - Constant

The Julia `Main` module, as a [`ModuleValue`](#juliacall.ModuleValue).
The Julia `Main` module, as a [`Jl`](#juliacall.Jl).

In interactive scripts, you can use this as the main entry-point to JuliaCall:
```python
Expand All @@ -20,18 +20,6 @@ The modules `Base`, `Core` and `PythonCall` are also available.

## Utilities

`````@customdoc
juliacall.convert - Function

```python
convert(T, x)
```

Convert `x` to a Julia object of type `T`.

You can use this to pass an argument to a Julia function of a specific type.
`````

`````@customdoc
juliacall.newmodule - Function

Expand All @@ -45,75 +33,71 @@ A new module with the given name.
## [Wrapper types](@id julia-wrappers)

Apart from a few fundamental immutable types, all Julia values are by default converted into
Python to some [`AnyValue`](#juliacall.AnyValue) object, which wraps the original value, but
giving it a Pythonic interface.

Subclasses of [`AnyValue`](#juliacall.AnyValue) provide additional Python semantics. For
example a Julia vector is converted to a [`VectorValue`](#juliacall.VectorValue) which
satisfies the Python sequence interface and behaves very similar to a list.

There is also a [`RawValue`](#juliacall.RawValue) object, which gives a stricter
"Julia-only" interface, documented below. These types all inherit from `ValueBase`:

- `ValueBase`
- [`RawValue`](#juliacall.RawValue)
- [`AnyValue`](#juliacall.AnyValue)
- [`NumberValue`](#juliacall.NumberValue)
- `ComplexValue`
- `RealValue`
- `RationalValue`
- `IntegerValue`
- [`ArrayValue`](#juliacall.ArrayValue)
- [`VectorValue`](#juliacall.VectorValue)
- [`DictValue`](#juliacall.DictValue)
- [`SetValue`](#juliacall.SetValue)
- [`IOValue`](#juliacall.IOValue)
- `BinaryIOValue`
- `TextIOValue`
- [`ModuleValue`](#juliacall.ModuleValue)
- [`TypeValue`](#juliacall.TypeValue)
Python to a [`Jl`](#juliacall.Jl) object, which wraps the original value and gives it a
Pythonic interface.

Other wrapper classes provide more specific Python semantics. For example a Julia vector can
be converted to a [`JlVector`](#juliacall.JlVector) which satisfies the Python sequence
interface and behaves very similar to a list.

- `JlBase`
- [`Jl`](#juliacall.Jl)
- [`JlCollection`](#juliacall.JlCollection)
- [`JlArray`](#juliacall.JlArray)
- [`JlVector`](#juliacall.JlVector)
- [`JlDict`](#juliacall.JlDict)
- [`JlSet`](#juliacall.JlSet)
- [`JlIOBase`](#juliacall.JlIOBase)
- `JlBinaryIO`
- `JlTextIO`

`````@customdoc
juliacall.AnyValue - Class
juliacall.Jl - Class

Wraps any Julia object, giving it some basic Python semantics. Subtypes provide extra
semantics.
Wraps any Julia object, giving it some basic Python semantics.

Supports `repr(x)`, `str(x)`, attributes (`x.attr`), calling (`x(a,b)`), iteration,
comparisons, `len(x)`, `a in x`, `dir(x)`.

Calling, indexing, attribute access, etc. will convert the result to a Python object
according to [this table](@ref jl2py). This is typically a builtin Python type (for
immutables) or a subtype of `AnyValue`.
Calling, indexing, attribute access, etc. will always return a `Jl`. To get the result
as an ordinary Python object, you can use the `.jl_to_py()` method.

Attribute access can be used to access Julia properties as well as normal class members. In
the case of a name clash, the class member will take precedence. For convenience with Julia
naming conventions, `_b` at the end of an attribute is replaced with `!` and `_bb` is
replaced with `!!`.
Attribute access (`x.attr`) can be used to access Julia properties except those starting
and ending with `__` (since these are Python special methods) or starting with `jl_` or
`_jl_` (which are reserved by `juliacall` for Julia-specific methods).

###### Members
- `_jl_raw()`: Convert to a [`RawValue`](#juliacall.RawValue). (See also [`pyjlraw`](@ref).)
- `_jl_display(mime=None)`: Display the object using Julia's display mechanism.
- `_jl_help(mime=None)`: Display help for the object.
- `_jl_call_nogil(*args, **kwargs)`: Call this with the GIL disabled.
- `jl_callback(*args, **kwargs)`: Calls the Julia object with the given arguments.
Unlike ordinary calling syntax, the arguments are passed as `Py` objects instead of
being converted.
- `jl_call_nogil(*args, **kwargs)`: Call this with the GIL disabled.
- `jl_display()`: Display the object using Julia's display mechanism.
- `jl_eval(expr)`: If the object is a Julia `Module`, evaluates the given expression.
- `jl_help()`: Display help for the object.
- `jl_to_py()`: Convert to a Python object using the [usual conversion rules](@ref jl2py).
`````

`````@customdoc
juliacall.NumberValue - Class
juliacall.JlCollection - Class

Wraps any Julia collection. It is a subclass of `collections.abc.Collection`.

This wraps any Julia `Number` value. It is a subclass of `numbers.Number` and behaves
similar to other Python numbers.
Julia collections are arrays, sets, dicts, tuples, named tuples, refs, and in general
anything which is a collection of values in the sense that it supports functions like
`iterate`, `in`, `length`, `hash`, `==`, `isempty`, `copy`, `empty!`.

There are also subtypes `ComplexValue`, `RealValue`, `RationalValue`, `IntegerValue` which
wrap values of the corresponding Julia types, and are subclasses of the corresponding
`numbers` ABC.
It supports `in`, `iter`, `len`, `hash`, `bool`, `==`.

###### Members
- `clear()`: Empty the collection in-place.
- `copy()`: A copy of the collection.
`````

`````@customdoc
juliacall.ArrayValue - Class
juliacall.JlArray - Class

This wraps any Julia `AbstractArray` value. It is a subclass of
`collections.abc.Collection`.
`juliacall.JlCollection`.

It supports zero-up indexing, and can be indexed with integers or slices. Slicing returns a
view of the original array.
Expand All @@ -131,22 +115,20 @@ copy of the original array.
###### Members
- `ndim`: The number of dimensions.
- `shape`: Tuple of lengths in each dimension.
- `copy()`: A copy of the array.
- `reshape(shape)`: A reshaped view of the array.
- `to_numpy(dtype=None, copy=True, order="K")`: Convert to a numpy array.
`````

`````@customdoc
juliacall.VectorValue - Class
juliacall.JlVector - Class

This wraps any Julia `AbstractVector` value. It is a subclass of `juliacall.ArrayValue` and
This wraps any Julia `AbstractVector` value. It is a subclass of `juliacall.JlArray` and
`collections.abc.MutableSequence` and behaves similar to a Python `list`.

###### Members
- `resize(size)`: Change the length of the vector.
- `sort(reverse=False, key=None)`: Sort the vector in-place.
- `reverse()`: Reverse the vector.
- `clear()`: Empty the vector.
- `insert(index, value)`: Insert the value at the given index.
- `append(value)`: Append the value to the end of the vector.
- `extend(values)`: Append the values to the end of the vector.
Expand All @@ -157,66 +139,23 @@ This wraps any Julia `AbstractVector` value. It is a subclass of `juliacall.Arra
`````

`````@customdoc
juliacall.DictValue - Class
juliacall.JlDict - Class
This wraps any Julia `AbstractDict` value. It is a subclass of `collections.abc.Mapping` and
behaves similar to a Python `dict`.
`````

`````@customdoc
juliacall.SetValue - Class
juliacall.JlSet - Class
This wraps any Julia `AbstractSet` value. It is a subclass of `collections.abc.Set` and
behaves similar to a Python `set`.
`````

`````@customdoc
juliacall.IOValue - Class
juliacall.JlIOBase - Class

This wraps any Julia `IO` value. It is a subclass of `io.IOBase` and behaves like Python
files.

There are also subtypes `BinaryIOValue` and `TextIOValue`, which are subclasses of
There are also subtypes `JlBinaryIO` and `JlTextIO`, which are subclasses of
`io.BufferedIOBase` (buffered bytes) and `io.TextIOBase` (text).
`````

`````@customdoc
juliacall.ModuleValue - Class
This wraps any Julia `Module` value.

It is the same as [`AnyValue`](#juliacall.AnyValue) except for one additional convenience
method:
- `seval([module=self], code)`: Evaluates the given code (a string) in the given module.
`````

`````@customdoc
juliacall.TypeValue - Class

This wraps any Julia `Type` value.

It is the same as [`AnyValue`](#juliacall.AnyValue) except that indexing is used to access
Julia's "curly" syntax for specifying parametric types:

```python
from juliacall import Main as jl
# equivalent to Vector{Int}() in Julia
jl.Vector[jl.Int]()
```
`````

`````@customdoc
juliacall.RawValue - Class

Wraps any Julia value with a rigid interface suitable for generic programming.

Supports `repr(x)`, `str(x)`, attributes (`x.attr`), calling (`x(a,b)`), `len(x)`, `dir(x)`.

This is very similar to [`AnyValue`](#juliacall.AnyValue) except that indexing, calling,
etc. will always return a `RawValue`.

Indexing with a tuple corresponds to indexing in Julia with multiple values. To index with a
single tuple, it will need to be wrapped in another tuple.

###### Members
- `_jl_any()`: Convert to a [`AnyValue`](#juliacall.AnyValue) (or subclass). (See also
[`pyjl`](@ref).)
- `_jl_call_nogil(*args, **kwargs)`: Call this with the GIL disabled.
`````
6 changes: 3 additions & 3 deletions docs/src/juliacall.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ import juliacall
jl = juliacall.newmodule("SomeName")
```

Julia modules have a special method `seval` which will evaluate a given piece of code given
Julia modules have a special method `jl_eval` which will evaluate a given piece of code given
as a string in the module. This is most frequently used to import modules:
```python
from array import array
jl.seval("using Statistics")
jl.jl_eval("using Statistics")
x = array('i', [1, 2, 3])
jl.mean(x)
# 2.0
Expand All @@ -64,7 +64,7 @@ jl.cor(x, y)
```

What to read next:
- The main functionality of this package is in `AnyValue` objects, which represent Julia
- The main functionality of this package is in `Jl` objects, which represent Julia
objects, [documented here](@ref julia-wrappers).
- If you need to install Julia packages, [read here](@ref julia-deps).
- When you call a Julia function, such as `jl.rand(...)` in the above example, its
Expand Down
4 changes: 3 additions & 1 deletion docs/src/pythoncall-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,13 @@ conversion to Python, unless the value is immutable and has a corresponding Pyth

```@docs
pyjl
pyjlraw
pyisjl
pyjlvalue
pybinaryio
pytextio
pyjlarray
pyjlset
pyjldict
```

## Arithmetic
Expand Down
Loading
Loading