alcove 0.1.1__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.
- alcove-0.1.1/.env.example +10 -0
- alcove-0.1.1/.github/workflows/ci.yml +63 -0
- alcove-0.1.1/.gitignore +165 -0
- alcove-0.1.1/.python-version +1 -0
- alcove-0.1.1/.vscode/settings.json +11 -0
- alcove-0.1.1/CLAUDE.md +4 -0
- alcove-0.1.1/LICENSE +21 -0
- alcove-0.1.1/MANIFEST.in +4 -0
- alcove-0.1.1/Makefile +69 -0
- alcove-0.1.1/PKG-INFO +211 -0
- alcove-0.1.1/README.md +184 -0
- alcove-0.1.1/docker-compose.yml +34 -0
- alcove-0.1.1/pyproject.toml +54 -0
- alcove-0.1.1/src/alcove/__init__.py +520 -0
- alcove-0.1.1/src/alcove/core.py +79 -0
- alcove-0.1.1/src/alcove/exceptions.py +10 -0
- alcove-0.1.1/src/alcove/paths.py +9 -0
- alcove-0.1.1/src/alcove/schemas/alcove-v1.schema.json +41 -0
- alcove-0.1.1/src/alcove/schemas/snapshot-v1.schema.json +73 -0
- alcove-0.1.1/src/alcove/schemas/table-config-v1.schema.json +86 -0
- alcove-0.1.1/src/alcove/schemas/table-v1.schema.json +66 -0
- alcove-0.1.1/src/alcove/schemas.py +22 -0
- alcove-0.1.1/src/alcove/snapshots.py +328 -0
- alcove-0.1.1/src/alcove/steps.py +94 -0
- alcove-0.1.1/src/alcove/table_metadata.py +239 -0
- alcove-0.1.1/src/alcove/tables.py +312 -0
- alcove-0.1.1/src/alcove/types.py +57 -0
- alcove-0.1.1/src/alcove/utils.py +98 -0
- alcove-0.1.1/tests/conftest.py +159 -0
- alcove-0.1.1/tests/test_alcove.py +573 -0
- alcove-0.1.1/tests/test_tables.py +231 -0
- alcove-0.1.1/uv.lock +914 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# S3-compatible storage credentials for Backblaze B2
|
|
2
|
+
S3_ACCESS_KEY=your_application_key_id
|
|
3
|
+
S3_SECRET_KEY=your_application_key
|
|
4
|
+
S3_BUCKET_NAME=your_bucket_name
|
|
5
|
+
S3_ENDPOINT_URL=your_endpoint_url
|
|
6
|
+
|
|
7
|
+
TEST_ACCESS_KEY=
|
|
8
|
+
TEST_SECRET_KEY=
|
|
9
|
+
TEST_ENDPOINT_URL=
|
|
10
|
+
TEST_BUCKET_NAME=
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
|
|
15
|
+
services:
|
|
16
|
+
minio:
|
|
17
|
+
image: lazybit/minio
|
|
18
|
+
ports:
|
|
19
|
+
- 9000:9000
|
|
20
|
+
env:
|
|
21
|
+
MINIO_ACCESS_KEY: justtesting
|
|
22
|
+
MINIO_SECRET_KEY: justtesting
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- name: Checkout code
|
|
26
|
+
uses: actions/checkout@v2
|
|
27
|
+
|
|
28
|
+
- name: Set up Python
|
|
29
|
+
uses: actions/setup-python@v2
|
|
30
|
+
with:
|
|
31
|
+
python-version: 3.12
|
|
32
|
+
|
|
33
|
+
- name: Install uv
|
|
34
|
+
run: |
|
|
35
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
36
|
+
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
|
37
|
+
|
|
38
|
+
- name: Install dependencies
|
|
39
|
+
run: make .venv
|
|
40
|
+
|
|
41
|
+
- name: Set up testing minio bucket
|
|
42
|
+
run: |
|
|
43
|
+
.venv/bin/python3 - <<'EOF'
|
|
44
|
+
from minio import Minio
|
|
45
|
+
|
|
46
|
+
minio = Minio(
|
|
47
|
+
'localhost:9000',
|
|
48
|
+
access_key='justtesting',
|
|
49
|
+
secret_key='justtesting',
|
|
50
|
+
secure=False
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
minio.make_bucket('test')
|
|
54
|
+
print(f'{minio.list_buckets()}')
|
|
55
|
+
EOF
|
|
56
|
+
|
|
57
|
+
- name: Run tests
|
|
58
|
+
run: make test
|
|
59
|
+
env:
|
|
60
|
+
B2_APPLICATION_KEY: justtesting
|
|
61
|
+
B2_APPLICATION_KEY_ID: justtesting
|
|
62
|
+
B2_BUCKET_NAME: test
|
|
63
|
+
B2_ENDPOINT_URL: http://localhost:9000/
|
alcove-0.1.1/.gitignore
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py,cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
#Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# poetry
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
102
|
+
#poetry.lock
|
|
103
|
+
|
|
104
|
+
# pdm
|
|
105
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
106
|
+
#pdm.lock
|
|
107
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
108
|
+
# in version control.
|
|
109
|
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
110
|
+
.pdm.toml
|
|
111
|
+
.pdm-python
|
|
112
|
+
.pdm-build/
|
|
113
|
+
|
|
114
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
115
|
+
__pypackages__/
|
|
116
|
+
|
|
117
|
+
# Celery stuff
|
|
118
|
+
celerybeat-schedule
|
|
119
|
+
celerybeat.pid
|
|
120
|
+
|
|
121
|
+
# SageMath parsed files
|
|
122
|
+
*.sage.py
|
|
123
|
+
|
|
124
|
+
# Environments
|
|
125
|
+
.env
|
|
126
|
+
.venv
|
|
127
|
+
env/
|
|
128
|
+
venv/
|
|
129
|
+
ENV/
|
|
130
|
+
env.bak/
|
|
131
|
+
venv.bak/
|
|
132
|
+
|
|
133
|
+
# Spyder project settings
|
|
134
|
+
.spyderproject
|
|
135
|
+
.spyproject
|
|
136
|
+
|
|
137
|
+
# Rope project settings
|
|
138
|
+
.ropeproject
|
|
139
|
+
|
|
140
|
+
# mkdocs documentation
|
|
141
|
+
/site
|
|
142
|
+
|
|
143
|
+
# mypy
|
|
144
|
+
.mypy_cache/
|
|
145
|
+
.dmypy.json
|
|
146
|
+
dmypy.json
|
|
147
|
+
|
|
148
|
+
# Pyre type checker
|
|
149
|
+
.pyre/
|
|
150
|
+
|
|
151
|
+
# pytype static type analyzer
|
|
152
|
+
.pytype/
|
|
153
|
+
|
|
154
|
+
# Cython debug symbols
|
|
155
|
+
cython_debug/
|
|
156
|
+
|
|
157
|
+
# PyCharm
|
|
158
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
159
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
160
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
161
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
162
|
+
#.idea/
|
|
163
|
+
|
|
164
|
+
.DS_Store
|
|
165
|
+
.aider*
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"[python]": {
|
|
3
|
+
"editor.formatOnSave": true,
|
|
4
|
+
"editor.defaultFormatter": "charliermarsh.ruff",
|
|
5
|
+
},
|
|
6
|
+
"python.analysis.typeCheckingMode": "basic",
|
|
7
|
+
"python.analysis.diagnosticSeverityOverrides": {
|
|
8
|
+
"reportMissingTypeStubs": "none"
|
|
9
|
+
},
|
|
10
|
+
"files.trimTrailingWhitespace": true
|
|
11
|
+
}
|
alcove-0.1.1/CLAUDE.md
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
- After each change, run `make test-strict` to check project health (requires Docker)
|
|
2
|
+
- Install packages with `uv add <pkg>` or `uv add --dev <pkg>`
|
|
3
|
+
- Test Github CI runs cleanly with `make act`
|
|
4
|
+
- Avoid modifying the global Python environment or relying on globally installed packages
|
alcove-0.1.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Lars Yencken
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
alcove-0.1.1/MANIFEST.in
ADDED
alcove-0.1.1/Makefile
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
.PHONY: help unittest format lint typecheck test test-strict act act-dry
|
|
2
|
+
|
|
3
|
+
# Default target
|
|
4
|
+
help:
|
|
5
|
+
@echo "Available targets:"
|
|
6
|
+
@echo " make unittest - Run unittests with pytest"
|
|
7
|
+
@echo " make format - Reformat using ruff"
|
|
8
|
+
@echo " make lint - Lint using ruff"
|
|
9
|
+
@echo " make typecheck - Typecheck with pyright"
|
|
10
|
+
@echo " make test - Run lint, typecheck, and unittest sequentially"
|
|
11
|
+
@echo " make test-strict - Run tests requiring MinIO container (will fail if not available)"
|
|
12
|
+
@echo " make act - Run GitHub Actions locally with act"
|
|
13
|
+
|
|
14
|
+
# Check if .venv exists and is up to date
|
|
15
|
+
.venv: pyproject.toml
|
|
16
|
+
@echo "==> Installing packages"
|
|
17
|
+
@uv sync
|
|
18
|
+
@touch $@
|
|
19
|
+
|
|
20
|
+
# Run unittests with pytest
|
|
21
|
+
unittest: .venv
|
|
22
|
+
@echo "==> Running unit tests"
|
|
23
|
+
@uv run pytest --sw
|
|
24
|
+
|
|
25
|
+
# Reformat using rye
|
|
26
|
+
format: .venv
|
|
27
|
+
@echo "==> Formatting all files"
|
|
28
|
+
@uv run ruff format
|
|
29
|
+
@uv run ruff check --fix
|
|
30
|
+
|
|
31
|
+
# Lint using rye
|
|
32
|
+
lint: .venv
|
|
33
|
+
@echo "==> Linting all files"
|
|
34
|
+
@uv run ruff check
|
|
35
|
+
|
|
36
|
+
# Typecheck with pyright
|
|
37
|
+
typecheck: .venv
|
|
38
|
+
@echo "==> Typechecking"
|
|
39
|
+
@uv run pyright
|
|
40
|
+
|
|
41
|
+
# Run lint, typecheck, and unittest sequentially
|
|
42
|
+
test: lint typecheck unittest
|
|
43
|
+
|
|
44
|
+
# Run tests in strict mode - MinIO container is required
|
|
45
|
+
test-strict: lint typecheck
|
|
46
|
+
@echo "==> Detecting Docker context"
|
|
47
|
+
$(eval DOCKER_HOST := $(shell docker context inspect --format '{{.Endpoints.docker.Host}}'))
|
|
48
|
+
@echo "Using Docker context: $(DOCKER_HOST)"
|
|
49
|
+
@echo "==> Running unit tests with strict MinIO requirements"
|
|
50
|
+
@DOCKER_HOST=$(DOCKER_HOST) REQUIRE_MINIO=1 uv run pytest --sw
|
|
51
|
+
|
|
52
|
+
clean:
|
|
53
|
+
rm -rf data/* metadata/*
|
|
54
|
+
|
|
55
|
+
act:
|
|
56
|
+
@echo "==> Detecting Docker context"
|
|
57
|
+
$(eval DOCKER_HOST := $(shell docker context inspect --format '{{.Endpoints.docker.Host}}'))
|
|
58
|
+
@echo "Using Docker context: $(DOCKER_HOST)"
|
|
59
|
+
@echo "==> Running GitHub Actions workflow locally with act"
|
|
60
|
+
@DOCKER_HOST=$(DOCKER_HOST) act
|
|
61
|
+
|
|
62
|
+
build:
|
|
63
|
+
@echo "==> Building package"
|
|
64
|
+
@uv build
|
|
65
|
+
@uv run twine check dist/*
|
|
66
|
+
|
|
67
|
+
publish: build
|
|
68
|
+
@echo "==> Publishing to PyPI"
|
|
69
|
+
@uv run twine upload dist/*
|
alcove-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: alcove
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: An opinionated small-scale ETL framework for managing data files and directories in a content-addressable way.
|
|
5
|
+
Project-URL: Homepage, https://github.com/larsyencken/alcove
|
|
6
|
+
Project-URL: Repository, https://github.com/larsyencken/alcove
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/larsyencken/alcove/issues
|
|
8
|
+
Author-email: Lars Yencken <lars@yencken.org>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: content-addressable,data-engineering,data-lake,etl
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Requires-Dist: boto3>=1.34.145
|
|
19
|
+
Requires-Dist: duckdb>=1.0.0
|
|
20
|
+
Requires-Dist: jsonschema>=4.23.0
|
|
21
|
+
Requires-Dist: polars>=1.4.0
|
|
22
|
+
Requires-Dist: python-dotenv>=1.0.1
|
|
23
|
+
Requires-Dist: pyyaml>=6.0.1
|
|
24
|
+
Requires-Dist: rich>=13.7.1
|
|
25
|
+
Requires-Dist: ruff>=0.5.5
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# alcove
|
|
29
|
+
|
|
30
|
+
[](https://github.com/larsyencken/alcove/actions/workflows/ci.yml)
|
|
31
|
+
[](https://www.python.org/downloads/)
|
|
32
|
+
|
|
33
|
+
_A personal ETL and data lake._
|
|
34
|
+
|
|
35
|
+
Status: in alpha, changing often
|
|
36
|
+
|
|
37
|
+
## Overview
|
|
38
|
+
|
|
39
|
+
Alcove is an opinionated small-scale ETL framework for managing data files and directories in a content-addressable way.
|
|
40
|
+
|
|
41
|
+
## Core principles
|
|
42
|
+
|
|
43
|
+
- **A reusable framework.** Alcove provides a structured way of managing data files, scripts and their interdependencies that can be used across multiple projects.
|
|
44
|
+
- **First class metadata.** Every data file has an accompanying metadata sidecar that can be used to store provenance, licensing and other information.
|
|
45
|
+
- **Content addressed.** An `alcove` DAG is a Merkle tree of checksums that includes data, metadata and scripts, used to lazily rebuild only what is out of date.
|
|
46
|
+
- **Data versioning.** Every step in the DAG has a URI that includes a version, which can be an ISO date or `latest`, to encourage a reproducible workflow that still allows for change.
|
|
47
|
+
- **SQL support.** Alcove is a Python framework, but allows you to write steps in SQL which will be executed by DuckDB.
|
|
48
|
+
- **Parquet interchange.** All derived tables are generated as Parquet, which makes reuse easier.
|
|
49
|
+
|
|
50
|
+
## Usage
|
|
51
|
+
|
|
52
|
+
### Install the package
|
|
53
|
+
|
|
54
|
+
Start by installing the alcove package, either globally, or into an existing Python project.
|
|
55
|
+
|
|
56
|
+
`pip install git+https://github.com/larsyencken/alcove`
|
|
57
|
+
|
|
58
|
+
### Initialise an alcove
|
|
59
|
+
|
|
60
|
+
Enter the folder where you want to store your data and metadata, and run:
|
|
61
|
+
|
|
62
|
+
`alcove init`
|
|
63
|
+
|
|
64
|
+
This will create a `alcove.yaml` file, which will serve as the catalogue of all the data in your alcove.
|
|
65
|
+
|
|
66
|
+
### Configure object storage
|
|
67
|
+
|
|
68
|
+
You will need to configure your S3-compatible storage credentials in a `.env` file, in the same directory as your `alcove.yaml` file. Define:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
S3_ACCESS_KEY=your_application_key_id
|
|
72
|
+
S3_SECRET_KEY=your_application_key
|
|
73
|
+
S3_BUCKET_NAME=your_bucket_name
|
|
74
|
+
S3_ENDPOINT_URL=your_endpoint_url
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Now your alcove is ready to use.
|
|
78
|
+
|
|
79
|
+
### Adding a file or folder
|
|
80
|
+
|
|
81
|
+
From within your alcove folder, run `alcove snapshot path/to/your/file_or_folder dataset_name` to add a file to your alcove. See the earlier overview for choosing a dataset name.
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
alcove snapshot ~/Downloads/countries.csv countries/latest
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
This will upload the file to your S3-compatible storage, and create a metadata file at `data/<dataset_name>.meta.yaml` directory for you to complete.
|
|
88
|
+
|
|
89
|
+
The metadata format has some minimum fields, but is meant for you to extend as needed for your own purposes. Best practice would be to retain the provenance and licence information of any data you add to your alcove, especially if it originates from a third party.
|
|
90
|
+
|
|
91
|
+
### Creating a new table
|
|
92
|
+
|
|
93
|
+
To create a new table, use the `alcove new-table <table-path> [dep1 [dep2 [...]]` command. This command will create a placeholder executable script that generates an example data file of the given type based on the file extension (.parquet or .sql).
|
|
94
|
+
|
|
95
|
+
For example, to create a new table with a Parquet placeholder script:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
alcove new-table path/to/your/table
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
This will create a placeholder script that generates an example Parquet file with the following content:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
#!/usr/bin/env python3
|
|
105
|
+
import sys
|
|
106
|
+
import polars as pl
|
|
107
|
+
|
|
108
|
+
data = {
|
|
109
|
+
"a": [1, 1, 3],
|
|
110
|
+
"b": [2, 3, 5],
|
|
111
|
+
"c": [3, 4, 6]
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
df = pl.DataFrame(data)
|
|
115
|
+
|
|
116
|
+
output_file = sys.argv[-1]
|
|
117
|
+
df.write_parquet(output_file)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
For example, to create a new table with a SQL placeholder script:
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
alcove new-table path/to/your/table.sql
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
This will create a placeholder script that generates an example SQL file with the following content:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
-- SQL script to create a table
|
|
130
|
+
CREATE TABLE example_table AS
|
|
131
|
+
SELECT
|
|
132
|
+
1 AS a,
|
|
133
|
+
2 AS b,
|
|
134
|
+
3 AS c
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The command also supports the `--edit` option to open the metadata file for the table in your editor:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
alcove new-table path/to/your/table --edit
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Executing SQL step definitions
|
|
144
|
+
|
|
145
|
+
If a `.sql` step definition is detected, it will be executed using DuckDB with an in-memory database. The SQL file can use `{variable}` to interpolate template variables. The following template variables are available:
|
|
146
|
+
|
|
147
|
+
- `{output_file}`: The path to the output file.
|
|
148
|
+
- `{dependency}`: The path of each dependency, simplified to a semantic name.
|
|
149
|
+
|
|
150
|
+
### Building your alcove
|
|
151
|
+
|
|
152
|
+
Run `alcove run` to fetch any data that's out of date, and build any derived tables.
|
|
153
|
+
|
|
154
|
+
## Development
|
|
155
|
+
|
|
156
|
+
### Testing with MinIO
|
|
157
|
+
|
|
158
|
+
For testing with S3-compatible storage, this project uses automatically managed containers:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# Regular testing - continues even if MinIO isn't available
|
|
162
|
+
make test
|
|
163
|
+
|
|
164
|
+
# Strict testing - fails if MinIO container isn't available
|
|
165
|
+
make test-strict
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
The test environment provides two modes:
|
|
169
|
+
1. **Default mode**: Attempts to use MinIO container but won't fail if unavailable
|
|
170
|
+
2. **Strict mode**: Requires MinIO container, fails if Docker isn't running
|
|
171
|
+
|
|
172
|
+
### Docker Context Support
|
|
173
|
+
|
|
174
|
+
The testing framework automatically detects your current Docker context and uses it for container operations. This ensures tests work properly with:
|
|
175
|
+
- Docker Desktop
|
|
176
|
+
- Colima
|
|
177
|
+
- OrbStack
|
|
178
|
+
- Remote Docker contexts
|
|
179
|
+
|
|
180
|
+
### MinIO Configuration
|
|
181
|
+
|
|
182
|
+
With Docker, these credentials are automatically used:
|
|
183
|
+
- Access Key: minioadmin
|
|
184
|
+
- Secret Key: minioadmin
|
|
185
|
+
- Bucket: test-bucket
|
|
186
|
+
- Endpoint: http://localhost:9000
|
|
187
|
+
|
|
188
|
+
Containers are automatically managed and kept running between test runs for performance.
|
|
189
|
+
MinIO's health is verified before tests run to ensure proper S3 compatibility.
|
|
190
|
+
|
|
191
|
+
## Bugs
|
|
192
|
+
|
|
193
|
+
Please report any issues at: https://github.com/larsyencken/alcove/issues
|
|
194
|
+
|
|
195
|
+
## Changelog
|
|
196
|
+
|
|
197
|
+
- `0.1.1` (2025-04-25)
|
|
198
|
+
- Renamed project from "shelf" to "alcove"
|
|
199
|
+
- Added automated Docker container management for testing with MinIO
|
|
200
|
+
- Added two testing modes: standard and strict (requires Docker)
|
|
201
|
+
- Enhanced Docker context support for different environments (Docker Desktop, Colima, OrbStack)
|
|
202
|
+
- Improved S3-compatible storage testing reliability
|
|
203
|
+
- Fixed test fixtures to use consistent credentials
|
|
204
|
+
|
|
205
|
+
- `0.1.0` (Initial release)
|
|
206
|
+
- Initialise a repo with `alcove.yaml`
|
|
207
|
+
- `alcove snapshot` and `alcove run` with file and directory support
|
|
208
|
+
- Only fetch things that are out of date
|
|
209
|
+
- `alcove list` to see what datasets are available
|
|
210
|
+
- `alcove audit` to ensure your alcove is coherent and correct
|
|
211
|
+
- `alcove db` to enter an interactive DuckDB shell with all your data
|