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)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| spellops-0.0.1.tar.gz | 6.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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.