-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Make
register_plugin
a standalone function and include shared…
… lib discovery (#14804) Co-authored-by: Stijn de Gooijer <[email protected]>
- Loading branch information
1 parent
8c34bcc
commit 71a6563
Showing
11 changed files
with
372 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
======= | ||
Plugins | ||
======= | ||
.. currentmodule:: polars | ||
|
||
Plugins allow for extending Polars' functionality. See the | ||
`user guide <https://docs.pola.rs/user-guide/expressions/plugins/>`_ for more information | ||
and resources. | ||
|
||
Available plugin utility functions are: | ||
|
||
.. automodule:: polars.plugins | ||
:members: | ||
:autosummary: | ||
:autosummary-no-titles: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
from __future__ import annotations | ||
|
||
import contextlib | ||
from pathlib import Path | ||
from typing import TYPE_CHECKING, Any, Iterable | ||
|
||
from polars._utils.parse_expr_input import parse_as_list_of_expressions | ||
from polars._utils.wrap import wrap_expr | ||
|
||
with contextlib.suppress(ImportError): # Module not available when building docs | ||
import polars.polars as plr | ||
|
||
if TYPE_CHECKING: | ||
from polars import Expr | ||
from polars.type_aliases import IntoExpr | ||
|
||
__all__ = ["register_plugin_function"] | ||
|
||
|
||
def register_plugin_function( | ||
*, | ||
plugin_path: Path | str, | ||
function_name: str, | ||
args: IntoExpr | Iterable[IntoExpr], | ||
kwargs: dict[str, Any] | None = None, | ||
is_elementwise: bool = False, | ||
changes_length: bool = False, | ||
returns_scalar: bool = False, | ||
cast_to_supertype: bool = False, | ||
input_wildcard_expansion: bool = False, | ||
pass_name_to_apply: bool = False, | ||
) -> Expr: | ||
""" | ||
Register a plugin function. | ||
See the `user guide <https://docs.pola.rs/user-guide/expressions/plugins/>`_ | ||
for more information about plugins. | ||
Parameters | ||
---------- | ||
plugin_path | ||
Path to the plugin package. Accepts either the file path to the dynamic library | ||
file or the path to the directory containing it. | ||
function_name | ||
The name of the Rust function to register. | ||
args | ||
The arguments passed to this function. These get passed to the `input` | ||
argument on the Rust side, and have to be expressions (or be convertible | ||
to expressions). | ||
kwargs | ||
Non-expression arguments to the plugin function. These must be | ||
JSON serializable. | ||
is_elementwise | ||
Indicate that the function operates on scalars only. This will potentially | ||
trigger fast paths. | ||
changes_length | ||
Indicate that the function will change the length of the expression. | ||
For example, a `unique` or `slice` operation. | ||
returns_scalar | ||
Automatically explode on unit length if the function ran as final aggregation. | ||
This is the case for aggregations like `sum`, `min`, `covariance` etc. | ||
cast_to_supertype | ||
Cast the input expressions to their supertype. | ||
input_wildcard_expansion | ||
Expand wildcard expressions before executing the function. | ||
pass_name_to_apply | ||
If set to `True`, the `Series` passed to the function in a group-by operation | ||
will ensure the name is set. This is an extra heap allocation per group. | ||
Returns | ||
------- | ||
Expr | ||
Warnings | ||
-------- | ||
This is highly unsafe as this will call the C function loaded by | ||
`plugin::function_name`. | ||
The parameters you set dictate how Polars will handle the function. | ||
Make sure they are correct! | ||
""" | ||
pyexprs = parse_as_list_of_expressions(args) | ||
serialized_kwargs = _serialize_kwargs(kwargs) | ||
plugin_path = _resolve_plugin_path(plugin_path) | ||
|
||
return wrap_expr( | ||
plr.register_plugin_function( | ||
plugin_path=str(plugin_path), | ||
function_name=function_name, | ||
args=pyexprs, | ||
kwargs=serialized_kwargs, | ||
is_elementwise=is_elementwise, | ||
input_wildcard_expansion=input_wildcard_expansion, | ||
returns_scalar=returns_scalar, | ||
cast_to_supertype=cast_to_supertype, | ||
pass_name_to_apply=pass_name_to_apply, | ||
changes_length=changes_length, | ||
) | ||
) | ||
|
||
|
||
def _serialize_kwargs(kwargs: dict[str, Any] | None) -> bytes: | ||
"""Serialize the function's keyword arguments.""" | ||
if not kwargs: | ||
return b"" | ||
|
||
import pickle | ||
|
||
# Use the highest pickle protocol supported the serde-pickle crate: | ||
# https://docs.rs/serde-pickle/latest/serde_pickle/ | ||
return pickle.dumps(kwargs, protocol=5) | ||
|
||
|
||
def _resolve_plugin_path(path: Path | str) -> Path: | ||
"""Get the file path of the dynamic library file.""" | ||
if not isinstance(path, Path): | ||
path = Path(path) | ||
|
||
if path.is_file(): | ||
return path.resolve() | ||
|
||
for p in path.iterdir(): | ||
if _is_dynamic_lib(p): | ||
return p.resolve() | ||
else: | ||
msg = f"no dynamic library found at path: {path}" | ||
raise FileNotFoundError(msg) | ||
|
||
|
||
def _is_dynamic_lib(path: Path) -> bool: | ||
return path.is_file() and path.suffix in (".so", ".dll", ".pyd") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.