lens

lens

Lens-based type transformations for datasets.

This module implements a lens system for bidirectional transformations between different sample types. Lenses enable viewing a dataset through different type schemas without duplicating the underlying data.

Key components:

  • Lens: Bidirectional transformation with getter (S -> V) and optional putter (V, S -> S)
  • LensNetwork: Global singleton registry for lens transformations
  • @lens: Decorator to create and register lens transformations

Lenses support the functional programming concept of composable, well-behaved transformations that satisfy lens laws (GetPut and PutGet).

Examples

>>> @packable
... class FullData:
...     name: str
...     age: int
...     embedding: NDArray
...
>>> @packable
... class NameOnly:
...     name: str
...
>>> @lens
... def name_view(full: FullData) -> NameOnly:
...     return NameOnly(name=full.name)
...
>>> @name_view.putter
... def name_view_put(view: NameOnly, source: FullData) -> FullData:
...     return FullData(name=view.name, age=source.age,
...                     embedding=source.embedding)
...
>>> ds = Dataset[FullData]("data.tar")
>>> ds_names = ds.as_type(NameOnly)  # Uses registered lens

Classes

Name Description
Lens A bidirectional transformation between two sample types.
LensNetwork Global registry for lens transformations between sample types.

Lens

lens.Lens(get, put=None)

A bidirectional transformation between two sample types.

A lens provides a way to view and update data of type S (source) as if it were type V (view). It consists of a getter that transforms S -> V and an optional putter that transforms (V, S) -> S, enabling updates to the view to be reflected back in the source.

Parameters

Name Type Description Default
S The source type, must derive from PackableSample. required
V The view type, must derive from PackableSample. required

Examples

>>> @lens
... def name_lens(full: FullData) -> NameOnly:
...     return NameOnly(name=full.name)
...
>>> @name_lens.putter
... def name_lens_put(view: NameOnly, source: FullData) -> FullData:
...     return FullData(name=view.name, age=source.age)

Methods

Name Description
get Transform the source into the view type.
put Update the source based on a modified view.
putter Decorator to register a putter function for this lens.
get
lens.Lens.get(s)

Transform the source into the view type.

Parameters
Name Type Description Default
s S The source sample of type S. required
Returns
Name Type Description
V A view of the source as type V.
put
lens.Lens.put(v, s)

Update the source based on a modified view.

Parameters
Name Type Description Default
v V The modified view of type V. required
s S The original source of type S. required
Returns
Name Type Description
S An updated source of type S that reflects changes from the view.
putter
lens.Lens.putter(put)

Decorator to register a putter function for this lens.

Parameters
Name Type Description Default
put LensPutter[S, V] A function that takes a view of type V and source of type S, and returns an updated source of type S. required
Returns
Name Type Description
LensPutter[S, V] The putter function, allowing this to be used as a decorator.
Examples
>>> @my_lens.putter
... def my_lens_put(view: ViewType, source: SourceType) -> SourceType:
...     return SourceType(field=view.field, other=source.other)

LensNetwork

lens.LensNetwork()

Global registry for lens transformations between sample types.

This class implements a singleton pattern to maintain a global registry of all lenses decorated with @lens. It enables looking up transformations between different PackableSample types.

Attributes

Name Type Description
_instance The singleton instance of this class.
_registry Dict[LensSignature, Lens] Dictionary mapping (source_type, view_type) tuples to their corresponding Lens objects.

Methods

Name Description
register Register a lens as the canonical transformation between two types.
transform Look up the lens transformation between two sample types.
register
lens.LensNetwork.register(_lens)

Register a lens as the canonical transformation between two types.

Parameters
Name Type Description Default
_lens Lens The lens to register. Will be stored in the registry under the key (_lens.source_type, _lens.view_type). required
Note

If a lens already exists for the same type pair, it will be overwritten.

transform
lens.LensNetwork.transform(source, view)

Look up the lens transformation between two sample types.

Parameters
Name Type Description Default
source DatasetType The source sample type (must derive from PackableSample). required
view DatasetType The target view type (must derive from PackableSample). required
Returns
Name Type Description
Lens The registered Lens that transforms from source to view.
Raises
Name Type Description
ValueError If no lens has been registered for the given type pair.
Note

Currently only supports direct transformations. Compositional transformations (chaining multiple lenses) are not yet implemented.

Functions

Name Description
lens Decorator to create and register a lens transformation.

lens

lens.lens(f)

Decorator to create and register a lens transformation.

This decorator converts a getter function into a Lens object and automatically registers it in the global LensNetwork registry.

Parameters

Name Type Description Default
f LensGetter[S, V] A getter function that transforms from source type S to view type V. Must have exactly one parameter with a type annotation. required

Returns

Name Type Description
Lens[S, V] A Lens[S, V] object that can be called to apply the transformation
Lens[S, V] or decorated with @lens_name.putter to add a putter function.

Examples

>>> @lens
... def extract_name(full: FullData) -> NameOnly:
...     return NameOnly(name=full.name)
...
>>> @extract_name.putter
... def extract_name_put(view: NameOnly, source: FullData) -> FullData:
...     return FullData(name=view.name, age=source.age)