duckpd 0.0.2__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 (57) hide show
  1. duckpd-0.0.2/.github/workflows/ci.yml +27 -0
  2. duckpd-0.0.2/.gitignore +229 -0
  3. duckpd-0.0.2/.pre-commit-config.yaml +23 -0
  4. duckpd-0.0.2/.python-version +1 -0
  5. duckpd-0.0.2/CONTRIBUTING.md +37 -0
  6. duckpd-0.0.2/LICENSE +21 -0
  7. duckpd-0.0.2/Makefile +49 -0
  8. duckpd-0.0.2/PKG-INFO +139 -0
  9. duckpd-0.0.2/README.md +90 -0
  10. duckpd-0.0.2/demo/DuckPD_Quickstart.ipynb +1459 -0
  11. duckpd-0.0.2/demo/README.md +61 -0
  12. duckpd-0.0.2/demo/__init__.py +1 -0
  13. duckpd-0.0.2/demo/basic_pipeline.py +38 -0
  14. duckpd-0.0.2/demo/generate_market_data.py +223 -0
  15. duckpd-0.0.2/demo/language_summary.parquet +0 -0
  16. duckpd-0.0.2/demo/market_data_demo.py +245 -0
  17. duckpd-0.0.2/demo/parquet_pipeline.py +48 -0
  18. duckpd-0.0.2/demo/reduction_pipeline.py +55 -0
  19. duckpd-0.0.2/docs/BENCHMARK.md +149 -0
  20. duckpd-0.0.2/docs/CHANGELOG.md +31 -0
  21. duckpd-0.0.2/docs/README.md +37 -0
  22. duckpd-0.0.2/docs/RELEASES.md +58 -0
  23. duckpd-0.0.2/docs/decisions/0001-core-contract.md +37 -0
  24. duckpd-0.0.2/docs/design/early-ideation.md +703 -0
  25. duckpd-0.0.2/docs/references/competitive-landscape.md +252 -0
  26. duckpd-0.0.2/docs/roadmap.md +797 -0
  27. duckpd-0.0.2/pyproject.toml +85 -0
  28. duckpd-0.0.2/src/duckpd/__init__.py +23 -0
  29. duckpd-0.0.2/src/duckpd/_compiler.py +464 -0
  30. duckpd-0.0.2/src/duckpd/_executor.py +153 -0
  31. duckpd-0.0.2/src/duckpd/_logical.py +387 -0
  32. duckpd-0.0.2/src/duckpd/_merging.py +235 -0
  33. duckpd-0.0.2/src/duckpd/_metadata.py +212 -0
  34. duckpd-0.0.2/src/duckpd/_quoting.py +6 -0
  35. duckpd-0.0.2/src/duckpd/_reductions.py +146 -0
  36. duckpd-0.0.2/src/duckpd/_typing.py +56 -0
  37. duckpd-0.0.2/src/duckpd/accessors.py +122 -0
  38. duckpd-0.0.2/src/duckpd/errors.py +29 -0
  39. duckpd-0.0.2/src/duckpd/frame.py +566 -0
  40. duckpd-0.0.2/src/duckpd/groupby.py +206 -0
  41. duckpd-0.0.2/src/duckpd/io.py +60 -0
  42. duckpd-0.0.2/src/duckpd/py.typed +1 -0
  43. duckpd-0.0.2/src/duckpd/series.py +264 -0
  44. duckpd-0.0.2/src/duckpd/session.py +254 -0
  45. duckpd-0.0.2/tests/test_accessors.py +205 -0
  46. duckpd-0.0.2/tests/test_benchmark_demo.py +42 -0
  47. duckpd-0.0.2/tests/test_execution_limits.py +87 -0
  48. duckpd-0.0.2/tests/test_frame_operations.py +216 -0
  49. duckpd-0.0.2/tests/test_groupby.py +187 -0
  50. duckpd-0.0.2/tests/test_market_data_demo.py +64 -0
  51. duckpd-0.0.2/tests/test_merging.py +173 -0
  52. duckpd-0.0.2/tests/test_metadata.py +192 -0
  53. duckpd-0.0.2/tests/test_package.py +7 -0
  54. duckpd-0.0.2/tests/test_reduction_demo.py +19 -0
  55. duckpd-0.0.2/tests/test_reductions.py +217 -0
  56. duckpd-0.0.2/tests/test_sources.py +141 -0
  57. duckpd-0.0.2/uv.lock +933 -0
