Skip to main content

ETLRelay

ETLRelay is an open-source Python framework for building lightweight, composable ETL pipelines.

It uses a simple pipeline model:

Source → Processor(s) → Sink

A source produces batches of data, processors transform those batches, and a sink consumes the results.

For file-based pipelines, ETLRelay separates storage access from format parsing and serialization:

FileSystem → TabularReader → Batch → Processor(s) → TabularWriter → FileSystem

This separation allows file sources and sinks to compose storage and format implementations independently. CSV and Parquet readers/writers use the same file source/sink abstractions without format-specific branches in those components.

ETLRelay is being developed incrementally, with test-driven development, explicit component contracts, and a focus on keeping the architecture small.

v1.0.1 — Community Standards and Contribution Guidance

ETLRelay v1.0.1 is a documentation-only patch release that builds on the stable foundation established in v1.0.0.

This release introduces community contribution guidelines, a Code of Conduct, an accessibility statement, and standardized GitHub issue and pull request templates.

These additions establish clearer expectations for contributors, improve issue reporting, and provide a foundation for community participation as ETLRelay continues to develop.

No runtime functionality, public Python APIs, CLI behavior, YAML configuration schema, or dependencies have changed from v1.0.0.

See Getting Started, the compatibility policy, and the v1.0.1 release notes.

Installation

Install ETLRelay from PyPI:

pip install etlrelay==1.0.1

Supported Python Versions and Platforms

ETLRelay supports CPython 3.12, 3.13, and 3.14.

The following configurations are verified in CI:

Platform Python Verification
Ubuntu 3.12 Full test suite, quality checks, and installed wheel/sdist smoke tests
Ubuntu 3.13 Installed wheel/sdist smoke tests
Ubuntu 3.14 Installed wheel/sdist smoke tests
macOS 3.12 Installed wheel/sdist smoke tests
Windows 3.12 Installed wheel/sdist smoke tests

Compatibility testing installs the built wheel and source distribution into separate clean virtual environments outside the source checkout. It verifies public imports, dependency consistency, direct CSV/Parquet/SQLite composition, CLI operation, YAML validation, and a minimal CSV CLI pipeline.

Other operating-system and Python-version combinations may work but are not independently verified by CI.

Python 3.15 is not currently supported because ETLRelay's pinned PyArrow major version does not provide Python 3.15 support.

CLI Quick Start

Install ETLRelay v1.0.0 and inspect the available commands:

python -m pip install etlrelay==1.0.0

etlrelay --help
etlrelay version

Validate and run a YAML pipeline from its working directory:

etlrelay validate pipeline.yaml
etlrelay run pipeline.yaml

The CLI supports configuration validation, pipeline execution, version reporting, and command help.

validate parses the configuration and validates schema and component settings. It does not build runtime components, resolve SQL connection environment variables, or execute the pipeline. It does not guarantee that runtime filesystem operations, database operations, or data transformations will succeed.

See the CLI Reference for command syntax, exit codes, and error-output conventions.

See Getting Started for a complete local CSV example.

Logging

ETLRelay supports configurable operational logging through Python's standard logging module.

The CLI defaults to WARNING. Use --log-level to enable additional information:

etlrelay --log-level info run pipeline.yaml
etlrelay --log-level debug run pipeline.yaml

Logs are written to stderr, separately from normal command output.

When using ETLRelay as a Python library, logging is controlled by the calling application. ETLRelay does not configure the application's root logger.

Operational logs report pipeline progress, component activity, and resource lifecycle events without routinely exposing record contents, SQL parameters, or database credentials.

See the Logging documentation for supported levels, examples, Python integration, and security limitations.

Documentation

Read the v1.0.1 documentation for installation instructions, configuration, public API contracts, architecture, security considerations, and examples.

For the changes introduced in each release, see the Changelog.

Project Status

Current release: 1.0.1 — Community standards and documentation patch

