Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
ecd0c87
explicitly import importlib.util; remove erroneous print
Oct 28, 2025
50c802b
Fix ADBC driver path resolution when `importlib.util` was not implici…
evertlammerts Oct 28, 2025
e825f82
bumped submodule
evertlammerts Oct 31, 2025
ec3264b
add targeted test workflow
evertlammerts Oct 30, 2025
d8d7832
add targeted test workflow (#145)
evertlammerts Oct 31, 2025
fdef1fc
Remove xfail annotations on adbc tests
evertlammerts Oct 31, 2025
135f09c
Remove xfail annotations on adbc tests (#147)
evertlammerts Oct 31, 2025
0304a87
fix config dict value typehint
evertlammerts Oct 31, 2025
66abe60
fix config dict value typehint (#151)
evertlammerts Oct 31, 2025
e991b2a
Add df data and tz type columns back into the same loc after type con…
evertlammerts Oct 31, 2025
fd1c34f
Add df data and tz type columns back into the same loc after type con…
evertlammerts Oct 31, 2025
83aa04a
Enable pyarrow with python 3.14
evertlammerts Oct 31, 2025
6e95472
Enable pyarrow with python 3.14 (#152)
evertlammerts Nov 1, 2025
4838232
use macos-15-intel now that macos-13 is closing down
evertlammerts Nov 1, 2025
07c1414
release s3 upload fix
evertlammerts Nov 1, 2025
c04f9b8
spark imports
evertlammerts Nov 4, 2025
353566b
spark imports (#157)
evertlammerts Nov 4, 2025
02ceac1
Bumped submodule
evertlammerts Nov 5, 2025
c14473e
Fix failing test due to changed error msg
evertlammerts Nov 5, 2025
538c10a
Fix failing test due to changed error msg (#158)
evertlammerts Nov 5, 2025
e35a2ce
mypy shouldn't check experimental.spark
evertlammerts Nov 5, 2025
17a0cad
remove experimental import because of the transitive dependencies tha…
evertlammerts Nov 5, 2025
f5618a3
Bumped submodule
evertlammerts Nov 7, 2025
f3b8c8a
Bumped submodule
evertlammerts Nov 7, 2025
95a9968
Fix InsertRelation on attached database
evertlammerts Nov 1, 2025
10e0ef3
Add explicit polars overloads
J-Meyers Nov 9, 2025
20bfd52
review feedback
evertlammerts Nov 6, 2025
7ccc8e9
Add explicit .pl(lazy=True) overload (#172)
evertlammerts Nov 10, 2025
13827e7
Fix InsertRelation on attached database (#155)
evertlammerts Nov 10, 2025
70380a1
Submodule at 68d7555 for 1.4.2 release
evertlammerts Nov 11, 2025
30e53c4
Fix project metadata
evertlammerts Nov 12, 2025
5442569
Fix project metadata (#174)
evertlammerts Nov 12, 2025
4746ac8
Create a PR to bump submodule if nightly is stale
evertlammerts Nov 5, 2025
8b104c0
Create a PR to bump submodule if nightly is stale (#159)
evertlammerts Nov 19, 2025
96762c1
Bump submodule
duckdblabs-bot Nov 19, 2025
b7973e8
[duckdb-labs bot] Bump DuckDB submodule (#185)
evertlammerts Nov 19, 2025
8f1aa4b
Bump submodule
duckdblabs-bot Nov 20, 2025
51d7260
[duckdb-labs bot] Bump DuckDB submodule (#186)
evertlammerts Nov 20, 2025
c7ed4f6
Bump submodule
duckdblabs-bot Nov 21, 2025
1dcc1c5
[duckdb-labs bot] Bump DuckDB submodule (#188)
evertlammerts Nov 21, 2025
4460b32
don't fail if the submodule is at the same commit as the input
evertlammerts Nov 24, 2025
c542c18
Bump submodule
duckdblabs-bot Nov 26, 2025
b9f4571
[duckdb-labs bot] Bump DuckDB submodule (#191)
evertlammerts Nov 26, 2025
d1a4643
Bump submodule
duckdblabs-bot Nov 29, 2025
f6b01c8
[duckdb-labs bot] Bump DuckDB submodule (#197)
evertlammerts Nov 29, 2025
9ec8614
Bump submodule
duckdblabs-bot Nov 30, 2025
f053a52
[duckdb-labs bot] Bump DuckDB submodule (#198)
evertlammerts Nov 30, 2025
f39e010
Bump submodule
duckdblabs-bot Dec 2, 2025
8944767
[duckdb-labs bot] Bump DuckDB submodule (#202)
evertlammerts Dec 2, 2025
8ab292c
Add filename_pattern to to_parquet Python API
matthew-bayer Dec 1, 2025
5cb2afb
Fix linting and test
evertlammerts Dec 2, 2025
f118972
Bump submodule
duckdblabs-bot Dec 3, 2025
7a0a181
Add filename_pattern to to_parquet Python API (#201)
evertlammerts Dec 3, 2025
b82d1a5
[duckdb-labs bot] Bump DuckDB submodule (#203)
evertlammerts Dec 3, 2025
112a6a2
Bump submodule
duckdblabs-bot Dec 4, 2025
1d29607
[duckdb-labs bot] Bump DuckDB submodule (#206)
evertlammerts Dec 4, 2025
28a6d22
Bump submodule
duckdblabs-bot Dec 5, 2025
6dfc1af
[duckdb-labs bot] Bump DuckDB submodule (#207)
evertlammerts Dec 5, 2025
b3ef82c
add windows arm64 build
evertlammerts Dec 1, 2025
a2a798a
Fix Windows ARM64 excludes in workflow
evertlammerts Dec 5, 2025
a76d96a
Bump submodule
duckdblabs-bot Dec 6, 2025
70accd9
[duckdb-labs bot] Bump DuckDB submodule (#212)
evertlammerts Dec 6, 2025
3c67754
Merge branch 'v1.4-andium' into windows_arm64
evertlammerts Dec 6, 2025
f2b5da9
add windows arm64 build (#211)
evertlammerts Dec 6, 2025
4191d25
Merge remote-tracking branch 'upstream/v1.4-andium'
evertlammerts Dec 6, 2025
c5d6dc0
fix main builds
evertlammerts Dec 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/packaging_wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ jobs:
python: [ cp39, cp310, cp311, cp312, cp313, cp314 ]
platform:
- { os: windows-2025, arch: amd64, cibw_system: win }
- { os: windows-11-arm, arch: ARM64, cibw_system: win } # cibw requires ARM64 to be uppercase
- { os: ubuntu-24.04, arch: x86_64, cibw_system: manylinux }
- { os: ubuntu-24.04-arm, arch: aarch64, cibw_system: manylinux }
- { os: macos-15, arch: arm64, cibw_system: macosx }
- { os: macos-15, arch: universal2, cibw_system: macosx }
- { os: macos-13, arch: x86_64, cibw_system: macosx }
- { os: macos-15-intel, arch: x86_64, cibw_system: macosx }
minimal:
- ${{ inputs.minimal }}
exclude:
Expand All @@ -46,6 +47,8 @@ jobs:
- { minimal: true, python: cp312 }
- { minimal: true, python: cp313 }
- { minimal: true, platform: { arch: universal2 } }
- { python: cp39, platform: { os: windows-11-arm, arch: ARM64 } } # too many dependency problems for win arm64
- { python: cp310, platform: { os: windows-11-arm, arch: ARM64 } } # too many dependency problems for win arm64
runs-on: ${{ matrix.platform.os }}
env:
### cibuildwheel configuration
Expand Down
61 changes: 45 additions & 16 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ on:
options:
- test
- prod
nightly-stale-after-days:
type: string
description: After how many days should nightlies be considered stale
required: true
default: 3
store-s3:
type: boolean
description: Also store test packages in S3 (always true for prod)
Expand All @@ -41,6 +46,17 @@ jobs:
duckdb-sha: ${{ inputs.duckdb-sha }}
set-version: ${{ inputs.stable-version }}

submodule_pr:
name: Create or update PR to bump submodule to given SHA
needs: build_sdist
uses: ./.github/workflows/submodule_auto_pr.yml
with:
duckdb-python-sha: ${{ inputs.duckdb-python-sha }}
duckdb-sha: ${{ inputs.duckdb-sha }}
secrets:
# reusable workflows and secrets are not great: https://github.com/actions/runner/issues/3206
DUCKDBLABS_BOT_TOKEN: ${{ secrets.DUCKDBLABS_BOT_TOKEN }}

workflow_state:
name: Set state for the release workflow
needs: build_sdist
Expand All @@ -51,23 +67,36 @@ jobs:
runs-on: ubuntu-latest
steps:
- id: index_check
name: Check ${{ needs.build_sdist.outputs.package-version }} on PyPI
name: Check version on PyPI
run: |
set -eu
# Check PyPI whether the release we're building is already present
set -ex
pypi_hostname=${{ inputs.pypi-index == 'test' && 'test.' || '' }}pypi.org
pkg_version=${{ needs.build_sdist.outputs.package-version }}
url=https://${pypi_hostname}/pypi/duckdb/${pkg_version}/json
http_status=$( curl -s -o /dev/null -w "%{http_code}" $url || echo $? )
if [[ $http_status == "200" ]]; then
echo "::warning::Package version ${pkg_version} is already present on ${pypi_hostname}"
pypi_state=VERSION_FOUND
elif [[ $http_status == 000* ]]; then
echo "::error::Error checking PyPI at ${url}: curl exit code ${http_status#'000'}"
pypi_state=UNKNOWN
else
echo "::notice::Package version ${pkg_version} not found on ${pypi_hostname} (http status: ${http_status})"
# install duckdb
curl https://install.duckdb.org | sh
# query pypi
result=$(cat <<EOF | ${HOME}/.duckdb/cli/latest/duckdb | xargs
---- Output lines
.mode line
---- Query that fetches the given version's age, if the version already exists
SELECT
today() - (file.value->>'upload_time_iso_8601')::DATE AS age,
FROM read_json('https://${pypi_hostname}/pypi/duckdb/json') AS jd
CROSS JOIN json_each(jd.releases) AS rel(key, value)
CROSS JOIN unnest(FROM_JSON(rel.value, '["JSON"]')) AS file(value)
WHERE rel.key='${{ needs.build_sdist.outputs.package-version }}'
LIMIT 1;
EOF
)
if [ -z "$result" ]; then
pypi_state=VERSION_NOT_FOUND
else
pypi_state=VERSION_FOUND
fi
if [[ -z "${{ inputs.stable-version }}" ]]; then
age=${result#age = }
if [ "${age}" -ge "${{ inputs.nightly-stale-after-days }}" ]; then
echo "::warning title=Stale nightly for ${{ github.ref_name }}::Nightly is ${age} days old (max=${{ inputs.nightly-stale-after-days }})"
fi
fi
echo "pypi_state=${pypi_state}" >> $GITHUB_OUTPUT

Expand Down Expand Up @@ -96,7 +125,7 @@ jobs:
echo "::notice::S3 upload disabled in inputs, not generating S3 URL"
exit 0
fi
if [[ VERSION_FOUND == "${{ steps.index_check.outputs.pypi_state }}" ]]; then
if [[ VERSION_NOT_FOUND != "${{ steps.index_check.outputs.pypi_state }}" ]]; then
echo "::warning::S3 upload disabled because package version already uploaded to PyPI"
exit 0
fi
Expand All @@ -110,7 +139,7 @@ jobs:
build_wheels:
name: Build and test releases
needs: workflow_state
if: ${{ needs.workflow_state.outputs.pypi_state != 'VERSION_FOUND' }}
if: ${{ needs.workflow_state.outputs.pypi_state == 'VERSION_NOT_FOUND' }}
uses: ./.github/workflows/packaging_wheels.yml
with:
minimal: false
Expand Down
130 changes: 130 additions & 0 deletions .github/workflows/submodule_auto_pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
name: Submodule Auto PR
on:
workflow_call:
inputs:
duckdb-python-sha:
type: string
description: The commit to build against (defaults to latest commit of current ref)
required: false
duckdb-sha:
type: string
description: The DuckDB submodule commit or ref to build against
required: true
auto-land:
type: boolean
description: Immediately merge the PR (placeholder - doesn't work)
default: false
secrets:
DUCKDBLABS_BOT_TOKEN:
description: Github token of the DuckDBLabs bot
required: true

defaults:
run:
shell: bash

jobs:
create_pr:
name: Create PR to bump duckdb submodule to given SHA
runs-on: ubuntu-latest
steps:
- name: Checkout DuckDB Python
uses: actions/checkout@v4
with:
ref: ${{ inputs.duckdb-python-sha }}
fetch-depth: 0
submodules: true

- name: Checkout or Create Needed Branch
run: |
git fetch --all
head_sha=${{ inputs.duckdb-python-sha }}
branch_name="vendoring-${{ github.ref_name }}"
if [[ `git rev-parse --verify ${branch_name} 2>/dev/null` ]]; then
# branch exists
git checkout ${branch_name}
else
# new branch
git checkout -b ${branch_name}
fi
[[ ${head_sha} ]] && git reset --hard ${head_sha} || true

- name: Checkout DuckDB at Given SHA
run: |
cd external/duckdb
git fetch origin
git checkout ${{ inputs.duckdb-sha }}

- name: Determine GH PR Command
id: gh_pr_command
env:
GH_TOKEN: ${{ secrets.DUCKDBLABS_BOT_TOKEN }}
run: |
pr_url=$( gh pr list --head vendoring-${{ github.ref_name }} --state open --json url --jq '.[].url' )
if [[ $pr_url ]]; then
echo "::notice::Found existing pr, will edit (${pr_url})"
gh_command="edit ${pr_url}"
else
echo "::notice::No existing PR, will create new"
gh_command="create --head vendoring-${{ github.ref_name }} --base ${{ github.ref_name }}"
fi
echo "subcommand=${gh_command}" >> $GITHUB_OUTPUT

- name: Set Git User
run: |
git config --global user.email "[email protected]"
git config --global user.name "DuckDB Labs GitHub Bot"

- name: Create PR to Bump DuckDB Submodule
env:
GH_TOKEN: ${{ secrets.DUCKDBLABS_BOT_TOKEN }}
run: |
# No need to do anything if the submodule is already at the given sha
[[ `git status --porcelain -- external/duckdb` == "" ]] && exit 0
# We have changes. Commit and push
git add external/duckdb
git commit -m "Bump submodule"
git push --force origin vendoring-${{ github.ref_name }}
# create PR msg
echo "Bump duckdb submodule:" > body.txt
echo "- Target branch: ${{ github.ref_name }}" >> body.txt
echo "- Date: $( date +"%Y-%m-%d %H:%M:%S" )" >> body.txt
echo "- DuckDB SHA: ${{ inputs.duckdb-sha }}" >> body.txt
echo "- Trigger: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> body.txt
subcommand="${{ steps.gh_pr_command.outputs.subcommand }}"
gh pr ${subcommand} \
--title "[duckdb-labs bot] Bump DuckDB submodule" \
--body-file body.txt > output.txt 2>&1
success=$?
# Show summary
url=$( [[ $success ]] && gh pr view vendoring-${{ github.ref_name }} --json url --jq .url || true )
echo "## Submodule PR Summary" >> $GITHUB_STEP_SUMMARY
if [[ $success ]]; then
prefix=$( [[ $subcommand == edit* ]] && echo "Created" || echo "Updated" )
echo "### ${prefix} PR: [${url}](${url})" >> $GITHUB_STEP_SUMMARY
else
echo "### Failed to create PR" >> $GITHUB_STEP_SUMMARY
fi
echo '```' >> $GITHUB_STEP_SUMMARY
cat output.txt >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
[[ $success ]] || exit 1

- name: Automerge PR
if: ${{ inputs.auto-land }}
env:
GH_TOKEN: ${{ secrets.DUCKDBLABS_BOT_TOKEN }}
run: |
# PLACEHOLDER: DUCKDBLABS_BOT_TOKEN DOES NOT HAVE PERMISSIONS TO MERGE PRS
set -ex
gh pr merge vendoring-${{ github.ref_name }} --rebase > output.txt
success=$?
# Show summary
if [[ $success ]]; then
echo "### PR merged" >> $GITHUB_STEP_SUMMARY
else
echo "### Failed to auto-merge PR" >> $GITHUB_STEP_SUMMARY
fi
echo '```' >> $GITHUB_STEP_SUMMARY
cat output.txt >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
8 changes: 7 additions & 1 deletion .github/workflows/targeted_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
type: choice
options:
- 'windows-2025'
- 'windows-11-arm'
- 'ubuntu-24.04'
- 'ubuntu-24.04-arm'
- 'macos-15'
Expand Down Expand Up @@ -36,6 +37,11 @@ on:
description: 'Custom test path (must be in tests/ directory, overrides testsuite)'
required: false
type: string
verbose-uv:
description: 'Let uv generate verbose output (pytest verbosity is always on)'
required: false
type: boolean
default: true

jobs:
test:
Expand Down Expand Up @@ -83,4 +89,4 @@ jobs:
- name: Run tests
shell: bash
run: |
uv run pytest -vv ${{ steps.test_path.outputs.test_path }}
uv ${{ inputs.verbose-uv && 'run -v' || 'run' }} pytest -vv ${{ steps.test_path.outputs.test_path }}
19 changes: 0 additions & 19 deletions CHANGELOG.md

This file was deleted.

45 changes: 41 additions & 4 deletions _duckdb-stubs/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,18 @@ class DuckDBPyConnection:
def list_type(self, type: sqltypes.DuckDBPyType) -> sqltypes.DuckDBPyType: ...
def load_extension(self, extension: str) -> None: ...
def map_type(self, key: sqltypes.DuckDBPyType, value: sqltypes.DuckDBPyType) -> sqltypes.DuckDBPyType: ...
def pl(self, rows_per_batch: pytyping.SupportsInt = 1000000, *, lazy: bool = False) -> polars.DataFrame: ...
@pytyping.overload
def pl(
self, rows_per_batch: pytyping.SupportsInt = 1000000, *, lazy: pytyping.Literal[False] = ...
) -> polars.DataFrame: ...
@pytyping.overload
def pl(
self, rows_per_batch: pytyping.SupportsInt = 1000000, *, lazy: pytyping.Literal[True]
) -> polars.LazyFrame: ...
@pytyping.overload
def pl(
self, rows_per_batch: pytyping.SupportsInt = 1000000, *, lazy: bool = False
) -> pytyping.Union[polars.DataFrame, polars.LazyFrame]: ...
def query(self, query: str, *, alias: str = "", params: object = None) -> DuckDBPyRelation: ...
def query_progress(self) -> float: ...
def read_csv(
Expand Down Expand Up @@ -596,7 +607,16 @@ class DuckDBPyRelation:
) -> DuckDBPyRelation: ...
def order(self, order_expr: str) -> DuckDBPyRelation: ...
def percent_rank(self, window_spec: str, projected_columns: str = "") -> DuckDBPyRelation: ...
def pl(self, batch_size: pytyping.SupportsInt = 1000000, *, lazy: bool = False) -> polars.DataFrame: ...
@pytyping.overload
def pl(
self, batch_size: pytyping.SupportsInt = 1000000, *, lazy: pytyping.Literal[False] = ...
) -> polars.DataFrame: ...
@pytyping.overload
def pl(self, batch_size: pytyping.SupportsInt = 1000000, *, lazy: pytyping.Literal[True]) -> polars.LazyFrame: ...
@pytyping.overload
def pl(
self, batch_size: pytyping.SupportsInt = 1000000, *, lazy: bool = False
) -> pytyping.Union[polars.DataFrame, polars.LazyFrame]: ...
def product(
self, column: str, groups: str = "", window_spec: str = "", projected_columns: str = ""
) -> DuckDBPyRelation: ...
Expand Down Expand Up @@ -700,6 +720,7 @@ class DuckDBPyRelation:
partition_by: pytyping.List[str] | None = None,
write_partition_columns: bool | None = None,
append: bool | None = None,
filename_pattern: str | None = None,
) -> None: ...
def to_table(self, table_name: str) -> None: ...
def to_view(self, view_name: str, replace: bool = True) -> DuckDBPyRelation: ...
Expand Down Expand Up @@ -752,6 +773,7 @@ class DuckDBPyRelation:
partition_by: pytyping.List[str] | None = None,
write_partition_columns: bool | None = None,
append: bool | None = None,
filename_pattern: str | None = None,
) -> None: ...
@property
def alias(self) -> str: ...
Expand Down Expand Up @@ -1048,7 +1070,7 @@ def commit(*, connection: DuckDBPyConnection | None = None) -> DuckDBPyConnectio
def connect(
database: str | pathlib.Path = ":memory:",
read_only: bool = False,
config: dict[str, str] | None = None,
config: dict[str, str | bool | int | float | list[str]] | None = None,
) -> DuckDBPyConnection: ...
def create_function(
name: str,
Expand Down Expand Up @@ -1241,12 +1263,27 @@ def map_type(
def order(
df: pandas.DataFrame, order_expr: str, *, connection: DuckDBPyConnection | None = None
) -> DuckDBPyRelation: ...
@pytyping.overload
def pl(
rows_per_batch: pytyping.SupportsInt = 1000000,
*,
lazy: bool = False,
lazy: pytyping.Literal[False] = ...,
connection: DuckDBPyConnection | None = None,
) -> polars.DataFrame: ...
@pytyping.overload
def pl(
rows_per_batch: pytyping.SupportsInt = 1000000,
*,
lazy: pytyping.Literal[True],
connection: DuckDBPyConnection | None = None,
) -> polars.LazyFrame: ...
@pytyping.overload
def pl(
rows_per_batch: pytyping.SupportsInt = 1000000,
*,
lazy: bool = False,
connection: DuckDBPyConnection | None = None,
) -> pytyping.Union[polars.DataFrame, polars.LazyFrame]: ...
def project(
df: pandas.DataFrame, *args: str | Expression, groups: str = "", connection: DuckDBPyConnection | None = None
) -> DuckDBPyRelation: ...
Expand Down
4 changes: 3 additions & 1 deletion duckdb/experimental/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from . import spark # noqa: D104

__all__ = spark.__all__
__all__ = [
"spark",
]
Loading
Loading