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.
Files changed (73) hide show
  1. nexolith-0.2.0/.env.example +6 -0
  2. nexolith-0.2.0/.github/ISSUE_TEMPLATE/bug_report.yml +34 -0
  3. nexolith-0.2.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. nexolith-0.2.0/.github/ISSUE_TEMPLATE/feature_request.yml +20 -0
  5. nexolith-0.2.0/.github/pull_request_template.md +12 -0
  6. nexolith-0.2.0/.github/workflows/ci.yml +80 -0
  7. nexolith-0.2.0/.github/workflows/release.yml +74 -0
  8. nexolith-0.2.0/.gitignore +18 -0
  9. nexolith-0.2.0/CHANGELOG.md +74 -0
  10. nexolith-0.2.0/CODE_OF_CONDUCT.md +56 -0
  11. nexolith-0.2.0/CONTRIBUTING.md +66 -0
  12. nexolith-0.2.0/FIRST_PIPELINE.md +141 -0
  13. nexolith-0.2.0/LICENSE +201 -0
  14. nexolith-0.2.0/PKG-INFO +302 -0
  15. nexolith-0.2.0/README.md +276 -0
  16. nexolith-0.2.0/RELEASING.md +79 -0
  17. nexolith-0.2.0/SECURITY.md +15 -0
  18. nexolith-0.2.0/assets/nexo-icon.png +0 -0
  19. nexolith-0.2.0/docker-compose.yml +20 -0
  20. nexolith-0.2.0/examples/README.md +9 -0
  21. nexolith-0.2.0/examples/data/README.md +9 -0
  22. nexolith-0.2.0/examples/data/orders.csv +6 -0
  23. nexolith-0.2.0/examples/pipelines/README.md +10 -0
  24. nexolith-0.2.0/examples/pipelines/completed_orders.yaml +20 -0
  25. nexolith-0.2.0/examples/pipelines/postgresql_orders.yaml +17 -0
  26. nexolith-0.2.0/pyproject.toml +59 -0
  27. nexolith-0.2.0/src/README.md +7 -0
  28. nexolith-0.2.0/src/nexolith/README.md +10 -0
  29. nexolith-0.2.0/src/nexolith/__init__.py +3 -0
  30. nexolith-0.2.0/src/nexolith/cli/README.md +16 -0
  31. nexolith-0.2.0/src/nexolith/cli/__init__.py +3 -0
  32. nexolith-0.2.0/src/nexolith/cli/app.py +105 -0
  33. nexolith-0.2.0/src/nexolith/cli/diagnostics.py +125 -0
  34. nexolith-0.2.0/src/nexolith/config/README.md +9 -0
  35. nexolith-0.2.0/src/nexolith/config/__init__.py +4 -0
  36. nexolith-0.2.0/src/nexolith/config/loader.py +67 -0
  37. nexolith-0.2.0/src/nexolith/config/models.py +97 -0
  38. nexolith-0.2.0/src/nexolith/connectors/README.md +9 -0
  39. nexolith-0.2.0/src/nexolith/connectors/__init__.py +3 -0
  40. nexolith-0.2.0/src/nexolith/connectors/base.py +11 -0
  41. nexolith-0.2.0/src/nexolith/connectors/csv.py +42 -0
  42. nexolith-0.2.0/src/nexolith/connectors/registry.py +69 -0
  43. nexolith-0.2.0/src/nexolith/connectors/sql.py +90 -0
  44. nexolith-0.2.0/src/nexolith/exceptions/README.md +9 -0
  45. nexolith-0.2.0/src/nexolith/exceptions/__init__.py +25 -0
  46. nexolith-0.2.0/src/nexolith/execution/README.md +11 -0
  47. nexolith-0.2.0/src/nexolith/execution/__init__.py +3 -0
  48. nexolith-0.2.0/src/nexolith/execution/runner.py +48 -0
  49. nexolith-0.2.0/src/nexolith/models/README.md +6 -0
  50. nexolith-0.2.0/src/nexolith/models/__init__.py +3 -0
  51. nexolith-0.2.0/src/nexolith/models/execution.py +43 -0
  52. nexolith-0.2.0/src/nexolith/release_validation.py +118 -0
  53. nexolith-0.2.0/src/nexolith/transformations/README.md +7 -0
  54. nexolith-0.2.0/src/nexolith/transformations/__init__.py +6 -0
  55. nexolith-0.2.0/src/nexolith/transformations/base.py +7 -0
  56. nexolith-0.2.0/src/nexolith/transformations/builtin.py +87 -0
  57. nexolith-0.2.0/src/nexolith/transformations/registry.py +54 -0
  58. nexolith-0.2.0/src/nexolith/types.py +5 -0
  59. nexolith-0.2.0/tests/README.md +8 -0
  60. nexolith-0.2.0/tests/conftest.py +42 -0
  61. nexolith-0.2.0/tests/integration/README.md +22 -0
  62. nexolith-0.2.0/tests/integration/test_connectors.py +18 -0
  63. nexolith-0.2.0/tests/integration/test_pipeline.py +73 -0
  64. nexolith-0.2.0/tests/integration/test_postgresql.py +229 -0
  65. nexolith-0.2.0/tests/unit/README.md +14 -0
  66. nexolith-0.2.0/tests/unit/test_cli.py +29 -0
  67. nexolith-0.2.0/tests/unit/test_config.py +75 -0
  68. nexolith-0.2.0/tests/unit/test_environment_diagnostics.py +129 -0
  69. nexolith-0.2.0/tests/unit/test_error_diagnostics.py +196 -0
  70. nexolith-0.2.0/tests/unit/test_runner.py +88 -0
  71. nexolith-0.2.0/tests/unit/test_transformations.py +43 -0
  72. nexolith-0.2.0/tests/unit/test_validate_release.py +109 -0
  73. nexolith-0.2.0/uv.lock +1022 -0
@@ -0,0 +1,6 @@
1
+ # Non-sensitive local Docker Compose defaults. Never reuse them in production.
2
+ DATABASE_URL=postgresql+psycopg://nexolith:nexolith@localhost:5432/nexolith
3
+ POSTGRES_DB=nexolith
4
+ POSTGRES_USER=nexolith
5
+ POSTGRES_PASSWORD=nexolith
6
+ POSTGRES_PORT=5432
@@ -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,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security vulnerability
4
+ url: https://github.com/Reiver56/Nexolith/security/advisories/new
5
+ about: Report vulnerabilities privately.
@@ -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,12 @@
1
+ ## Summary
2
+
3
+ Describe what changed and why.
4
+
5
+ ## Validation
6
+
7
+ - [ ] `uv run ruff format --check .`
8
+ - [ ] `uv run ruff check .`
9
+ - [ ] `uv run mypy src`
10
+ - [ ] `uv run pytest`
11
+ - [ ] Documentation updated where needed
12
+
@@ -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,18 @@
1
+ .env
2
+ .venv/
3
+ .uv-cache/
4
+ .uv-python/
5
+ __pycache__/
6
+ *.py[cod]
7
+ *.db
8
+ .pytest_cache/
9
+ .mypy_cache/
10
+ .ruff_cache/
11
+ .idea/
12
+ .vscode/
13
+ .coverage
14
+ coverage.xml
15
+ htmlcov/
16
+ dist/
17
+ build/
18
+ *.egg-info/
@@ -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.