ETLRelay v1.0.1 retains the stable functionality and public contracts established in v1.0.0.

The supported feature set covers synchronous local CSV/Parquet and SQLite pipelines, the three existing processors, YAML schema version 1, and CLI execution. Public Python interfaces and documented behavior follow the compatibility policy.

The stable release retains the reviewed schema, exception, resource ownership, and persistence contracts. Local file writes can be partial; SQL sinks append to existing tables using one transaction per nonempty batch. Evaluate the security boundaries and operational limitations for your deployment.

v1.0.1 introduces no changes to these runtime contracts. Instead, it improves contributor documentation, community participation guidelines, issue reporting, and accessibility guidance.

Future features and integrations will be evaluated through a separate post-v1.0 roadmap based on concrete end-user workflows and maintenance cost.

Unit tests validate individual components. Integration and functional tests exercise component composition and complete pipeline workflows.

Implemented Components

Component Responsibility
Batch Represents tabular data using Apache Arrow
Source Defines the contract for producing batches
Processor Defines the contract for transforming a batch
Sink Defines the contract for consuming batches
Pipeline Coordinates source, processor, and sink execution
FileSystem Defines the interface for opening binary streams
LocalFileSystem Provides local filesystem access
PathValidator Enforces local filesystem path containment
TabularReader Defines the contract for reading data from a binary stream
CsvReader Parses CSV data into ETLRelay batches
ParquetReader Parses Parquet data into ETLRelay batches
TabularWriter Defines the contract for serializing batches to a binary stream
CsvWriter Serializes ETLRelay batches as CSV
ParquetWriter Serializes ETLRelay batches as Parquet
FileSource Composes a filesystem and reader to produce batches
FileSink Composes a filesystem and writer to consume batches
SqlSource Reads SQL query results into batches using SQLAlchemy
SqlSink Appends batch rows to an existing SQL table
KeyValueReader Defines the mapping-shaped document reader contract
YamlReader Safely parses one YAML configuration document
ConfigLoader Reads, parses, and validates configuration documents
ConfigValidator Validates schema version 1 and its component sections
ComponentCatalog Shares built-in registries, validators, factories, and SQL service
PipelineBuilder Builds runtime pipelines from validated configuration mappings

v1.0 Scope and Feature Freeze

The intended v1.0 feature set is frozen: synchronous pipelines using local CSV/Parquet files or SQL, the existing built-in processors, YAML configuration, and CLI execution.

The v1.0 feature boundary is complete. Maintenance preserves documented behavior; additional capabilities require a separate roadmap decision.

S3, HDFS, additional formats and processors, dynamic plugin loading, scheduling, retries, and distributed execution are deferred. Future consideration does not promise implementation or a release date.

See the v1.0 Feature Scope and Support Policy for the feature inventory, exact support matrix, operational boundaries, and required readiness work.

Operational Contracts

ETLRelay processes batches synchronously and validates output-schema compatibility during pipeline execution.

An entirely empty source does not invoke its sink. Zero-row batches still participate in processing and schema validation.

Pipeline execution attempts to close active source and processing iterators when they expose callable close() methods. File sources and sinks manage the streams they open; readers and writers borrow caller-provided streams.

Local file writes are not atomic. Opening an existing output file for writing truncates it, and a failed write may leave partial output.

SQL sinks append to existing tables using one transaction per nonempty batch. Previously committed batches are not rolled back by a later pipeline failure.

ETLRelay provides controlled operational logging and CLI diagnostics, but it does not guarantee the sanitization of arbitrary third-party exceptions or application logging.

For details, see:

Architecture

Pipeline Execution

The pipeline provides the central execution model:

Source
  │
  ▼
Iterable[Batch]
  │
  ▼
Processor 1
  │
  ▼
Processor 2
  │
  ▼
    ...
  │
  ▼
Sink

The pipeline applies processors in their configured order to each batch. With no processors, batches pass through unchanged.

