Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
551fc5d
pyproject: Move homepage and repo up (#2736)
kevinjqliu Nov 11, 2025
1220295
Renable linter rule B024 (#2737)
rambleraptor Nov 11, 2025
c807124
sdist: remove .egg-info and setup.cfg from sdist (#2734)
kevinjqliu Nov 11, 2025
d6e978c
Makefile: apply PYTHON_ARG override in all uv commands (#2735)
kevinjqliu Nov 11, 2025
ff0fa55
Re-enable rule B208 (#2738)
rambleraptor Nov 11, 2025
60ebe93
Enable up037 (#2739)
rambleraptor Nov 12, 2025
36906ed
Enables linter rule UP006 (#2744)
rambleraptor Nov 13, 2025
f2131e6
docs: add GCP BigLake Metastore Catalog configuration example (#2740)
heathkh-recursion Nov 13, 2025
ea8ade2
Exclude `pyiceberg-core` for some optional deps (#2748)
kevinjqliu Nov 17, 2025
6773c85
infra: notify on github workflow failure (#2682)
kevinjqliu Nov 17, 2025
7e3d3af
Fix `check-md-link` and allow manual trigger (#2765)
kevinjqliu Nov 18, 2025
4cd1a63
Remove `Generic` from expressions (#2750)
Fokko Nov 18, 2025
bb325f2
Build: Bump pypa/cibuildwheel from 3.2.1 to 3.3.0 (#2751)
dependabot[bot] Nov 18, 2025
0ed0bef
Build: Bump mypy-boto3-glue from 1.40.63 to 1.40.75 (#2752)
dependabot[bot] Nov 18, 2025
fa38829
Build: Bump prek from 0.2.13 to 0.2.15 (#2753)
dependabot[bot] Nov 18, 2025
93f5214
Build: Bump pyarrow from 21.0.0 to 22.0.0 (#2754)
dependabot[bot] Nov 18, 2025
f1e9ba6
Build: Bump huggingface-hub from 1.1.2 to 1.1.4 (#2755)
dependabot[bot] Nov 18, 2025
4644687
Build: Bump cython from 3.2.0 to 3.2.1 (#2756)
dependabot[bot] Nov 18, 2025
4ef074e
Build: Bump cachetools from 6.2.1 to 6.2.2 (#2759)
dependabot[bot] Nov 18, 2025
e4b41c5
Build: Bump duckdb from 1.4.1 to 1.4.2 (#2760)
dependabot[bot] Nov 18, 2025
27f92fe
Build: Bump boto3 from 1.40.61 to 1.40.75 (#2761)
dependabot[bot] Nov 18, 2025
456aabd
Build: Bump click from 8.3.0 to 8.3.1 (#2762)
dependabot[bot] Nov 18, 2025
de1f1b4
Build: Bump mkdocs-material from 9.6.23 to 9.7.0 (#2763)
dependabot[bot] Nov 18, 2025
7254a9d
Build: Bump daft from 0.6.12 to 0.6.14 (#2758)
dependabot[bot] Nov 18, 2025
155af26
Remove UP035 from ruff ignore list (#2767)
rambleraptor Nov 18, 2025
93a4173
Build: Bump protobuf from 6.33.0 to 6.33.1 (#2757)
dependabot[bot] Nov 18, 2025
c330eb4
Follow up on cleaning up the removal of `Generic` (#2769)
Fokko Nov 19, 2025
36baca9
infra: add instructions for cleaning up testpypi artifacts (#2774)
kevinjqliu Nov 20, 2025
59dc8d1
fix: Remove unused fields from FileScanTask (#2777)
geruh Nov 21, 2025
d9bdf8e
fix: Serialize AlwaysTrue/AlwaysFalse as boolean literals (#2780)
geruh Nov 25, 2025
3d20ff5
Build: Bump actions/checkout from 5 to 6 (#2779)
dependabot[bot] Nov 25, 2025
38c9ca2
Build: Bump tcort/github-action-markdown-link-check from 1.1.1 to 1.1…
dependabot[bot] Nov 25, 2025
6806207
chore: add pyarrow-stubs dependency for type hint & suggestion (#2768)
dingo4dev Nov 25, 2025
9610b41
fix: Set Expression serialization to use 'values' (#2782)
geruh Nov 25, 2025
d1826f1
feat: Make `and` expression JSON serializable (#2784)
geruh Nov 26, 2025
33438bd
Add missing ORC iceberg.required attribute (#2789)
ebyhr Dec 1, 2025
32c97ae
infra: use new `del_branch_on_merge` in .asf.yaml (#2788)
kevinjqliu Dec 1, 2025
e3070d4
JSON to expression (#2783)
Fokko Dec 3, 2025
8ed913b
Read partitioned tables with source field missing (#2367)
gabeiglio Dec 4, 2025
e3567bc
example
kevinjqliu Dec 5, 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 .asf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ github:
required_approving_review_count: 1

required_linear_history: true
del_branch_on_merge: true
pull_requests:
# auto-delete head branches after being merged
del_branch_on_merge: true
features:
wiki: true
issues: true
Expand All @@ -57,4 +59,5 @@ notifications:
commits: commits@iceberg.apache.org
issues: issues@iceberg.apache.org
pullrequests: issues@iceberg.apache.org
jobs: ci-jobs@iceberg.apache.org
jira_options: link label link label
3 changes: 2 additions & 1 deletion .github/workflows/check-md-link.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ on:
paths:
- '.github/workflows/check-md-link.yml'
- 'mkdocs/**'
workflow_dispatch:

jobs:
markdown-link-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: tcort/github-action-markdown-link-check@v1
- uses: tcort/github-action-markdown-link-check@e7c7a18363c842693fadde5d41a3bd3573a7a225
2 changes: 1 addition & 1 deletion .github/workflows/license_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ jobs:
rat:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- run: dev/check-license
29 changes: 28 additions & 1 deletion .github/workflows/nightly-pypi-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
outputs:
VERSION: ${{ steps.set-version.outputs.VERSION }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
fetch-depth: 1

Expand Down Expand Up @@ -78,8 +78,35 @@ jobs:
- name: List downloaded artifacts
run: ls -R dist/
- name: Publish to TestPyPI
id: publish-testpypi
continue-on-error: true
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
skip-existing: true
verbose: true
- name: Display error message on publish failure
if: steps.publish-testpypi.outcome == 'failure'
run: |
echo "::error::Failed to publish to TestPyPI"
echo ""
echo "⚠️ TestPyPI Publish Failed"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "This may be due to TestPyPI storage limits."
echo "See: https://docs.pypi.org/project-management/storage-limits"
echo ""
echo "To resolve this issue, use the pypi-cleanup utility to clean up old TestPyPI artifacts:"
echo "https://pypi.org/project/pypi-cleanup/"
echo ""
echo " uvx pypi-cleanup --package pyiceberg --host https://test.pypi.org/ \\"
echo " --verbose -d 10 --do-it --username <username>"
echo ""
echo "Requirements:"
echo " • Must be a maintainer for pyiceberg on TestPyPI"
echo " (https://test.pypi.org/project/pyiceberg)"
echo " • Requires TestPyPI password and 2FA"
echo " • ⚠️ ONLY do this for TestPyPI, NOT for production PyPI!"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
exit 1
4 changes: 2 additions & 2 deletions .github/workflows/pypi-build-artifacts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
os: [ ubuntu-latest, windows-latest, macos-latest ]

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
fetch-depth: 1

Expand All @@ -61,7 +61,7 @@ jobs:
if: startsWith(matrix.os, 'ubuntu')

- name: Build wheels
uses: pypa/cibuildwheel@v3.2.1
uses: pypa/cibuildwheel@v3.3.0
with:
output-dir: wheelhouse
config-file: "pyproject.toml"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/python-ci-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: 3.12
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
python: ['3.10', '3.11', '3.12']

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
Expand All @@ -74,7 +74,7 @@ jobs:
python: ['3.10', '3.11', '3.12']

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/python-release-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/python-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ jobs:
needs:
- validate-inputs
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
fetch-depth: 1

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/svn-build-artifacts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
os: [ ubuntu-latest, windows-latest, macos-latest ]

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
fetch-depth: 1

Expand All @@ -56,7 +56,7 @@ jobs:
if: startsWith(matrix.os, 'ubuntu')

- name: Build wheels
uses: pypa/cibuildwheel@v3.2.1
uses: pypa/cibuildwheel@v3.3.0
with:
output-dir: wheelhouse
config-file: "pyproject.toml"
Expand Down
26 changes: 14 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
# Configuration Variables
# ========================



PYTHON ?= # Override with e.g. PYTHON=3.11 to use specific Python version
PYTEST_ARGS ?= -v -x # Override with e.g. PYTEST_ARGS="-vv --tb=short"
COVERAGE ?= 0 # Set COVERAGE=1 to enable coverage: make test COVERAGE=1
Expand All @@ -32,9 +34,9 @@ else
endif

ifeq ($(COVERAGE),1)
TEST_RUNNER = uv run python -m coverage run --parallel-mode --source=pyiceberg -m
TEST_RUNNER = uv run $(PYTHON_ARG) python -m coverage run --parallel-mode --source=pyiceberg -m
else
TEST_RUNNER = uv run python -m
TEST_RUNNER = uv run $(PYTHON_ARG) python -m
endif

ifeq ($(KEEP_COMPOSE),1)
Expand Down Expand Up @@ -70,7 +72,7 @@ setup-venv: ## Create virtual environment
uv venv $(PYTHON_ARG)

install-dependencies: setup-venv ## Install all dependencies including extras
uv sync --all-extras
uv sync $(PYTHON_ARG) --all-extras

install: install-uv install-dependencies ## Install uv and dependencies

Expand All @@ -84,7 +86,7 @@ check-license: ## Check license headers
./dev/check-license

lint: ## Run code linters via prek (pre-commit hooks)
uv run prek run -a
uv run $(PYTHON_ARG) prek run -a

# ===============
# Testing Section
Expand All @@ -101,7 +103,7 @@ test-integration-setup: ## Start Docker services for integration tests
docker compose -f dev/docker-compose-integration.yml kill
docker compose -f dev/docker-compose-integration.yml rm -f
docker compose -f dev/docker-compose-integration.yml up -d --wait
uv run python dev/provision.py
uv run $(PYTHON_ARG) python dev/provision.py

test-integration-exec: ## Run integration tests (excluding provision)
$(TEST_RUNNER) pytest tests/ -m integration $(PYTEST_ARGS)
Expand Down Expand Up @@ -133,10 +135,10 @@ test-coverage: COVERAGE=1
test-coverage: test test-integration test-s3 test-adls test-gcs coverage-report ## Run all tests with coverage and report

coverage-report: ## Combine and report coverage
uv run coverage combine
uv run coverage report -m --fail-under=$(COVERAGE_FAIL_UNDER)
uv run coverage html
uv run coverage xml
uv run $(PYTHON_ARG) coverage combine
uv run $(PYTHON_ARG) coverage report -m --fail-under=$(COVERAGE_FAIL_UNDER)
uv run $(PYTHON_ARG) coverage html
uv run $(PYTHON_ARG) coverage xml

# ================
# Documentation
Expand All @@ -145,13 +147,13 @@ coverage-report: ## Combine and report coverage
##@ Documentation

docs-install: ## Install docs dependencies (included in default groups)
uv sync --group docs
uv sync $(PYTHON_ARG) --group docs

docs-serve: ## Serve local docs preview (hot reload)
uv run mkdocs serve -f mkdocs/mkdocs.yml
uv run $(PYTHON_ARG) mkdocs serve -f mkdocs/mkdocs.yml

docs-build: ## Build the static documentation site
uv run mkdocs build -f mkdocs/mkdocs.yml --strict
uv run $(PYTHON_ARG) mkdocs build -f mkdocs/mkdocs.yml --strict

# ===================
# Project Maintenance
Expand Down
2 changes: 0 additions & 2 deletions dev/.rat-excludes
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,3 @@ build
.gitignore
uv.lock
mkdocs/*
setup.cfg
(^|.*/)[^/]*\.egg-info(/.*)?$
22 changes: 22 additions & 0 deletions mkdocs/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,28 @@ catalog:
type: noop
```

##### GCP BigLake Metastore Catalog REST

```yaml
catalog:
biglake_catalog:
type: rest
uri: https://biglake.googleapis.com/iceberg/v1/restcatalog
warehouse: gs://<bucket-name> # Use bq://projects/<gcp-project-id> for federation option (see docs)
auth:
type: google
header.x-goog-user-project: <gcp-project-id>
header.X-Iceberg-Access-Delegation: "" # For user-credentials authentication, set to empty string.
```

<!-- prettier-ignore-start -->

!!! Note "Metastore Authentication Models"
If your BigLake Metastore catalog is configured for "user credentials" authentication instead of "vendor credentials", set the `header.X-Iceberg-Access-Delegation` header to an empty string as shown above. Standard GCP Application Default Credentials (ADC) will be used to authenticate requests to the BigLake Metastore REST API.
You can retrieve the configuration details for your BigLake Iceberg catalog at the [GCP Console BigLake Metastore page](https://console.cloud.google.com/biglake/metastore/catalogs). Select your catalog, then find the necessary parameters such as `uri`, `warehouse`, and authentication method (e.g. user-creds or vendor).

<!-- prettier-ignore-end -->

### SQL Catalog

The SQL catalog requires a database for its backend. PyIceberg supports PostgreSQL and SQLite through psycopg2. The database connection has to be configured using the `uri` property. The init_catalog_tables is optional and defaults to True. If it is set to False, the catalog tables will not be created when the SQLCatalog is initialized. See SQLAlchemy's [documentation for URL format](https://docs.sqlalchemy.org/en/20/core/engines.html#backend-specific-urls):
Expand Down
8 changes: 3 additions & 5 deletions pyiceberg/avro/codecs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@

from __future__ import annotations

from typing import Dict, Literal, Type

from typing_extensions import TypeAlias
from typing import Literal, TypeAlias

from pyiceberg.avro.codecs.bzip2 import BZip2Codec
from pyiceberg.avro.codecs.codec import Codec
Expand All @@ -40,7 +38,7 @@

AVRO_CODEC_KEY = "avro.codec"

KNOWN_CODECS: Dict[AvroCompressionCodec, Type[Codec] | None] = {
KNOWN_CODECS: dict[AvroCompressionCodec, type[Codec] | None] = {
"null": None,
"bzip2": BZip2Codec,
"snappy": SnappyCodec,
Expand All @@ -49,4 +47,4 @@
}

# Map to convert the naming from Iceberg to Avro
CODEC_MAPPING_ICEBERG_TO_AVRO: Dict[str, str] = {"gzip": "deflate", "zstd": "zstandard"}
CODEC_MAPPING_ICEBERG_TO_AVRO: dict[str, str] = {"gzip": "deflate", "zstd": "zstandard"}
15 changes: 6 additions & 9 deletions pyiceberg/avro/decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
from abc import ABC, abstractmethod
from io import SEEK_CUR
from typing import (
Dict,
List,
Tuple,
cast,
)

Expand Down Expand Up @@ -67,11 +64,11 @@ def read_int(self) -> int:
datum = (n >> 1) ^ -(n & 1)
return datum

def read_ints(self, n: int) -> Tuple[int, ...]:
def read_ints(self, n: int) -> tuple[int, ...]:
"""Read a list of integers."""
return tuple(self.read_int() for _ in range(n))

def read_int_bytes_dict(self, n: int, dest: Dict[int, bytes]) -> None:
def read_int_bytes_dict(self, n: int, dest: dict[int, bytes]) -> None:
"""Read a dictionary of integers for keys and bytes for values into a destination dictionary."""
for _ in range(n):
k = self.read_int()
Expand All @@ -85,7 +82,7 @@ def read_float(self) -> float:
The float is converted into a 32-bit integer using a method equivalent to
Java's floatToIntBits and then encoded in little-endian format.
"""
return float(cast(Tuple[float, ...], STRUCT_FLOAT.unpack(self.read(4)))[0])
return float(cast(tuple[float, ...], STRUCT_FLOAT.unpack(self.read(4)))[0])

def read_double(self) -> float:
"""Read a value from the stream as a double.
Expand All @@ -94,7 +91,7 @@ def read_double(self) -> float:
The double is converted into a 64-bit integer using a method equivalent to
Java's doubleToLongBits and then encoded in little-endian format.
"""
return float(cast(Tuple[float, ...], STRUCT_DOUBLE.unpack(self.read(8)))[0])
return float(cast(tuple[float, ...], STRUCT_DOUBLE.unpack(self.read(8)))[0])

def read_bytes(self) -> bytes:
"""Bytes are encoded as a long followed by that many bytes of data."""
Expand Down Expand Up @@ -152,7 +149,7 @@ def read(self, n: int) -> bytes:
"""Read n bytes."""
if n < 0:
raise ValueError(f"Requested {n} bytes to read, expected positive integer.")
data: List[bytes] = []
data: list[bytes] = []

n_remaining = n
while n_remaining > 0:
Expand Down Expand Up @@ -181,6 +178,6 @@ def new_decoder(b: bytes) -> BinaryDecoder:
except ModuleNotFoundError:
import warnings

warnings.warn("Falling back to pure Python Avro decoder, missing Cython implementation")
warnings.warn("Falling back to pure Python Avro decoder, missing Cython implementation", stacklevel=2)

return StreamingBinaryDecoder(b)
Loading