Ingestors
zenpyre.ingestors ¶
Contain all ingestors.
zenpyre.ingestors.BaseIngestor ¶
Bases: ABC, Generic[T]
Abstract base class for data ingestors.
A generic base for any component that ingests data — reads it from
a source, transforms it, writes it to a store, or any combination
thereof. Works with any payload type T, including
:class:~langchain_core.documents.Document objects, plain strings,
dataclasses, or None (for ingestors that write to a store and
return nothing).
The contract intentionally leaves the source, transport, and schema
to the concrete implementation. Subclasses must implement
:meth:ingest.
Example
>>> from zenpyre.ingestors import BaseIngestor
>>> from langchain_core.documents import Document
>>> class MyDocumentIngestor(BaseIngestor[list[Document]]):
... def ingest(self) -> list[Document]:
... return [Document(page_content="Hello")]
...
>>> ingestor = MyDocumentIngestor()
>>> docs = ingestor.ingest()
zenpyre.ingestors.BaseIngestor.ingest
abstractmethod
¶
ingest() -> T
Ingest data from the configured source.
Depending on the implementation, this may read from a file, database, API, or any other source, optionally transform the data, and return it or write it to a destination store.
Returns:
| Type | Description |
|---|---|
T
|
The ingested payload. Its type and structure are defined |
T
|
by the concrete implementation. May be |
T
|
ingestors that write to a store as a side effect. |
zenpyre.ingestors.DataclassIngestor ¶
Bases: BaseIngestor[list[T]], InlineDisplayMixin, Generic[T]
An ingestor that loads a list of dataclass instances from a JSON file.
Reads a JSON file previously written by
:func:~zenpyre.utils.dataclass_io.save_dataclasses and
reconstructs each entry as an instance of cls.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
The path to the JSON file to load. |
required |
cls
|
type[T]
|
The dataclass type to reconstruct each entry as. |
required |
Example
>>> from dataclasses import dataclass
>>> from zenpyre.ingestors import DataclassIngestor
>>> @dataclass(frozen=True)
... class Point:
... x: int
... y: int
...
>>> ingestor = DataclassIngestor(path="points.json", cls=Point)
>>> points = ingestor.ingest() # doctest: +SKIP
zenpyre.ingestors.FirstNIngestor ¶
Bases: BaseIngestor[list[T]], MultilineDisplayMixin
Ingestor that returns the first n items from another
ingestor.
Wraps a source :class:~zenpyre.ingestors.BaseIngestor that
returns a sequence, and slices the first n elements from its
output. If the source ingestor returns fewer than n items, all
items are returned.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
BaseIngestor[Sequence[T]]
|
The source ingestor whose output will be sliced. Must return a sequence. |
required |
n
|
int
|
The maximum number of items to return from the start of the sequence. Must be a positive integer. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Example
>>> from zenpyre.ingestors import InMemoryIngestor, FirstNIngestor
>>> ingestor = FirstNIngestor(
... source=InMemoryIngestor(data=[1, 2, 3, 4, 5]),
... n=3,
... )
>>> ingestor.ingest()
[1, 2, 3]
zenpyre.ingestors.FirstNIngestor.ingest ¶
ingest() -> list[T]
Return the first n items from the source ingestor.
Returns:
| Type | Description |
|---|---|
list[T]
|
A list containing the first |
list[T]
|
ingestor's output. If fewer than |
list[T]
|
all of them are returned. |
zenpyre.ingestors.InMemoryIngestor ¶
Bases: BaseIngestor[T], InlineDisplayMixin
Ingestor that returns a pre-loaded in-memory value.
Wraps an arbitrary value and exposes it through the
:meth:ingest interface, allowing any data already in memory to be
used wherever a :class:~zenpyre.ingestors.BaseIngestor is expected.
Useful for testing, rapid prototyping, or bypassing the download and
caching steps of a pipeline.
By default each call to :meth:ingest returns a deep copy of the
stored value, preventing callers from accidentally mutating the
ingestor's internal state. Pass copy=False to return the original
object directly, which is useful in tests where mock identity must be
preserved.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
T
|
The value to return when :meth: |
required |
copy
|
bool
|
If |
True
|
Example
>>> from zenpyre.ingestors import InMemoryIngestor
>>> ingestor = InMemoryIngestor(data="hello\nworld")
>>> ingestor.ingest()
hello\nworld
zenpyre.ingestors.LastNIngestor ¶
Bases: BaseIngestor[list[T]], MultilineDisplayMixin
Ingestor that returns the last n items from another ingestor.
Wraps a source :class:~zenpyre.ingestors.BaseIngestor that
returns a sequence, and slices the last n elements from its
output. If the source ingestor returns fewer than n items, all
items are returned.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ingestor
|
The source ingestor whose output will be sliced. Must return a sequence. |
required | |
n
|
int
|
The maximum number of items to return from the end of the sequence. Must be a positive integer. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Example
>>> from zenpyre.ingestors import InMemoryIngestor
>>> ingestor = LastNIngestor(
... source=InMemoryIngestor(data=[1, 2, 3, 4, 5]),
... n=3,
... )
>>> ingestor.ingest()
[3, 4, 5]
zenpyre.ingestors.LastNIngestor.ingest ¶
ingest() -> list[T]
Return the last n items from the source ingestor.
Returns:
| Type | Description |
|---|---|
list[T]
|
A list containing the last |
list[T]
|
ingestor's output. If fewer than |
list[T]
|
all of them are returned. |
zenpyre.ingestors.MappingIngestor ¶
Bases: BaseIngestor[dict[Hashable, BaseIngestor[T]]], MultilineDisplayMixin
Ingestor that calls a mapping of ingestors and returns their results as a dict.
Each inner ingestor is called in order and its return value is stored under the corresponding key. The types of the individual results are unconstrained — each ingestor may return a different type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sources
|
Mapping[Hashable, BaseIngestor[T]]
|
A mapping from arbitrary keys to
:class: |
required |
Example
>>> from zenpyre.ingestors import InMemoryIngestor, MappingIngestor
>>> ingestor = MappingIngestor(
... sources={
... "10-K": InMemoryIngestor(data="annual report text"),
... "10-Q": InMemoryIngestor(data="quarterly report text"),
... }
... )
>>> ingestor.ingest()
{'10-K': 'annual report text', '10-Q': 'quarterly report text'}
zenpyre.ingestors.PickleIngestor ¶
Bases: BaseIngestor[T], InlineDisplayMixin
Ingestor that loads data from a pickle file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
Path to the pickle file to load. |
required |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If |
Example
>>> ingestor = PickleIngestor(path="data.pkl")
>>> data = ingestor.ingest() # doctest: +SKIP
zenpyre.ingestors.PickleIngestor.ingest ¶
ingest() -> T
Load and return data from the pickle file.
Returns:
| Type | Description |
|---|---|
T
|
The Python object stored in the pickle file. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the pickle file does not exist at the configured path. |
zenpyre.ingestors.ProcessorIngestor ¶
Bases: BaseIngestor[T], MultilineDisplayMixin
Ingestor that applies a processor to the output of another ingestor.
Wraps a source :class:`~zenpyre.ingestors.base.BaseIngestor` and a
:class:`~zenpyre.data_processors.base.BaseProcessor`: it ingests
data from the source, then passes it through the processor and
returns the processed result. This makes it possible to compose
any processor (e.g. :class:`~zenpyre.data_processors.ShuffleProcessor`)
with any ingestor without needing a dedicated ingestor subclass for
each processor.
Type parameters:
U: The type of data returned by the source ingestor, and
accepted as input by the processor.
T: The type of data returned by the processor, and returned by
:meth:`ingest`.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
BaseIngestor[U]
|
The ingestor used to fetch the raw data. |
required |
processor
|
BaseProcessor[U, T]
|
The processor used to transform the data ingested
from |
required |
Example:
>>> from zenpyre.data_processors import ShuffleProcessor
>>> from zenpyre.ingestors import InMemoryIngestor, ProcessorIngestor
>>> ingestor = ProcessorIngestor(
... source=InMemoryIngestor(data=[1, 2, 3, 4, 5]),
... processor=ShuffleProcessor(seed=42),
... )
>>> sorted(ingestor.ingest())
[1, 2, 3, 4, 5]
zenpyre.ingestors.ProcessorIngestor.ingest ¶
ingest() -> T
Ingest data from the source ingestor and process it.
Calls :meth:~zenpyre.ingestors.base.BaseIngestor.ingest on
the source ingestor, then passes the result to
:meth:~zenpyre.data_processors.base.BaseProcessor.process.
Returns:
| Type | Description |
|---|---|
T
|
The processed output, as returned by the processor. |
zenpyre.ingestors.ShuffleIngestor ¶
Bases: BaseIngestor[list[T]], MultilineDisplayMixin
Ingestor that shuffles the output of another ingestor.
Wraps a source :class:~zenpyre.ingestors.base.BaseIngestor and
returns its ingested payload as a list with elements shuffled
in random order. The source ingestor's output must be an iterable
(e.g. list, tuple) whose elements can be reordered; the
result is always materialized as a new list, so the original
sequence type of T is not preserved.
The shuffling uses its own :class:random.Random instance, so it
does not affect and is not affected by the global random
module state. Note that the internal random generator is created
once, in __init__, and its state advances with each call to
:meth:ingest. This means calling ingest multiple times on
the same instance — even with a fixed seed — will generally
produce a different shuffle order each time, since each call
consumes further random state rather than resetting it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
BaseIngestor[Sequence[T]]
|
The ingestor whose output will be shuffled. |
required |
seed
|
int | None
|
Seed for the internal random number generator, to make
the shuffle order reproducible across runs. If |
None
|
Example
>>> from zenpyre.ingestors import ShuffleIngestor, InMemoryIngestor
>>> ingestor = ShuffleIngestor(InMemoryIngestor([1, 2, 3, 4, 5]), seed=42)
>>> shuffled = ingestor.ingest()
>>> sorted(shuffled)
[1, 2, 3, 4, 5]
zenpyre.ingestors.ShuffleIngestor.ingest ¶
ingest() -> list[T]
Ingest data from the source ingestor and shuffle it.
Calls :meth:~zenpyre.ingestors.base.BaseIngestor.ingest on
the wrapped source ingestor, converts the result to a
list, and shuffles it in place using the internal random
generator.
Returns:
| Type | Description |
|---|---|
list[T]
|
A new |
list[T]
|
source ingestor's output, in a random order. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the source ingestor's output is not iterable. |
zenpyre.ingestors.TextIngestor ¶
Bases: BaseIngestor[str], InlineDisplayMixin
Ingestor that loads data from a text file.
Reads the full content of a text file and returns it as a single string. Intended for loading Markdown filings or other plain-text documents for downstream processing by an agent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
Path to the text file to load. |
required |
encoding
|
str
|
The file encoding to use when reading the file.
Defaults to |
'utf-8'
|
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If |
Example
>>> from zenpyre.ingestors import TextIngestor
>>> ingestor = TextIngestor(path="filing.md")
>>> text = ingestor.ingest() # doctest: +SKIP
zenpyre.ingestors.TextIngestor.ingest ¶
ingest() -> str
Load and return the content of the text file.
Returns:
| Type | Description |
|---|---|
str
|
The full file content as a string. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the text file does not exist at the configured path. |
zenpyre.ingestors.resolve_ingestor ¶
resolve_ingestor(
ingestor: (
BaseIngestor[T] | dict[str, Any] | BaseConfig
),
) -> BaseIngestor[T]
Resolve a :class:~zenpyre.ingestors.base.BaseIngestor instance
from an existing object, a configuration dictionary, or a
:class:~zenpyre.utils.config.BaseConfig.
If ingestor is already a
:class:~zenpyre.ingestors.base.BaseIngestor instance it is
returned as-is. If it is a :class:dict or a
:class:~zenpyre.utils.config.BaseConfig, it is treated as an
objectory factory configuration and instantiated via
:func:objectory.factory. See
:func:~zenpyre.utils.resolve.resolve_object for details.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ingestor
|
BaseIngestor[T] | dict[str, Any] | BaseConfig
|
Either a fully configured
:class: |
required |
Returns:
| Type | Description |
|---|---|
BaseIngestor[T]
|
A configured :class: |
BaseIngestor[T]
|
instance. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the resolved object is not a
:class: |
Example
>>> from zenpyre.ingestors import resolve_ingestor
>>> from zenpyre.ingestors.base import BaseIngestor
>>> class MyIngestor(BaseIngestor):
... def ingest(self) -> Any:
... return {"hello": "world"}
...
>>> # From an existing instance:
>>> ingestor = resolve_ingestor(MyIngestor())
>>> # From a configuration dictionary:
>>> ingestor = resolve_ingestor( # doctest: +SKIP
... {"_target_": "my_package.ingestors.MyIngestor"}
... )
zenpyre.ingestors.factory ¶
Contain factories for document ingestors.
zenpyre.ingestors.factory.BaseIngestorFactory ¶
Bases: ABC, Generic[T]
Abstract base class for
:class:~zenpyre.ingestors.base.BaseIngestor factories.
Subclasses implement :meth:make_ingestor to instantiate and
return a configured
:class:~zenpyre.ingestors.base.BaseIngestor object. This
pattern decouples ingestor creation from the rest of the
codebase, making it easy to swap ingestors (e.g. file, web,
database) without changing call sites.
Example
>>> from zenpyre.ingestors import InMemoryIngestor
>>> from zenpyre.ingestors.base import BaseIngestor
>>> from zenpyre.ingestors.factory import BaseIngestorFactory
>>> class MyIngestorFactory(BaseIngestorFactory[list[int]]):
... def make_ingestor(self) -> BaseIngestor[list[int]]:
... return InMemoryIngestor([1, 2, 3])
...
>>> factory = MyIngestorFactory()
>>> ingestor = factory.make_ingestor()
zenpyre.ingestors.factory.BaseIngestorFactory.make_ingestor
abstractmethod
¶
make_ingestor() -> BaseIngestor[T]
Create and return a configured BaseIngestor instance.
Returns:
| Name | Type | Description |
|---|---|---|
A |
BaseIngestor[T]
|
class: |
BaseIngestor[T]
|
instance ready for use. |
zenpyre.ingestors.factory.ConfigurableIngestorFactory ¶
Bases: BaseIngestorFactory[T], MultilineDisplayMixin
A concrete BaseIngestor factory that accepts either a pre-built
:class:~zenpyre.ingestors.base.BaseIngestor instance or a
configuration dictionary.
When a dict is provided it is resolved at each :meth:make_ingestor
call via :func:~zenpyre.ingestors.resolve.resolve_ingestor, which
uses objectory to instantiate the configured class. When an
instance is provided it is returned as-is.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ingestor
|
BaseIngestor[T] | dict[str, Any]
|
A fully configured
:class: |
required |
Example
>>> from zenpyre.ingestors import InMemoryIngestor
>>> from zenpyre.ingestors.factory import ConfigurableIngestorFactory
>>> factory = ConfigurableIngestorFactory(InMemoryIngestor([1, 2, 3]))
>>> ingestor = factory.make_ingestor()
zenpyre.ingestors.factory.IngestorFactory ¶
Bases: BaseIngestorFactory[T], MultilineDisplayMixin
A concrete BaseIngestor factory that wraps a pre-built
:class:~zenpyre.ingestors.base.BaseIngestor instance.
Use this when the ingestor is already instantiated and you
simply want to wrap it in the :class:~BaseIngestorFactory
interface — for example, when injecting a fixed ingestor into a
component that expects a factory.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ingestor
|
BaseIngestor[T]
|
A fully configured
:class: |
required |
Example
>>> from zenpyre.ingestors import InMemoryIngestor
>>> from zenpyre.ingestors.factory import IngestorFactory
>>> factory = IngestorFactory(InMemoryIngestor([1, 2, 3]))
>>> ingestor = factory.make_ingestor()