Execution is synchronous. Exceptions propagate to the caller rather than being silently discarded or handled by an elaborate recovery framework.

Separation of Storage and Serialization

ETLRelay keeps resource access independent of file-format handling.

The FileSystem protocol defines operations for opening readable and writable binary streams. LocalFileSystem implements that protocol for local files and uses PathValidator to enforce its permitted filesystem boundary.

Readers and writers operate on streams rather than filesystem paths.

For example, CSV reading follows:

LocalFileSystem.open_read(path)
          │
          ▼
      BinaryIO
          │
          ▼
       CsvReader
          │
          ▼
        Batch

CSV writing follows the reverse path:

        Batch
          │
          ▼
       CsvWriter
          │
          ▼
      BinaryIO
          │
          ▼
LocalFileSystem.open_write(path)

FileSource composes a filesystem and a reader. FileSink composes a filesystem and a writer.

This prevents source and sink implementations from becoming coupled to individual storage technologies or serialization formats.

For file-based pipelines, the current implementation supports the local filesystem with CSV and Parquet. SQL input/output is a separate source/sink integration rather than a file-format or storage variant.

SQL Sources and Sinks

SqlSource and SqlSink implement the core source/sink contracts using SQLAlchemy. They are separate from file storage and file-format readers/writers. Query values can be supplied as bound parameters; the sink appends to an existing table using one transaction per non-empty batch. The caller owns the SQLAlchemy engine. SQLite is the reference integration-test backend; see SQL source and sink for identifier handling, empty-data behavior, transaction boundaries, and limitations.

Declarative YAML Configuration

Schema version 1 defines a closed set of supported components: file and SQL sources/sinks, local storage, CSV/Parquet file formats, and the select_columns, rename_columns, and filter_rows processors. The schema requires version, source, processors, and sink; unsupported keys and types are rejected.

The configuration lifecycle is ConfigLoader → ConfigValidator → PipelineBuilder → Pipeline.run(). Loading and validation do not construct runtime components. The builder resolves all configured component registrations and preflights SQL connection environment-variable references before invoking component factories. It returns a pipeline but does not execute it.

For SQL configuration, YAML stores an environment-variable name such as ETLRELAY_SOURCE_DATABASE_URL, not the resolved connection URL. Missing/empty variables fail before component factories or source/sink I/O. The PipelineBuilder owns the lifecycle of engines created by the catalog's shared SqlEngineFactory; callers close the builder after execution. Direct Python SqlSource/SqlSink engine ownership remains unchanged.

See the YAML Configuration reference for the versioned schema, examples, supported combinations, and validation errors.

Common Data Representation

ETLRelay uses Apache Arrow tables as the underlying tabular representation within Batch.

Readers convert external data into batches. Processors operate on batches, and writers serialize batches for output.

This provides a common data boundary between file formats and pipeline components.

The frozen feature set uses PyArrow for tabular representation and transformations. Polars is not a runtime dependency.

Component Contracts

ETLRelay uses Python protocols to define component boundaries where substitutability is useful.

The core contracts are deliberately small:

Source
    Produces batches

Processor
    Transforms a batch

Sink
    Consumes batches

For file-based operations:

FileSystem
    Opens binary streams

TabularReader
    Converts stream data into batches

TabularWriter
    Serializes batches to a stream

Concrete implementations remain independent of higher-level orchestration. The configuration path uses explicit registries and factories where a YAML component name must resolve to a validator and runtime implementation. It does not use a general dynamic plugin system, import-by-string, or reflection-based construction.

Development Environment

The development environment is managed with Nix flakes.

Enter the development shell:

nix develop

The Nix development shell provides:

  • Python 3.12 as the default development interpreter.
  • Python 3.13 and 3.14 for compatibility verification.
  • uv for Python dependency and environment management.
  • Node.js for Pyright.
  • Ruff, Pyright, Git, and other configured development tools.

The repository's .python-version file selects Python 3.12 by default. The supported package range is CPython 3.12–3.14.

