# Pipes And Generator [We already saw](../get_started/entities.md) how to generate a sample sequence and chain pipes to it. We will now detailed how you can extend the built-in types with your own generators and pipes. ## Custom Generators If you want to provide access to your own data or create a synthetic dataset, you should consider to use `SamplesSequence.from_callable()`, so that all you have to do is to provide a function `(idx: int) -> Sample`. However, writing a new generator class is not too difficult. First, derive from `SamplesSequence`, then: 1. apply the decorator `@source_sequence` to your class 2. set a `title`: this will be the name of the associated method (see the example below) 3. provide a class help: it will be used for automatic help generation (see [CLI](../cli/overview.md)) 4. define your parameters as [`pydantic.Field`](https://pydantic-docs.helpmanual.io/): field's description will be used for automatic help generation 5. implement `def get_sample(self, idx: int) -> Sample` and `def size(self) -> int` ```python from typing import List from pathlib import Path from pydantic import Field, DirectoryPath, PrivateAttr from pipelime.sequences import SamplesSequence, Sample, source_sequence from pipelime.items.base import ItemFactory @source_sequence class SequenceFromImageList(SamplesSequence, title="from_image_list"): """A SamplesSequence loading images in folder as Samples.""" folder: DirectoryPath = Field(..., description="The folder to read.") ext: str = Field(".png", description="The image file extension.") _samples: List[Path] = PrivateAttr() def __init__(self, **data): super().__init__(**data) self._samples = [ Sample({"image": ItemFactory.get_instance(p)}) for p in self.folder.glob("*" + self.ext) ] def size(self) -> int: return len(self._samples) def get_sample(self, idx: int) -> Sample: return self._samples[idx] ``` In the above example notice that: - we use `PrivateAttr` to define an internal variable (see [pydantic](https://pydantic-docs.helpmanual.io/usage/models/#private-model-attributes) for details) - we delegate to `ItemFactory.get_instance` the actual creation of the item: this way we support any possible extension as well as the [`.remote` files](../advanced/remotes.md) Once the module is imported, the generator is automatically registered into `SamplesSequence` as `from_image_list`: ```python from pipelime.sequences import SamplesSequence dataset = SamplesSequence.from_image_list(folder="path/to/folder") ``` Do you want a preview of the auto-generated help? ```python from pipelime.cli import pl_print pl_print("from_image_list") ``` ```bash >>> from_image_list (*, folder: pydantic.types.DirectoryPath, ext: str = '.png') A SamplesSequence loading images in folder as Samples. Fields Description Type Default ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ folder ▶ The folder to read. DirectoryPath ✗ ext ▶ The image file extension. str .png ``` ## Custom Pipes To create your own piped operation just derive from `PipedSequenceBase`, then: 1. apply the decorator `@piped_sequence` to your class 2. set a `title`: this will be the name of the associated method (see the example below) 3. provide a class help: it will be used for automatic help generation (see [CLI](../cli/overview.md)) 4. define your parameters as [`pydantic.Field`](https://pydantic-docs.helpmanual.io/) (Field's description will be used for automatic help generation) 5. implement `def get_sample(self, idx: int) -> Sample` and, possibly, `def size(self) -> int` ```python from pydantic import Field from pipelime.sequences import Sample, piped_sequence from pipelime.sequences.pipes import PipedSequenceBase @piped_sequence class ReverseSequence(PipedSequenceBase, title="reversed"): """Reverses the order of the first `num` samples.""" num: int = Field(..., description="The number of samples to reverse.") def get_sample(self, idx: int) -> Sample: if idx < self.num: return self.source[self.num - idx - 1] return self.source[idx] ``` In the above example notice that: - we do not implement `size` since it does not change - we refer to the source sequence as `self.source`; alternatively, we could have accessed the source by calling `super().get_sample()` As with the generator before, once the module is imported, the pipe registers itself on `SamplesSequence` with the given title, i.e., `reversed`, so that you can simply do, e.g., `dataset.reversed(num=20)`. Do you want a preview of the auto-generated help? ```python from pipelime.cli import pl_print pl_print("reversed") ``` ```bash >>> reversed (*, num: int) Reverses the order of the first num samples. Fields Description Type Default ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ num ▶ The number of samples to reverse. int ✗ ```