Skip to main content

Simplifying conditional Polars Expressions with Python ๐Ÿ ๐Ÿปโ€โ„๏ธ

Project description

polarIFy: Simplifying conditional Polars Expressions with Python ๐Ÿ ๐Ÿปโ€โ„๏ธ

License Build Status conda-forge pypi-version python-version codecov

Welcome to polarIFy, a Python function decorator that simplifies the way you write logical statements for Polars. With polarIFy, you can use Python's language structures like if / elif / else statements and transform them into pl.when(..).then(..).otherwise(..) statements. This makes your code more readable and less cumbersome to write. ๐ŸŽ‰

๐ŸŽฏ Usage

polarIFy can automatically transform Python functions using if / elif / else statements into Polars expressions.

Basic Transformation

Here's an example:

@polarify
def signum(x: pl.Expr) -> pl.Expr:
    s = 0
    if x > 0:
        s = 1
    elif x < 0:
        s = -1
    return s

This gets transformed into:

def signum(x: pl.Expr) -> pl.Expr:
    return pl.when(x > 0).then(1).otherwise(pl.when(x < 0).then(-1).otherwise(0))

Handling Multiple Statements

polarIFy can also handle multiple statements like:

@polarify
def multiple_if_statement(x: pl.Expr) -> pl.Expr:
    a = 1 if x > 0 else 5
    b = 2 if x < 0 else 2
    return a + b

which becomes:

def multiple_if_statement(x):
    return pl.when(x > 0).then(1).otherwise(5) + pl.when(x < 0).then(2).otherwise(2)

Handling Nested Statements

Additionally, it can handle nested statements:

@polarify
def nested_if_else(x: pl.Expr) -> pl.Expr:
    if x > 0:
        if x > 1:
            s = 2
        else:
            s = 1
    elif x < 0:
        s = -1
    else:
        s = 0
    return s

which becomes:

def nested_if_else(x: pl.Expr) -> pl.Expr:
    return pl.when(x > 0).then(pl.when(x > 1).then(2).otherwise(1)).otherwise(pl.when(x < 0).then(-1).otherwise(0))

So you can still write readable row-wise python code while the @polarify decorator transforms it into a function that works with efficient polars expressions.

Using a polarifyd function

import polars as pl
from polarify import polarify

@polarify
def complicated_operation(x: pl.Expr) -> pl.Expr:
    k = 0
    c = 2
    if x > 0:
        k = 1
        c = 0
        if x < 10:
            c = 1
    elif x < 0:
        k = -1
    return k * c


df = pl.DataFrame({"x": [-1, 1, 5, 10]})
result = df.select(pl.col("x"), complicated_operation(pl.col("x")))
print(result)
# shape: (4, 2)
# โ”Œโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
# โ”‚ x   โ”† literal โ”‚
# โ”‚ --- โ”† ---     โ”‚
# โ”‚ i64 โ”† i32     โ”‚
# โ•žโ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ก
# โ”‚ -1  โ”† -2      โ”‚
# โ”‚ 1   โ”† 1       โ”‚
# โ”‚ 5   โ”† 1       โ”‚
# โ”‚ 10  โ”† 0       โ”‚
# โ””โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Displaying the transpiled polars expression

You can also display the transpiled polars expression by calling the transform_func_to_new_source method:

from polarify import transform_func_to_new_source

def signum(x):
    s = 0
    if x > 0:
        s = 1
    elif x < 0:
        s = -1
    return s


print(f"Original function:\n{inspect.getsource(signum)}")
# Original function:
# def signum(x):
#     s = 0
#     if x > 0:
#         s = 1
#     elif x < 0:
#         s = -1
#     return s
print(f"Transformed function:\n{transform_func_to_new_source(signum)}")
# Transformed function:
# def signum_polarified(x):
#     import polars as pl
#     return pl.when(x > 0).then(1).otherwise(pl.when(x < 0).then(-1).otherwise(0))

TODO: complicated example with nested functions

โš™๏ธ How It Works

polarIFy achieves this by parsing the AST (Abstract Syntax Tree) of the function and transforming the body into a Polars expression by inlining the different branches. To get a more detailed understanding of what's happening under the hood, check out our blog post explaining how polarify works!

๐Ÿ’ฟ Installation

conda

conda install -c conda-forge polarify
# or micromamba
micromamba install -c conda-forge polarify
# or pixi
pixi add polarify

pip

pip install polarify

โš ๏ธ Limitations

polarIFy is still in an early stage of development and doesn't support the full Python language. Here's a list of the currently supported and unsupported operations:

Supported operations

  • if / else / elif statements
  • binary operations (like +, ==, >, &, |, ...)
  • unary operations (like ~, -, not, ...) (TODO)
  • assignments (like x = 1)
  • polars expressions (like pl.col("x"), TODO)
  • side-effect free functions that return a polars expression (can be generated by @polarify) (TODO)
  • match statements

Unsupported operations

  • for loops
  • while loops
  • break statements
  • := walrus operator
  • dictionary mappings in match statements
  • list matching in match statements
  • star patterns in `match statements
  • functions with side-effects (print, pl.write_csv, ...)

๐Ÿš€ Benchmarks

TODO: Add some benchmarks

๐Ÿ“ฅ Development installation

pixi install
pixi run postinstall
pixi run test

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

polarify-0.2.1.tar.gz (11.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

polarify-0.2.1-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

File details

Details for the file polarify-0.2.1.tar.gz.

File metadata

  • Download URL: polarify-0.2.1.tar.gz
  • Upload date:
  • Size: 11.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for polarify-0.2.1.tar.gz
Algorithm Hash digest
SHA256 36770de45a20ff311c0891045babb7036653bb65705dacbac64f8fc2b9dc584c
MD5 42be3595e50a10c42e00ffad871a5897
BLAKE2b-256 0c2373443eca1f1a3836fcf9cae76f4a984fd074e49e335106956cdb73071af3

See more details on using hashes here.

Provenance

The following attestation bundles were made for polarify-0.2.1.tar.gz:

Publisher: build.yml on Quantco/polarify

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file polarify-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: polarify-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 9.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for polarify-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 7289ee94094092668d49847f200cc59b98fb480abd720c9dc37df8e74ce422cd
MD5 2db59f01834166a36aae70e61a48790c
BLAKE2b-256 be63355c7290618a8bc1777a6ff25bd19c2607423fb8a7f98ffd61d549625bce

See more details on using hashes here.

Provenance

The following attestation bundles were made for polarify-0.2.1-py3-none-any.whl:

Publisher: build.yml on Quantco/polarify

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page