The development shell uses Nix-provided executables while uv manages the project's Python dependencies. CI independently verifies built distribution artifacts using GitHub-hosted runners.

Getting Started

Enter the development shell:

nix develop

Install or synchronize Python dependencies:

uv sync

Run the test suite:

uv run pytest

Run the linter:

ruff check .

Check formatting:

ruff format --check .

Run static type checking:

pyright

Run these checks before committing implementation changes.

Development Principles

Test-Driven Development

Development follows a small, explicit cycle:

Requirement
    ↓
Acceptance Criteria
    ↓
Failing Test
    ↓
Minimal Implementation
    ↓
Passing Test
    ↓
Refactor
    ↓
Validation

Tests establish expected behavior before implementation. Unit tests validate components independently, while integration and functional tests verify that components work together.

Keep Architecture Small

Prefer simple, explicit abstractions over framework machinery.

An abstraction should exist because a concrete requirement justifies it, not because a hypothetical future requirement might eventually need it.

Prefer composition and small protocols over unnecessary inheritance. Add configuration, extension mechanisms, and additional layers only when they solve an identified problem.

Separate Responsibilities

Each component should have one clearly defined responsibility:

  • PathValidator checks local path containment.
  • LocalFileSystem handles local filesystem access.
  • Readers parse external representations.
  • Writers serialize batches.
  • Sources and sinks compose the relevant components.
  • Processors transform batches.
  • Pipeline coordinates execution.

Security checks should be implemented at the layer where the relevant risk exists.

Independent Implementation

ETLRelay is independently developed open-source software.

Its implementation, interfaces, documentation, tests, and design decisions are developed from its own requirements and design process.

Security

Security is a design concern from the beginning.

Current filesystem path validation resolves candidate paths and checks that they remain within the permitted base directory. It does not determine whether a path exists; filesystem operations handle existence and access errors.

Configuration uses a safe YAML loader, a strict versioned schema, and explicit component registrations. SQL connection URLs are referenced through environment-variable names rather than placed in YAML. The builder preflights required variables before constructing ETL components, and its SQL engine factory avoids exposing resolved connection URLs in its own errors. Environment variables are not a secrets vault; deployments remain responsible for controlling access to secrets and runtime diagnostics.

Further security work will be required as ETLRelay gains more capabilities. Areas for future development include:

  • Additional storage-specific authentication and access-control capabilities for future integrations

The current path-validation component is a filesystem containment control, not a complete filesystem sandbox or authorization system.

Testing

Testing follows the TDD development model.

Unit Tests

Unit tests validate components independently, including:

  • Batch representation
  • Pipeline execution and processor ordering
  • Path containment
  • Filesystem interactions
  • CSV and Parquet parsing and serialization
  • SQL source/sink validation, bound query values, table reflection, transactions, and resource cleanup
  • File source and sink orchestration
  • Error propagation and resource cleanup

Integration Tests

Integration tests verify real local filesystem and CSV/Parquet operations plus SQLAlchemy/SQLite reads, writes, and round trips. Functional tests also cover mixed file/SQL pipelines.

Functional Tests

Functional tests exercise complete workflows through the source, processing, and sink boundaries.

The suite should use temporary directories and controlled test inputs rather than relying on repository-local data or external infrastructure unnecessarily.

If additional storage backends or data sources are considered after v1.0.0, their integration tests should be introduced alongside the corresponding implementation. No such backend is included in the current release scope.

Project Structure

The current package is organized around component responsibilities. The structure will evolve as additional features are implemented.

