nexolith 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nexolith-0.2.0/.env.example +6 -0
- nexolith-0.2.0/.github/ISSUE_TEMPLATE/bug_report.yml +34 -0
- nexolith-0.2.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- nexolith-0.2.0/.github/ISSUE_TEMPLATE/feature_request.yml +20 -0
- nexolith-0.2.0/.github/pull_request_template.md +12 -0
- nexolith-0.2.0/.github/workflows/ci.yml +80 -0
- nexolith-0.2.0/.github/workflows/release.yml +74 -0
- nexolith-0.2.0/.gitignore +18 -0
- nexolith-0.2.0/CHANGELOG.md +74 -0
- nexolith-0.2.0/CODE_OF_CONDUCT.md +56 -0
- nexolith-0.2.0/CONTRIBUTING.md +66 -0
- nexolith-0.2.0/FIRST_PIPELINE.md +141 -0
- nexolith-0.2.0/LICENSE +201 -0
- nexolith-0.2.0/PKG-INFO +302 -0
- nexolith-0.2.0/README.md +276 -0
- nexolith-0.2.0/RELEASING.md +79 -0
- nexolith-0.2.0/SECURITY.md +15 -0
- nexolith-0.2.0/assets/nexo-icon.png +0 -0
- nexolith-0.2.0/docker-compose.yml +20 -0
- nexolith-0.2.0/examples/README.md +9 -0
- nexolith-0.2.0/examples/data/README.md +9 -0
- nexolith-0.2.0/examples/data/orders.csv +6 -0
- nexolith-0.2.0/examples/pipelines/README.md +10 -0
- nexolith-0.2.0/examples/pipelines/completed_orders.yaml +20 -0
- nexolith-0.2.0/examples/pipelines/postgresql_orders.yaml +17 -0
- nexolith-0.2.0/pyproject.toml +59 -0
- nexolith-0.2.0/src/README.md +7 -0
- nexolith-0.2.0/src/nexolith/README.md +10 -0
- nexolith-0.2.0/src/nexolith/__init__.py +3 -0
- nexolith-0.2.0/src/nexolith/cli/README.md +16 -0
- nexolith-0.2.0/src/nexolith/cli/__init__.py +3 -0
- nexolith-0.2.0/src/nexolith/cli/app.py +105 -0
- nexolith-0.2.0/src/nexolith/cli/diagnostics.py +125 -0
- nexolith-0.2.0/src/nexolith/config/README.md +9 -0
- nexolith-0.2.0/src/nexolith/config/__init__.py +4 -0
- nexolith-0.2.0/src/nexolith/config/loader.py +67 -0
- nexolith-0.2.0/src/nexolith/config/models.py +97 -0
- nexolith-0.2.0/src/nexolith/connectors/README.md +9 -0
- nexolith-0.2.0/src/nexolith/connectors/__init__.py +3 -0
- nexolith-0.2.0/src/nexolith/connectors/base.py +11 -0
- nexolith-0.2.0/src/nexolith/connectors/csv.py +42 -0
- nexolith-0.2.0/src/nexolith/connectors/registry.py +69 -0
- nexolith-0.2.0/src/nexolith/connectors/sql.py +90 -0
- nexolith-0.2.0/src/nexolith/exceptions/README.md +9 -0
- nexolith-0.2.0/src/nexolith/exceptions/__init__.py +25 -0
- nexolith-0.2.0/src/nexolith/execution/README.md +11 -0
- nexolith-0.2.0/src/nexolith/execution/__init__.py +3 -0
- nexolith-0.2.0/src/nexolith/execution/runner.py +48 -0
- nexolith-0.2.0/src/nexolith/models/README.md +6 -0
- nexolith-0.2.0/src/nexolith/models/__init__.py +3 -0
- nexolith-0.2.0/src/nexolith/models/execution.py +43 -0
- nexolith-0.2.0/src/nexolith/release_validation.py +118 -0
- nexolith-0.2.0/src/nexolith/transformations/README.md +7 -0
- nexolith-0.2.0/src/nexolith/transformations/__init__.py +6 -0
- nexolith-0.2.0/src/nexolith/transformations/base.py +7 -0
- nexolith-0.2.0/src/nexolith/transformations/builtin.py +87 -0
- nexolith-0.2.0/src/nexolith/transformations/registry.py +54 -0
- nexolith-0.2.0/src/nexolith/types.py +5 -0
- nexolith-0.2.0/tests/README.md +8 -0
- nexolith-0.2.0/tests/conftest.py +42 -0
- nexolith-0.2.0/tests/integration/README.md +22 -0
- nexolith-0.2.0/tests/integration/test_connectors.py +18 -0
- nexolith-0.2.0/tests/integration/test_pipeline.py +73 -0
- nexolith-0.2.0/tests/integration/test_postgresql.py +229 -0
- nexolith-0.2.0/tests/unit/README.md +14 -0
- nexolith-0.2.0/tests/unit/test_cli.py +29 -0
- nexolith-0.2.0/tests/unit/test_config.py +75 -0
- nexolith-0.2.0/tests/unit/test_environment_diagnostics.py +129 -0
- nexolith-0.2.0/tests/unit/test_error_diagnostics.py +196 -0
- nexolith-0.2.0/tests/unit/test_runner.py +88 -0
- nexolith-0.2.0/tests/unit/test_transformations.py +43 -0
- nexolith-0.2.0/tests/unit/test_validate_release.py +109 -0
- nexolith-0.2.0/uv.lock +1022 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report reproducible incorrect behavior
|
|
3
|
+
title: "[Bug]: "
|
|
4
|
+
labels: ["bug"]
|
|
5
|
+
body:
|
|
6
|
+
- type: textarea
|
|
7
|
+
id: description
|
|
8
|
+
attributes:
|
|
9
|
+
label: Description
|
|
10
|
+
description: What happened, and what did you expect?
|
|
11
|
+
validations:
|
|
12
|
+
required: true
|
|
13
|
+
- type: textarea
|
|
14
|
+
id: reproduction
|
|
15
|
+
attributes:
|
|
16
|
+
label: Reproduction
|
|
17
|
+
description: Include a minimal sanitized pipeline and command.
|
|
18
|
+
validations:
|
|
19
|
+
required: true
|
|
20
|
+
- type: input
|
|
21
|
+
id: versions
|
|
22
|
+
attributes:
|
|
23
|
+
label: Versions
|
|
24
|
+
description: Nexolith, Python, and operating system versions.
|
|
25
|
+
validations:
|
|
26
|
+
required: true
|
|
27
|
+
- type: checkboxes
|
|
28
|
+
id: security
|
|
29
|
+
attributes:
|
|
30
|
+
label: Security
|
|
31
|
+
options:
|
|
32
|
+
- label: This report contains no credentials or private vulnerability details.
|
|
33
|
+
required: true
|
|
34
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Propose an improvement to Nexolith
|
|
3
|
+
title: "[Feature]: "
|
|
4
|
+
labels: ["enhancement"]
|
|
5
|
+
body:
|
|
6
|
+
- type: textarea
|
|
7
|
+
id: problem
|
|
8
|
+
attributes:
|
|
9
|
+
label: Problem
|
|
10
|
+
description: What user problem should this solve?
|
|
11
|
+
validations:
|
|
12
|
+
required: true
|
|
13
|
+
- type: textarea
|
|
14
|
+
id: proposal
|
|
15
|
+
attributes:
|
|
16
|
+
label: Proposed solution
|
|
17
|
+
description: Describe the smallest useful solution and alternatives considered.
|
|
18
|
+
validations:
|
|
19
|
+
required: true
|
|
20
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
quality:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- name: Install uv
|
|
17
|
+
uses: astral-sh/setup-uv@v6
|
|
18
|
+
with:
|
|
19
|
+
enable-cache: true
|
|
20
|
+
- name: Install Python
|
|
21
|
+
run: uv python install 3.12
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: uv sync --extra dev
|
|
24
|
+
- name: Check formatting
|
|
25
|
+
run: uv run ruff format --check .
|
|
26
|
+
- name: Lint
|
|
27
|
+
run: uv run ruff check .
|
|
28
|
+
- name: Type check
|
|
29
|
+
run: uv run mypy src
|
|
30
|
+
- name: Test
|
|
31
|
+
run: uv run pytest
|
|
32
|
+
|
|
33
|
+
build:
|
|
34
|
+
name: Build distributions
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
- name: Install uv
|
|
39
|
+
uses: astral-sh/setup-uv@v6
|
|
40
|
+
- name: Install build Python
|
|
41
|
+
run: uv python install 3.12
|
|
42
|
+
- name: Build wheel and source distribution
|
|
43
|
+
run: uv build --python 3.12
|
|
44
|
+
- name: Upload distributions
|
|
45
|
+
uses: actions/upload-artifact@v4
|
|
46
|
+
with:
|
|
47
|
+
name: distributions
|
|
48
|
+
path: dist/
|
|
49
|
+
if-no-files-found: error
|
|
50
|
+
retention-days: 1
|
|
51
|
+
|
|
52
|
+
install:
|
|
53
|
+
name: Install / Python ${{ matrix.python-version }}
|
|
54
|
+
needs: build
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
strategy:
|
|
57
|
+
fail-fast: false
|
|
58
|
+
matrix:
|
|
59
|
+
python-version: ["3.12", "3.13", "3.14"]
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@v4
|
|
62
|
+
- name: Install Python ${{ matrix.python-version }}
|
|
63
|
+
uses: actions/setup-python@v5
|
|
64
|
+
with:
|
|
65
|
+
python-version: ${{ matrix.python-version }}
|
|
66
|
+
- name: Download distributions
|
|
67
|
+
uses: actions/download-artifact@v4
|
|
68
|
+
with:
|
|
69
|
+
name: distributions
|
|
70
|
+
path: dist/
|
|
71
|
+
- name: Install built wheel
|
|
72
|
+
run: python -m pip install --disable-pip-version-check dist/*.whl
|
|
73
|
+
- name: Verify package import
|
|
74
|
+
run: python -c "import nexolith; print(nexolith.__version__)"
|
|
75
|
+
- name: Verify version output
|
|
76
|
+
run: nexolith --version
|
|
77
|
+
- name: Validate service-free pipeline
|
|
78
|
+
run: nexolith validate examples/pipelines/completed_orders.yaml
|
|
79
|
+
- name: Run service-free pipeline
|
|
80
|
+
run: nexolith run examples/pipelines/completed_orders.yaml
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*.*.*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: release-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: false
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
build:
|
|
17
|
+
name: Build and validate distributions
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- name: Check out tagged source
|
|
21
|
+
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
|
22
|
+
with:
|
|
23
|
+
fetch-depth: 0
|
|
24
|
+
persist-credentials: false
|
|
25
|
+
- name: Verify tag belongs to master
|
|
26
|
+
run: |
|
|
27
|
+
if ! git merge-base --is-ancestor "${GITHUB_SHA}" "origin/master"; then
|
|
28
|
+
echo "::error::Release tags must point to a commit contained in master."
|
|
29
|
+
exit 1
|
|
30
|
+
fi
|
|
31
|
+
- name: Install uv
|
|
32
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
33
|
+
- name: Install build environment
|
|
34
|
+
run: uv sync --frozen --extra dev --python 3.12
|
|
35
|
+
- name: Validate release metadata
|
|
36
|
+
run: uv run python -m nexolith.release_validation --tag "${GITHUB_REF_NAME}"
|
|
37
|
+
- name: Build wheel and source distribution
|
|
38
|
+
run: uv build --python 3.12
|
|
39
|
+
- name: Validate distribution metadata
|
|
40
|
+
run: uv run twine check dist/*
|
|
41
|
+
- name: Validate distribution set
|
|
42
|
+
run: >-
|
|
43
|
+
uv run python -m nexolith.release_validation
|
|
44
|
+
--tag "${GITHUB_REF_NAME}"
|
|
45
|
+
--dist-dir dist
|
|
46
|
+
- name: Store validated distributions
|
|
47
|
+
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
|
48
|
+
with:
|
|
49
|
+
name: release-distributions
|
|
50
|
+
path: dist/
|
|
51
|
+
if-no-files-found: error
|
|
52
|
+
retention-days: 1
|
|
53
|
+
|
|
54
|
+
publish:
|
|
55
|
+
name: Publish to PyPI
|
|
56
|
+
needs: build
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
environment:
|
|
59
|
+
name: pypi
|
|
60
|
+
url: https://pypi.org/p/nexolith
|
|
61
|
+
permissions:
|
|
62
|
+
id-token: write
|
|
63
|
+
steps:
|
|
64
|
+
- name: Download validated distributions
|
|
65
|
+
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
|
|
66
|
+
with:
|
|
67
|
+
name: release-distributions
|
|
68
|
+
path: dist/
|
|
69
|
+
- name: Publish distributions with Trusted Publishing
|
|
70
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
71
|
+
with:
|
|
72
|
+
packages-dir: dist/
|
|
73
|
+
verify-metadata: false
|
|
74
|
+
attestations: true
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable user-facing changes to Nexolith are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and Nexolith
|
|
6
|
+
follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
Changes targeting releases after 0.2.0 will be recorded here.
|
|
11
|
+
|
|
12
|
+
## [0.2.0] - 2026-07-31
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- Added a tag-driven PyPI release workflow using short-lived Trusted Publishing credentials,
|
|
17
|
+
protected-environment approval, one-time artifact builds, and fail-closed release validation.
|
|
18
|
+
- Added `nexolith diagnostics`, a deterministic and secret-safe environment report for issue
|
|
19
|
+
submissions. It includes Nexolith, Python, platform, installation, dependency, SQLite, and
|
|
20
|
+
PostgreSQL driver availability without exposing local paths or environment values
|
|
21
|
+
([PR #4](https://github.com/Reiver56/Nexolith/pull/4)).
|
|
22
|
+
- Added a service-free zero-to-first-pipeline tutorial with a CSV example that covers installation,
|
|
23
|
+
validation, execution, and output inspection
|
|
24
|
+
([PR #2](https://github.com/Reiver56/Nexolith/pull/2)).
|
|
25
|
+
- Added an opt-in Docker Compose workflow and integration coverage for PostgreSQL connection,
|
|
26
|
+
reading, writing, destination modes, and CSV-to-PostgreSQL execution
|
|
27
|
+
([PR #1](https://github.com/Reiver56/Nexolith/pull/1)).
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- Standardized expected failures under configuration, connector, transformation, and execution
|
|
32
|
+
domain errors. CLI diagnostics now use stable categories and preserve original causes for API
|
|
33
|
+
callers ([PR #3](https://github.com/Reiver56/Nexolith/pull/3)).
|
|
34
|
+
- Declared Python 3.12, 3.13, and 3.14 as the supported versions. CI now builds the distribution
|
|
35
|
+
once, installs the wheel on every supported version, and verifies import plus the first CLI
|
|
36
|
+
workflow ([PR #5](https://github.com/Reiver56/Nexolith/pull/5)).
|
|
37
|
+
- Made the Docker Compose PostgreSQL host port configurable through `POSTGRES_PORT`
|
|
38
|
+
([PR #1](https://github.com/Reiver56/Nexolith/pull/1)).
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- Expected YAML, configuration, CSV, SQL, and transformation failures now produce actionable
|
|
43
|
+
messages without an expected-error traceback. Unexpected programming errors continue to
|
|
44
|
+
propagate for debugging ([PR #3](https://github.com/Reiver56/Nexolith/pull/3)).
|
|
45
|
+
- Explicit PostgreSQL test runs now fail clearly when `DATABASE_URL` is missing or PostgreSQL is
|
|
46
|
+
unreachable, while the standard service-free suite remains independent of Docker
|
|
47
|
+
([PR #1](https://github.com/Reiver56/Nexolith/pull/1)).
|
|
48
|
+
|
|
49
|
+
### Security
|
|
50
|
+
|
|
51
|
+
- Redacted credentials, authenticated connection URLs, and raw driver details from expected CLI
|
|
52
|
+
failures. Environment diagnostics do not collect or report usernames, hostnames, environment
|
|
53
|
+
values, or local paths
|
|
54
|
+
([PR #3](https://github.com/Reiver56/Nexolith/pull/3),
|
|
55
|
+
[PR #4](https://github.com/Reiver56/Nexolith/pull/4)).
|
|
56
|
+
|
|
57
|
+
### Breaking changes and migrations
|
|
58
|
+
|
|
59
|
+
- **CLI exit codes changed.** Scripts that previously expected exit code `1` for every failure must
|
|
60
|
+
use `2` for configuration or validation failures and `3` for execution, connector, or
|
|
61
|
+
transformation failures ([PR #3](https://github.com/Reiver56/Nexolith/pull/3)).
|
|
62
|
+
- **Python 3.15 and newer are outside the supported range.** Package metadata now requires
|
|
63
|
+
`>=3.12,<3.15`. Use Python 3.12, 3.13, or 3.14 before installing Nexolith 0.2.0
|
|
64
|
+
([PR #5](https://github.com/Reiver56/Nexolith/pull/5)).
|
|
65
|
+
- No pipeline YAML, connector configuration, or stored-data migration is required. The
|
|
66
|
+
`ComponentNotFoundError` import and the result-returning default of `PipelineRunner.run()` remain
|
|
67
|
+
available for compatibility ([PR #3](https://github.com/Reiver56/Nexolith/pull/3)).
|
|
68
|
+
|
|
69
|
+
## [0.1.0] - 2026-07-31
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
|
|
73
|
+
- Initial open-source Nexolith project with declarative YAML pipelines, CSV and SQL connectors,
|
|
74
|
+
built-in transformations, a Typer CLI, and service-free execution.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our community a
|
|
6
|
+
harassment-free experience for everyone, regardless of age, body size, visible or invisible
|
|
7
|
+
disability, ethnicity, sex characteristics, gender identity and expression, level of
|
|
8
|
+
experience, education, socio-economic status, nationality, personal appearance, race,
|
|
9
|
+
religion, or sexual identity and orientation.
|
|
10
|
+
|
|
11
|
+
We pledge to act and interact in ways that contribute to an open, welcoming, diverse,
|
|
12
|
+
inclusive, and healthy community.
|
|
13
|
+
|
|
14
|
+
## Our Standards
|
|
15
|
+
|
|
16
|
+
Examples of behavior that contributes to a positive environment include demonstrating
|
|
17
|
+
empathy, respecting differing viewpoints, accepting constructive feedback, taking
|
|
18
|
+
responsibility, and focusing on what is best for the community.
|
|
19
|
+
|
|
20
|
+
Unacceptable behavior includes sexualized language or imagery, trolling or insulting
|
|
21
|
+
comments, public or private harassment, publishing others' private information without
|
|
22
|
+
permission, and other conduct reasonably considered inappropriate in a professional setting.
|
|
23
|
+
|
|
24
|
+
## Enforcement Responsibilities
|
|
25
|
+
|
|
26
|
+
Community leaders are responsible for clarifying and enforcing standards of acceptable
|
|
27
|
+
behavior and will take appropriate and fair corrective action in response to behavior they
|
|
28
|
+
deem inappropriate, threatening, offensive, or harmful.
|
|
29
|
+
|
|
30
|
+
## Scope
|
|
31
|
+
|
|
32
|
+
This Code of Conduct applies within all community spaces and when an individual is officially
|
|
33
|
+
representing the community in public spaces.
|
|
34
|
+
|
|
35
|
+
## Enforcement
|
|
36
|
+
|
|
37
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported through
|
|
38
|
+
the private channel described in `SECURITY.md`. All complaints will be reviewed and
|
|
39
|
+
investigated promptly and fairly. Community leaders will respect the privacy and security of
|
|
40
|
+
the reporter.
|
|
41
|
+
|
|
42
|
+
## Enforcement Guidelines
|
|
43
|
+
|
|
44
|
+
Community leaders will follow these guidelines in determining consequences:
|
|
45
|
+
|
|
46
|
+
1. **Correction** — A private warning and clarification for inappropriate behavior.
|
|
47
|
+
2. **Warning** — A warning with consequences for continued behavior.
|
|
48
|
+
3. **Temporary Ban** — A temporary ban from interaction with the community.
|
|
49
|
+
4. **Permanent Ban** — Permanent removal for sustained or severe violations.
|
|
50
|
+
|
|
51
|
+
## Attribution
|
|
52
|
+
|
|
53
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1.
|
|
54
|
+
|
|
55
|
+
[homepage]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
|
56
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Contributing to Nexolith
|
|
2
|
+
|
|
3
|
+
Thank you for helping make Nexolith better.
|
|
4
|
+
|
|
5
|
+
## Set up the project
|
|
6
|
+
|
|
7
|
+
Fork and clone the repository, then install Python 3.12, 3.13, or 3.14, uv, and the development
|
|
8
|
+
dependencies:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
uv sync --extra dev
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Create a focused branch from an up-to-date `main`:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
git switch -c fix/short-description
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quality checks
|
|
21
|
+
|
|
22
|
+
Run the complete local check suite before submitting a pull request:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
uv run ruff format .
|
|
26
|
+
uv run ruff check .
|
|
27
|
+
uv run mypy src
|
|
28
|
+
uv run pytest
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Code should be typed, small, readable, and separated by responsibility. Prefer explicit
|
|
32
|
+
domain errors, avoid global mutable state, never execute pipeline content as code, and add
|
|
33
|
+
tests for changed behavior. Ruff is the source of truth for formatting and lint rules.
|
|
34
|
+
|
|
35
|
+
## Issues and proposals
|
|
36
|
+
|
|
37
|
+
Search existing issues before filing a report. Bug reports should include a minimal pipeline,
|
|
38
|
+
the command used, expected and actual behavior, Nexolith and Python versions, and sanitized
|
|
39
|
+
logs. Feature proposals should explain the user problem and why it belongs in the focused
|
|
40
|
+
core. Do not include credentials or security vulnerabilities in public issues; follow
|
|
41
|
+
`SECURITY.md`.
|
|
42
|
+
|
|
43
|
+
## Pull requests
|
|
44
|
+
|
|
45
|
+
Keep pull requests focused and explain both what changed and why. Add or update tests and
|
|
46
|
+
documentation, complete the pull request template, and ensure CI passes. Maintainers may ask
|
|
47
|
+
for changes to preserve the small, modular architecture. Use clear commit messages; merge
|
|
48
|
+
strategy is determined by the maintainers.
|
|
49
|
+
|
|
50
|
+
## Changelog
|
|
51
|
+
|
|
52
|
+
Update `CHANGELOG.md` for every user-facing addition, behavior change, fix, deprecation, removal,
|
|
53
|
+
or security improvement. Group entries by Keep a Changelog category, link the relevant issue or
|
|
54
|
+
pull request when useful, and state breaking changes plus required migrations explicitly.
|
|
55
|
+
|
|
56
|
+
Version headings must use the exact form `## [X.Y.Z] - status-or-date`, without a leading `v`.
|
|
57
|
+
Release automation maps a tag such as `v0.2.0` to the `[0.2.0]` heading and fails when that section
|
|
58
|
+
is absent. Use `Unreleased` while preparing a version, then replace it with an ISO date such as
|
|
59
|
+
`2026-07-31` when publishing the release.
|
|
60
|
+
|
|
61
|
+
## Releases
|
|
62
|
+
|
|
63
|
+
Maintainers must follow [RELEASING.md](RELEASING.md). Releases originate from reviewed `master`
|
|
64
|
+
commits and exact `vX.Y.Z` tags. Never store a PyPI password or API token in GitHub: publication
|
|
65
|
+
uses the protected `pypi` environment and PyPI Trusted Publishing.
|
|
66
|
+
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Your first Nexolith pipeline
|
|
2
|
+
|
|
3
|
+
This tutorial takes you from a fresh clone to a verified CSV output. It uses only local files: no
|
|
4
|
+
database, Docker, credentials, `.env`, or external service is required. Allow about five minutes
|
|
5
|
+
after Python and `uv` are installed.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
Install:
|
|
10
|
+
|
|
11
|
+
- [Git](https://git-scm.com/)
|
|
12
|
+
- Python 3.12, 3.13, or 3.14
|
|
13
|
+
- [uv](https://docs.astral.sh/uv/getting-started/installation/)
|
|
14
|
+
|
|
15
|
+
Confirm that the tools are available:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
git --version
|
|
19
|
+
uv --version
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`uv` creates and manages the Python environment, so you do not need to activate a virtual
|
|
23
|
+
environment manually.
|
|
24
|
+
|
|
25
|
+
## 1. Clone and install
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git clone https://github.com/Reiver56/Nexolith.git
|
|
29
|
+
cd Nexolith
|
|
30
|
+
uv sync --extra dev
|
|
31
|
+
uv run nexolith --version
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The last command should print:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
Nexolith 0.2.0
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`uv sync` creates `.venv` when needed and installs Nexolith plus its development dependencies from
|
|
41
|
+
the lock file.
|
|
42
|
+
|
|
43
|
+
## 2. Meet the example
|
|
44
|
+
|
|
45
|
+
The tutorial uses two committed files:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
examples/
|
|
49
|
+
├── data/
|
|
50
|
+
│ └── orders.csv
|
|
51
|
+
└── pipelines/
|
|
52
|
+
└── completed_orders.yaml
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
[`orders.csv`](examples/data/orders.csv) contains five orders: three have `completed` status, one
|
|
56
|
+
is `pending`, and one is `cancelled`.
|
|
57
|
+
[`completed_orders.yaml`](examples/pipelines/completed_orders.yaml) defines this flow:
|
|
58
|
+
|
|
59
|
+
1. The `csv` **source** reads all five rows from `examples/data/orders.csv`.
|
|
60
|
+
2. The ordered **transformations** keep rows whose `status` equals `completed`, select `id`,
|
|
61
|
+
`customer_id`, and `total`, then rename `total` to `order_total`.
|
|
62
|
+
3. The `csv` **destination** writes the three remaining rows to
|
|
63
|
+
`build/completed_orders.csv`. Nexolith creates the `build` directory if necessary and
|
|
64
|
+
overwrites the CSV on later runs.
|
|
65
|
+
|
|
66
|
+
Open the small YAML file before continuing if you want to see the complete declarative pipeline.
|
|
67
|
+
Run all following commands from the repository root because its paths are relative to that
|
|
68
|
+
directory.
|
|
69
|
+
|
|
70
|
+
## 3. Validate
|
|
71
|
+
|
|
72
|
+
Validation checks the YAML structure and configuration without reading input or writing output:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
uv run nexolith validate examples/pipelines/completed_orders.yaml
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Expected output:
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
Pipeline 'completed_orders' is valid.
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 4. Run
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
uv run nexolith run examples/pipelines/completed_orders.yaml
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The duration varies, but the meaningful output is:
|
|
91
|
+
|
|
92
|
+
```text
|
|
93
|
+
Pipeline: completed_orders
|
|
94
|
+
Status: succeeded
|
|
95
|
+
Rows read: 5
|
|
96
|
+
Rows written: 3
|
|
97
|
+
Duration: <varies>s
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Informational log lines may also appear. A failed pipeline exits with a non-zero status and prints
|
|
101
|
+
an error.
|
|
102
|
+
|
|
103
|
+
## 5. Inspect the output
|
|
104
|
+
|
|
105
|
+
Use Python's standard CSV reader for the same check in PowerShell, Command Prompt, bash, and other
|
|
106
|
+
common shells:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
uv run python -c "import csv; print(*csv.DictReader(open('build/completed_orders.csv', newline='', encoding='utf-8')), sep='\n')"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Expected rows:
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
{'id': '1', 'customer_id': '101', 'order_total': '49.90'}
|
|
116
|
+
{'id': '3', 'customer_id': '103', 'order_total': '125.00'}
|
|
117
|
+
{'id': '5', 'customer_id': '105', 'order_total': '75.25'}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The header and those three rows are the entire generated file. The source remains unchanged.
|
|
121
|
+
Because `build/` is ignored by Git, this output will not be committed accidentally.
|
|
122
|
+
|
|
123
|
+
## Troubleshooting
|
|
124
|
+
|
|
125
|
+
- **`uv` is not recognized:** install `uv`, restart the shell so its installation directory is on
|
|
126
|
+
`PATH`, and run `uv --version`.
|
|
127
|
+
- **Unsupported Python version:** install Python 3.12, 3.13, or 3.14 (for example,
|
|
128
|
+
`uv python install 3.12`), then repeat `uv sync --extra dev`.
|
|
129
|
+
- **Pipeline file not found or input CSV cannot be read:** return to the cloned repository root and
|
|
130
|
+
run the commands there. Confirm that both files shown in the tree above exist.
|
|
131
|
+
- **Validation fails:** use the reported field path to check the YAML. Spaces matter in YAML; do
|
|
132
|
+
not replace indentation with tabs.
|
|
133
|
+
- **The output differs after editing the example:** rerun validation and execution. The
|
|
134
|
+
destination is overwritten on each successful run.
|
|
135
|
+
|
|
136
|
+
## Next step
|
|
137
|
+
|
|
138
|
+
Copy `completed_orders.yaml`, change the filter or selected columns, and give the destination a
|
|
139
|
+
different path under `build/`. Then review the supported
|
|
140
|
+
[connectors and transformations](README.md#connectors). When you need a database destination,
|
|
141
|
+
start with SQLite before moving to the optional PostgreSQL example.
|