Skip to main content

spellops

Developer Guide

Instead of writing this:

L(f_c(L(...).map(f_a).filter(f_b))).map(f_d)[0]

With spellops’s pipe operator, you can visually maintain the order of execution (f_a → filter(f_b) → f_c → f_d) by writing this:

L(...).map(f_a).filter(f_b).pipe(f_c).map(f_d)[0]

And with tee operator, you can inspect and document your pipeline like this:

(L(...)             .tee('input data')
    .map(f_a)       .tee('apply f_a to individual elements')
    .filter(f_b)    .tee('filter by f_b')
    .pipe(f_c)      .tee('apply f_c to the whole list')
    .map(f_d)[0]    .tee('finally apply f_d to the resulting elements and returning first value')
)

And once you’re done, you can keep all of this in your production code:

def process(data,verbose=False):
    s = dict(show=verbose)
    return (L(data)     .tee('input data', **s)
        .map(f_a)       .tee('apply f_a to individual elements', **s)
        .filter(f_b)    .tee('filter by f_b', **s)
        .pipe(f_c)      .tee('apply f_c to the whole list', **s)
        .map(f_d)       .tee('finally apply f_d to the resulting elements and returning first value', **s)
        .unwrap()       # Extract the element out of the list
    )

Here are some examples:

Import L and spellops

NOTE: order of import does not matters.

import spellops
from fastcore.foundation import L

Fluent string manipulaiton

L(['a', 'b', 'c']).map(str.upper).pipe('->'.join, wrap=False)
'A->B->C'

Or using convenience mehtod pipen that stands for pipe with wrap=False (no wrap):

L(['a', 'b', 'c']).map(str.upper).pipen('->'.join)
'A->B->C'

Count how many elements are present in both sublists

(L([[1,2,3,2],[2,4,1]])    .tee('input')
     .map(set)             .tee('to set')
     .starpipe(set.intersection)  .tee('common elements')
     .pipe(len)            .tee('count elements')
     .unwrap()
)
input
[[1, 2, 3, 2], [2, 4, 1]]
to set
[{1, 2, 3}, {1, 2, 4}]
common elements
[1, 2]
count elements
[2]

2

An alternative approach can be to pipe with wrap=False:

NOTE: In this case, you can’t use tee after the final pipe operator because it no longer returns an L instance.

(L([[1,2,3,2],[2,4,1]])    .tee('input')
     .map(set)             .tee('to set')
     .starpipe(set.intersection)  .tee('common elements')
     .pipe(len, wrap=False) # count elements
)
input
[[1, 2, 3, 2], [2, 4, 1]]
to set
[{1, 2, 3}, {1, 2, 4}]
common elements
[1, 2]

2

Solve an AoC task

SPOILER ALERT: the following is a speLL to solve AoC 2024 part B.

GOAL: For each number in the left list, we need to count how many times it appears in the right list, multiply these together, and sum all results. This creates a “similarity score”, counting occurrences and multiplying, that measures how frequently numbers from the left list appear in the right list.

sample = '''3   4
4   3
2   5
1   3
3   9
3   3
'''

# This function will be "mapped" to individual elements
def to_int_tuple(a,b): return (int(a),int(b))

# this function acts on the whole list
def count_instances(As,Bs): return [(o,len([t for t in Bs if t==o])) for  o in As]

from math import prod
(L(sample.splitlines())
                .map(str.split)         .tee('input data')
                .starmap(to_int_tuple)  .tee('int to tuples')
                .zip(cycled=True)       .tee('tuple of lists')
                .starpipe(count_instances)  .tee('apply count_instances to the "whole list"')
                .map(prod)              .tee('multiply tuple elements')
                .sum()
    )
input data
[['3', '4'], ['4', '3'], ['2', '5'], ['1', '3'], ['3', '9'], ['3', '3']]
int to tuples
[(3, 4), (4, 3), (2, 5), (1, 3), (3, 9), (3, 3)]
tuple of lists
[(3, 4, 2, 1, 3, 3), (4, 3, 5, 3, 9, 3)]
apply count_instances to the "whole list"
[(3, 3), (4, 1), (2, 0), (1, 0), (3, 3), (3, 3)]
multiply tuple elements
[9, 4, 0, 0, 9, 9]

31

Visually inspect images transformations:

import matplotlib.pyplot as plt
import numpy as np

def plot_images(x:L, msg):
    N = len(x)
    plt.figure(figsize=(4*N,4))
    for i,o in enumerate(x):
        plt.subplot(1,N,i+1)
        plt.imshow(o)
        plt.title(f'Image: {i}')
    plt.suptitle(msg)

(L([[[0,0,0],[1,1,1],[0,0,0]],[[1,0,0],[0,1,0],[0,0,1]]])  .tee('Input images',f=plot_images)
    .map(lambda x: np.rot90(x,k=1)) .tee('Rotate 90 degree',f=plot_images)
)
(#2) [array([[0, 1, 0],
       [0, 1, 0],
       [0, 1, 0]]),array([[0, 0, 1],
       [0, 1, 0],
       [1, 0, 0]])]

Install spellops in Development mode

# make sure spellops package is installed in development mode
$ pip install -e .

# make changes under nbs/ directory
# ...

# compile to have changes apply to spellops
$ nbdev_prepare

Usage

Installation

Install latest from the GitHub repository:

$ pip install git+https://github.com/artste/spellops.git

or from pypi

$ pip install spellops

Metadata

Release files for spellops 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for spellops 0.0.1
File Size Uploaded Provenance
spellops-0.0.1.tar.gz 6.8 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for spellops 0.0.1
File Interpreter ABI Platform
spellops-0.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 12.3 kB

Release files / spellops-0.0.1.tar.gz

Download URL spellops-0.0.1.tar.gz
Size 6.8 kB
Tags Source
SHA-256 checksum
How to use checksums
d0064533e52751cb721c8a627614e3a0062b53137fda460795af800c2888c7f7
BLAKE2b-256 checksum
How to use checksums
172d37796f763d1c472d1b31e0b0c93a8ba4fd68c9dec7949e214ec2892b5f5e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.0.1 CPython/3.11.11

Release files / spellops-0.0.1-py3-none-any.whl

Download URL spellops-0.0.1-py3-none-any.whl
Size 5.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
174692d2c5ad9f27ac3ee812590e1d6794b216a10d9bab6007764e7bd8edf8a8
BLAKE2b-256 checksum
How to use checksums
ff49d530041d85bb4e408ed532c88a111715c8527eef53810a91883f0d204514
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.0.1 CPython/3.11.11

Security for spellops 0.0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page