@@ -0,0 +1,27 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ${{ matrix.os }}
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ os: [ubuntu-latest, macos-latest, windows-latest]
14
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v5
18
+ - uses: astral-sh/setup-uv@v6
19
+ with:
20
+ enable-cache: true
21
+ python-version: ${{ matrix.python-version }}
22
+ - run: uv sync --frozen --group dev
23
+ - run: uv run pytest
24
+ - run: uv run ruff check .
25
+ - run: uv run ruff format --check .
26
+ - run: uv run pyright
27
+ - run: uv build
@@ -0,0 +1,229 @@
1
+ .venv/
2
+ .pytest_cache/
3
+ .ruff_cache/
4
+ .coverage
5
+ __pycache__/
6
+ *.py[cod]
7
+ build/
8
+ dist/
9
+ *.egg-info/
10
+ *.duckdb.tmp/
11
+ demo/data/
12
+ # Byte-compiled / optimized / DLL files
13
+ __pycache__/
14
+ *.py[codz]
15
+ *$py.class
16
+
17
+ # C extensions
18
+ *.so
19
+
20
+ # Distribution / packaging
21
+ .Python
22
+ build/
23
+ develop-eggs/
24
+ dist/
25
+ downloads/
26
+ eggs/
27
+ .eggs/
28
+ lib/
29
+ lib64/
30
+ parts/
31
+ sdist/
32
+ var/
33
+ wheels/
34
+ share/python-wheels/
35
+ *.egg-info/
36
+ .installed.cfg
37
+ *.egg
38
+ MANIFEST
39
+
40
+ # PyInstaller
41
+ # Usually these files are written by a python script from a template
42
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
43
+ *.manifest
44
+ *.spec
45
+
46
+ # Installer logs
47
+ pip-log.txt
48
+ pip-delete-this-directory.txt
49
+
50
+ # Unit test / coverage reports
51
+ htmlcov/
52
+ .tox/
53
+ .nox/
54
+ .coverage
55
+ .coverage.*
56
+ .cache
57
+ nosetests.xml
58
+ coverage.xml
59
+ *.cover
60
+ *.py.cover
61
+ .hypothesis/
62
+ .pytest_cache/
63
+ cover/
64
+
65
+ # Translations
66
+ *.mo
67
+ *.pot
68
+
69
+ # Django stuff:
70
+ *.log
71
+ local_settings.py
72
+ db.sqlite3
73
+ db.sqlite3-journal
74
+
75
+ # Flask stuff:
76
+ instance/
77
+ .webassets-cache
78
+
79
+ # Scrapy stuff:
80
+ .scrapy
81
+
82
+ # Sphinx documentation
83
+ docs/_build/
84
+
85
+ # PyBuilder
86
+ .pybuilder/
87
+ target/
88
+
89
+ # Jupyter Notebook
90
+ .ipynb_checkpoints
91
+
92
+ # IPython
93
+ profile_default/
94
+ ipython_config.py
95
+
96
+ # pyenv
97
+ # For a library or package, you might want to ignore these files since the code is
98
+ # intended to run in multiple environments; otherwise, check them in:
99
+ # .python-version
100
+
101
+ # pipenv
102
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
103
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
104
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
105
+ # install all needed dependencies.
106
+ # Pipfile.lock
107
+
108
+ # UV
109
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
110
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
111
+ # commonly ignored for libraries.
112
+ # uv.lock
113
+
114
+ # poetry
115
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
116
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
117
+ # commonly ignored for libraries.
118
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
119
+ # poetry.lock
120
+ # poetry.toml
121
+
122
+ # pdm
123
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
124
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
125
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
126
+ # pdm.lock
127
+ # pdm.toml
128
+ .pdm-python
129
+ .pdm-build/
130
+
131
+ # pixi
132
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
133
+ # pixi.lock
134
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
135
+ # in the .venv directory. It is recommended not to include this directory in version control.
136
+ .pixi
137
+
138
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
139
+ __pypackages__/
140
+
141
+ # Celery stuff
142
+ celerybeat-schedule
143
+ celerybeat.pid
144
+
145
+ # Redis
146
+ *.rdb
147
+ *.aof
148
+ *.pid
149
+
150
+ # RabbitMQ
151
+ mnesia/
152
+ rabbitmq/
153
+ rabbitmq-data/
154
+
155
+ # ActiveMQ
156
+ activemq-data/
157
+
158
+ # SageMath parsed files
159
+ *.sage.py
160
+
161
+ # Environments
162
+ .env
163
+ .envrc
164
+ .venv
165
+ env/
166
+ venv/
167
+ ENV/
168
+ env.bak/
169
+ venv.bak/
170
+
171
+ # Spyder project settings
172
+ .spyderproject
173
+ .spyproject
174
+
175
+ # Rope project settings
176
+ .ropeproject
177
+
178
+ # mkdocs documentation
179
+ /site
180
+
181
+ # mypy
182
+ .mypy_cache/
183
+ .dmypy.json
184
+ dmypy.json
185
+
186
+ # Pyre type checker
187
+ .pyre/
188
+
189
+ # pytype static type analyzer
190
+ .pytype/
191
+
192
+ # Cython debug symbols
193
+ cython_debug/
194
+
195
+ # PyCharm
196
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
197
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
198
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
199
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
200
+ # .idea/
201
+
202
+ # Abstra
203
+ # Abstra is an AI-powered process automation framework.
204
+ # Ignore directories containing user credentials, local state, and settings.
205
+ # Learn more at https://abstra.io/docs
206
+ .abstra/
207
+
208
+ # Visual Studio Code
209
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
210
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
211
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
212
+ # you could uncomment the following to ignore the entire vscode folder
213
+ # .vscode/
214
+ # Temporary file for partial code execution
215
+ tempCodeRunnerFile.py
216
+
217
+ # Ruff stuff:
218
+ .ruff_cache/
219
+
220
+ # PyPI configuration file
221
+ .pypirc
222
+
223
+ # Marimo
224
+ marimo/_static/
225
+ marimo/_lsp/
226
+ __marimo__/
227
+
228
+ # Streamlit
229
+ .streamlit/secrets.toml
@@ -0,0 +1,23 @@
1
+ repos:
2
+ - repo: local
3
+ hooks:
4
+ - id: ruff
5
+ name: ruff
6
+ entry: uv run ruff check .
7
+ language: system
8
+ pass_filenames: false
9
+ - id: ruff-format
10
+ name: ruff-format
11
+ entry: uv run ruff format --check .
12
+ language: system
13
+ pass_filenames: false
14
+ - id: pyright
15
+ name: pyright
16
+ entry: uv run pyright
17
+ language: system
18
+ pass_filenames: false
19
+ - id: pytest
20
+ name: pytest
21
+ entry: uv run pytest
22
+ language: system
23
+ pass_filenames: false
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,37 @@
1
+ # Contributing
2
+
3
+ DuckPD uses Python 3.11+, `uv`, pytest, Ruff, and Pyright.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ uv sync --frozen --group dev
9
+ uv run pre-commit install
10
+ ```
11
+
12
+ ## Checks
13
+
14
+ Run focused tests while developing, then run the complete gate before opening a
15
+ pull request:
16
+
17
+ ```bash
18
+ make check
19
+ make build
20
+ ```
21
+
22
+ The equivalent commands, useful on systems without GNU Make, are:
23
+
24
+ ```bash
25
+ uv run pytest
26
+ uv run ruff check .
27
+ uv run ruff format --check .
28
+ uv run pyright
29
+ uv build
30
+ ```
31
+
32
+ Every public operation must remain lazy until an explicit execution boundary,
33
+ update frame metadata, reject unsupported arguments before execution, and have
34
+ differential tests against the supported pandas behavior.
35
+
36
+ Do not add an automatic pandas fallback. Unsupported behavior should raise a
37
+ specific exception.
duckpd-0.0.2/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 QuantBert
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.
duckpd-0.0.2/Makefile ADDED
@@ -0,0 +1,49 @@
1
+ .DEFAULT_GOAL := help
2
+
3
+ .PHONY: help install test lint format format-check typecheck check build demos-smoke release-check clean publish
4
+
5
+ help: ## Show available targets
6
+ @grep -E '^[a-z-]+:.*##' $(MAKEFILE_LIST) | awk -F ':.*## ' '{printf " %-20s %s\n", $$1, $$2}'
7
+
8
+ install: ## Sync the locked development environment
9
+ uv sync --frozen --group dev
10
+
11
+ test: ## Run tests with the configured coverage requirements
12
+ uv run pytest
13
+
14
+ lint: ## Run Ruff lint checks
15
+ uv run ruff check .
16
+
17
+ format: ## Format the repository with Ruff
18
+ uv run ruff format .
19
+
20
+ format-check: ## Verify Ruff formatting without changing files
21
+ uv run ruff format --check .
22
+
23
+ typecheck: ## Run strict Pyright checks
24
+ uv run pyright
25
+
26
+ check: lint format-check typecheck test ## Run the complete local quality gate
27
+
28
+ build: ## Build the wheel and source distribution
29
+ rm -rf dist
30
+ uv build
31
+
32
+ demos-smoke: ## Run the inexpensive executable demos
33
+ uv run python demo/basic_pipeline.py
34
+ uv run python demo/parquet_pipeline.py
35
+ uv run python demo/reduction_pipeline.py
36
+ uv run python demo/generate_market_data.py smoke
37
+
38
+ release-check: check build ## Validate source and build release artifacts
39
+
40
+ publish: test ## Run tests, bump patch version, build, and publish to PyPI
41
+ uv version --bump patch
42
+ rm -rf dist
43
+ uv build
44
+ uv publish
45
+
46
+ clean: ## Remove caches, coverage data, and build artifacts
47
+ rm -rf .pytest_cache .ruff_cache .hypothesis htmlcov build dist
48
+ rm -f .coverage coverage.xml
49
+ find . -type d \( -path './.git' -o -path './.venv' \) -prune -o -type d -name __pycache__ -exec rm -rf {} +
duckpd-0.0.2/PKG-INFO ADDED
@@ -0,0 +1,139 @@
1
+ Metadata-Version: 2.5
2
+ Name: duckpd
3
+ Version: 0.0.2
4
+ Summary: A lazy pandas-shaped DataFrame powered by DuckDB
5
+ Project-URL: Homepage, https://github.com/quantbert/duckpd
6
+ Project-URL: Repository, https://github.com/quantbert/duckpd
7
+ Project-URL: Issues, https://github.com/quantbert/duckpd/issues
8
+ Project-URL: Changelog, https://github.com/quantbert/duckpd/blob/main/docs/CHANGELOG.md
9
+ Author: QuantBert
10
+ License: MIT License
11
+
12
+ Copyright (c) 2026 QuantBert
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+ License-File: LICENSE
32
+ Classifier: Development Status :: 2 - Pre-Alpha
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: Intended Audience :: Science/Research
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Programming Language :: Python :: 3
37
+ Classifier: Programming Language :: Python :: 3.11
38
+ Classifier: Programming Language :: Python :: 3.12
39
+ Classifier: Programming Language :: Python :: 3.13
40
+ Classifier: Programming Language :: Python :: 3.14
41
+ Classifier: Topic :: Database
42
+ Classifier: Topic :: Scientific/Engineering
43
+ Classifier: Typing :: Typed
44
+ Requires-Python: >=3.11
45
+ Requires-Dist: duckdb<1.6,>=1.5
46
+ Requires-Dist: pandas<3.1,>=3.0
47
+ Requires-Dist: pyarrow>=18
48
+ Description-Content-Type: text/markdown
49
+
50
+ # duckpd
51
+
52
+ DuckPD is an experimental lazy DataFrame library with a pandas-shaped frontend
53
+ and DuckDB as its execution engine.
54
+
55
+ > [!WARNING]
56
+ > **DuckPD is a work in progress and is not yet recommended for
57
+ > production-critical workloads.** The API and supported pandas semantics may
58
+ > change between `0.x` releases, and many pandas operations are intentionally
59
+ > unsupported. Validate results and resource behavior for each intended
60
+ > workload before adopting it.
61
+
62
+ DuckPD intentionally supports a small, explicit subset of pandas rather than
63
+ silently falling back to materializing a complete pandas DataFrame. See the
64
+ [release policy](docs/RELEASES.md) for the pre-`1.0` stability policy.
65
+
66
+ ## Current capabilities
67
+
68
+ - Lazy pandas, Arrow, Parquet, DuckDB table, and read-only SQL sources.
69
+ - Column selection, boolean filtering, arithmetic expressions, `assign`,
70
+ `sort_values`, and `limit`.
71
+ - Eager DataFrame and Series `count`, `size`, `sum`, `mean`, `min`, and `max`
72
+ reductions over numeric and boolean data, including `skipna`, `min_count`,
73
+ and DataFrame `numeric_only` support.
74
+ - Explicit lazy indexes with `set_index()`/`reset_index()` and source
75
+ `index=`/`order_by=` declarations.
76
+ - Explicit pandas collection, bounded `head`, Arrow tables and record batches,
77
+ physical plan inspection, and direct Parquet writes.
78
+ - Session-level memory, spill-directory, temporary-size, and thread settings.
79
+ - Rejection of ambiguous cross-frame alignment and mutating SQL.
80
+
81
+ ## Example
82
+
83
+ ```python
84
+ import duckpd as pd
85
+
86
+ orders = pd.read_parquet("orders/*.parquet")
87
+
88
+ result = (
89
+ orders[orders["status"] == "paid"]
90
+ .assign(net=lambda frame: frame["amount"] - frame["refund_amount"])
91
+ .sort_values("net", ascending=False)[["order_id", "net"]]
92
+ .limit(100)
93
+ )
94
+
95
+ print(result.explain())
96
+ preview = result.head(10)
97
+ result.write_parquet("largest-paid-orders.parquet")
98
+ pandas_result = result.collect()
99
+ ```
100
+
101
+ Transformations above are lazy. `explain()`, `head()`, `collect()`, Arrow output,
102
+ and file output are explicit execution boundaries. `limit()` stays lazy while
103
+ `head()` returns a bounded pandas preview.
104
+
105
+ ## Demos
106
+
107
+ Small runnable programs are available in [demo/](demo/README.md):
108
+
109
+ ```bash
110
+ uv run python demo/basic_pipeline.py
111
+ uv run python demo/parquet_pipeline.py
112
+ uv run python demo/reduction_pipeline.py
113
+ uv run python demo/generate_market_data.py
114
+ uv run python demo/market_data_demo.py
115
+ ```
116
+
117
+ See the [benchmark results](docs/BENCHMARK.md) for performance and memory
118
+ comparisons between DuckPD and pandas across 100 MB, 1 GB, and 5 GB datasets.
119
+
120
+ ## Development
121
+
122
+ ```bash
123
+ uv sync --frozen --group dev
124
+ make check
125
+ make build
126
+ ```
127
+
128
+ GNU Make is optional. The equivalent commands are:
129
+
130
+ ```bash
131
+ uv run pytest
132
+ uv run ruff check .
133
+ uv run ruff format --check .
134
+ uv run pyright
135
+ uv build
136
+ ```
137
+
138
+ See the [documentation index](docs/README.md) for the implementation roadmap,
139
+ architecture decisions, benchmarks, research, and changelog.
duckpd-0.0.2/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # duckpd
2
+
3
+ DuckPD is an experimental lazy DataFrame library with a pandas-shaped frontend
4
+ and DuckDB as its execution engine.
5
+
6
+ > [!WARNING]
7
+ > **DuckPD is a work in progress and is not yet recommended for
8
+ > production-critical workloads.** The API and supported pandas semantics may
9
+ > change between `0.x` releases, and many pandas operations are intentionally
10
+ > unsupported. Validate results and resource behavior for each intended
11
+ > workload before adopting it.
12
+
13
+ DuckPD intentionally supports a small, explicit subset of pandas rather than
14
+ silently falling back to materializing a complete pandas DataFrame. See the
15
+ [release policy](docs/RELEASES.md) for the pre-`1.0` stability policy.
16
+
17
+ ## Current capabilities
18
+
19
+ - Lazy pandas, Arrow, Parquet, DuckDB table, and read-only SQL sources.
20
+ - Column selection, boolean filtering, arithmetic expressions, `assign`,
21
+ `sort_values`, and `limit`.
22
+ - Eager DataFrame and Series `count`, `size`, `sum`, `mean`, `min`, and `max`
23
+ reductions over numeric and boolean data, including `skipna`, `min_count`,
24
+ and DataFrame `numeric_only` support.
25
+ - Explicit lazy indexes with `set_index()`/`reset_index()` and source
26
+ `index=`/`order_by=` declarations.
27
+ - Explicit pandas collection, bounded `head`, Arrow tables and record batches,
28
+ physical plan inspection, and direct Parquet writes.
29
+ - Session-level memory, spill-directory, temporary-size, and thread settings.
30
+ - Rejection of ambiguous cross-frame alignment and mutating SQL.
31
+
32
+ ## Example
33
+
34
+ ```python
35
+ import duckpd as pd
36
+
37
+ orders = pd.read_parquet("orders/*.parquet")
38
+
39
+ result = (
40
+ orders[orders["status"] == "paid"]
41
+ .assign(net=lambda frame: frame["amount"] - frame["refund_amount"])
42
+ .sort_values("net", ascending=False)[["order_id", "net"]]
43
+ .limit(100)
44
+ )
45
+
46
+ print(result.explain())
47
+ preview = result.head(10)
48
+ result.write_parquet("largest-paid-orders.parquet")
49
+ pandas_result = result.collect()
50
+ ```
51
+
52
+ Transformations above are lazy. `explain()`, `head()`, `collect()`, Arrow output,
53
+ and file output are explicit execution boundaries. `limit()` stays lazy while
54
+ `head()` returns a bounded pandas preview.
55
+
56
+ ## Demos
57
+
58
+ Small runnable programs are available in [demo/](demo/README.md):
59
+
60
+ ```bash
61
+ uv run python demo/basic_pipeline.py
62
+ uv run python demo/parquet_pipeline.py
63
+ uv run python demo/reduction_pipeline.py
64
+ uv run python demo/generate_market_data.py
65
+ uv run python demo/market_data_demo.py
66
+ ```
67
+
68
+ See the [benchmark results](docs/BENCHMARK.md) for performance and memory
69
+ comparisons between DuckPD and pandas across 100 MB, 1 GB, and 5 GB datasets.
70
+
71
+ ## Development
72
+
73
+ ```bash
74
+ uv sync --frozen --group dev
75
+ make check
76
+ make build
77
+ ```
78
+
79
+ GNU Make is optional. The equivalent commands are:
80
+
81
+ ```bash
82
+ uv run pytest
83
+ uv run ruff check .
84
+ uv run ruff format --check .
85
+ uv run pyright
86
+ uv build
87
+ ```
88
+
89
+ See the [documentation index](docs/README.md) for the implementation roadmap,
90
+ architecture decisions, benchmarks, research, and changelog.