src/
└── etlrelay/
    ├── core/
    │   ├── batch.py
    │   ├── source.py
    │   ├── processor.py
    │   ├── sink.py
    │   ├── reader.py
    │   └── writer.py
    ├── pipeline/
    │   └── pipeline.py
    ├── security/
    │   └── path.py
    ├── storage/
    │   ├── filesystem.py
    │   └── local.py
    ├── readers/
    │   ├── csv.py
    │   ├── parquet.py
    │   └── yaml.py
    ├── writers/
    │   ├── csv.py
    │   └── parquet.py
    ├── sources/
    │   ├── file.py
    │   └── sql.py
    ├── sinks/
    │   ├── file.py
    │   └── sql.py
    ├── config/
    │   ├── loader.py
    │   ├── validator.py
    │   ├── pipeline_builder.py
    │   ├── registry.py
    │   ├── sql_engine_factory.py
    │   ├── sources/
    │   ├── sinks/
    │   ├── storage/
    │   └── processors/
    ├── default_components.py
    └── file_formats.py

tests/
├── unit/
├── integration/
└── functional/

docs/
examples/

The tree is illustrative of the current component organization. It does not imply that every future feature or module has already been implemented.

Generated files and local development state—including .venv/, Python caches, test output, and local ETL data—should be excluded through .gitignore.

Development Workflow

Each implementation unit follows these steps:

  1. Define the requirement.
  2. Establish acceptance criteria.
  3. Choose the smallest suitable design.
  4. Write failing tests.
  5. Implement the minimum required behavior.
  6. Confirm the tests pass.
  7. Refactor where justified.
  8. Run the full test suite and quality checks.
  9. Update documentation.
  10. Commit the completed change.

The project should remain in a working state throughout development.

Contributing and Community

Contributions to ETLRelay are welcome, including bug fixes, documentation improvements, additional tests, and focused feature proposals.

Development follows a test-driven approach with an emphasis on explicit component contracts, maintainability, and incremental improvements.

Contributing

See CONTRIBUTING.md for information about:

  • Setting up the development environment.
  • Working with the dev development branch.
  • Running tests, linting, formatting, and static analysis.
  • Following project architecture and coding guidelines.
  • Preparing and submitting pull requests.

Significant features and architectural changes should be discussed through a GitHub issue before implementation.

Reporting Issues and Requesting Features

Bug reports and feature requests can be submitted through GitHub Issues.

The repository provides dedicated issue templates to help contributors describe reproducible defects, proposed enhancements, and compatibility considerations.

Code of Conduct

All contributors and community participants are expected to follow the project's Code of Conduct.

The Code of Conduct establishes expectations for respectful participation and procedures for reporting unacceptable behavior.

Security vulnerabilities should not be disclosed through public GitHub issues. Follow the private reporting instructions in SECURITY.md.

Accessibility

ETLRelay aims to make its documentation, command-line interface, and contribution process accessible.

See ACCESSIBILITY.md for the project's accessibility considerations, known limitations, and reporting procedures.

License

ETLRelay is licensed under the Apache License, Version 2.0.

See LICENSE for the full license text.

Metadata

Release files for etlrelay 1.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 etlrelay 1.0.1
File Size Uploaded Provenance
etlrelay-1.0.1.tar.gz 306.3 kB With provenance Details

Built distribution (wheel)

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

Total release size: 390.1 kB

Release files / etlrelay-1.0.1.tar.gz

Download URL etlrelay-1.0.1.tar.gz
Size 306.3 kB
Tags Source
SHA-256 checksum
How to use checksums
b3fa64071a0cd64823e64913703dc9c589ef26b2e9d6208567606ff51ce39e26
BLAKE2b-256 checksum
How to use checksums
3644506da8c4e133978775204eae6b8d81ccc1bebe9ccf4c2b6a35cf7f68e4c2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / etlrelay-1.0.1-py3-none-any.whl

Download URL etlrelay-1.0.1-py3-none-any.whl
Size 83.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2939d8ae911355c6b0c068b12ea0c8f9f62e721fb087274f6ce51e19fe52932a
BLAKE2b-256 checksum
How to use checksums
7ea3fbec9e1e59a2502976183d49e32731bb1f0186dc00bb2801eb44d15a2478
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Security for etlrelay 1.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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for etlrelay-1.0.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

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.

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