Skip to content

Commit 849c26c

Browse files
committed
Merge branch 'main' into fix/3625-signer-on-session
Resolves a conflict in _s3(): main added s3_additional_kwargs handling for server-side encryption while this branch replaced the post-construction signer registration with registration on an AioSession. Both apply — the additional kwargs are added to s3_fs_kwargs before the session is attached.
2 parents 402fa43 + 7539661 commit 849c26c

46 files changed

Lines changed: 3317 additions & 398 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.asf.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ github:
4444

4545
required_linear_history: true
4646
pull_requests:
47+
# allow pull requests to merge automatically once all requirements are met
48+
allow_auto_merge: true
4749
# auto-delete head branches after being merged
4850
del_branch_on_merge: true
4951
features:

.github/workflows/codeql.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ jobs:
4646
persist-credentials: false
4747

4848
- name: Initialize CodeQL
49-
uses: github/codeql-action/init@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4
49+
uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
5050
with:
5151
languages: actions
5252

5353
- name: Perform CodeQL Analysis
54-
uses: github/codeql-action/analyze@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4
54+
uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
5555
with:
5656
category: "/language:actions"

.github/workflows/pypi-build-artifacts.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ jobs:
6969
if: matrix.os == 'ubuntu-latest'
7070

7171
- name: Build wheels
72-
uses: pypa/cibuildwheel@4726cd35bb13f7bde50cf2761f2499ac7b3aa32c # v4.1.1
72+
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
7373
with:
7474
output-dir: wheelhouse
7575
config-file: "pyproject.toml"

.github/workflows/stale.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
if: github.repository_owner == 'apache'
3333
runs-on: ubuntu-latest
3434
steps:
35-
- uses: actions/stale@1e223db275d687790206a7acac4d1a11bd6fe629 # v10.4.0
35+
- uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0
3636
with:
3737
# stale issues
3838
stale-issue-label: 'stale'

.github/workflows/svn-build-artifacts.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ jobs:
6363
if: matrix.os == 'ubuntu-latest'
6464

6565
- name: Build wheels
66-
uses: pypa/cibuildwheel@4726cd35bb13f7bde50cf2761f2499ac7b3aa32c # v4.1.1
66+
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
6767
with:
6868
output-dir: wheelhouse
6969
config-file: "pyproject.toml"

dev/release/verify_rc.sh

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Licensed to the Apache Software Foundation (ASF) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The ASF licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing,
14+
# software distributed under the License is distributed on an
15+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
# KIND, either express or implied. See the License for the
17+
# specific language governing permissions and limitations
18+
# under the License.
19+
#
20+
# Verifies a PyIceberg release candidate, following the steps in
21+
# mkdocs/docs/verify-release.md: signatures, checksums, license
22+
# documentation (RAT), and the test suite of the source distribution.
23+
24+
set -euo pipefail
25+
26+
if [ "$#" -ne 1 ]; then
27+
echo "Usage: $0 <version>"
28+
echo " e.g.: $0 0.6.1rc3"
29+
exit 1
30+
fi
31+
32+
PYICEBERG_VERSION="$1"
33+
# remove the rcX qualifier, the artifacts inside the RC are named after the release
34+
PYICEBERG_RELEASE_VERSION="${PYICEBERG_VERSION%rc*}"
35+
PYICEBERG_VERIFICATION_DIR="${PYICEBERG_VERIFICATION_DIR:-/tmp/pyiceberg/${PYICEBERG_VERSION}}"
36+
37+
# Set to 0 to skip a step, e.g. VERIFY_TEST=0 ./dev/release/verify_rc.sh 0.6.1rc3
38+
: "${VERIFY_SIGN:=1}"
39+
: "${VERIFY_CHECKSUM:=1}"
40+
: "${VERIFY_LICENSE:=1}"
41+
: "${VERIFY_TEST:=1}"
42+
43+
if type shasum >/dev/null 2>&1; then
44+
sha512_verify="shasum -a 512 --check"
45+
else
46+
sha512_verify="sha512sum --check"
47+
fi
48+
49+
import_gpg_keys() {
50+
echo "--- Importing KEYS"
51+
curl --fail --location --show-error --silent https://downloads.apache.org/iceberg/KEYS | gpg --import
52+
}
53+
54+
download_rc() {
55+
echo "--- Downloading pyiceberg-${PYICEBERG_VERSION}"
56+
svn checkout "https://dist.apache.org/repos/dist/dev/iceberg/pyiceberg-${PYICEBERG_VERSION}/" "${PYICEBERG_VERIFICATION_DIR}"
57+
}
58+
59+
verify_signatures() {
60+
echo "--- Verifying signatures"
61+
for name in pyiceberg-*.whl pyiceberg-*.tar.gz; do
62+
gpg --verify "${name}.asc" "${name}"
63+
done
64+
}
65+
66+
verify_checksums() {
67+
echo "--- Verifying checksums"
68+
for name in pyiceberg-*.whl.sha512 pyiceberg-*.tar.gz.sha512; do
69+
${sha512_verify} "${name}"
70+
done
71+
}
72+
73+
extract_source_distribution() {
74+
echo "--- Extracting pyiceberg-${PYICEBERG_RELEASE_VERSION}.tar.gz"
75+
tar xzf "pyiceberg-${PYICEBERG_RELEASE_VERSION}.tar.gz"
76+
}
77+
78+
verify_license_documentation() {
79+
echo "--- Running RAT checks"
80+
./dev/check-license
81+
}
82+
83+
test_source_distribution() {
84+
echo "--- Installing and running the tests, this spins up Docker containers"
85+
make install
86+
make test-coverage
87+
}
88+
89+
echo "Verifying pyiceberg-${PYICEBERG_VERSION} in ${PYICEBERG_VERIFICATION_DIR}"
90+
91+
if [ "${VERIFY_SIGN}" -gt 0 ]; then
92+
import_gpg_keys
93+
fi
94+
95+
download_rc
96+
cd "${PYICEBERG_VERIFICATION_DIR}"
97+
98+
if [ "${VERIFY_SIGN}" -gt 0 ]; then
99+
verify_signatures
100+
fi
101+
102+
if [ "${VERIFY_CHECKSUM}" -gt 0 ]; then
103+
verify_checksums
104+
fi
105+
106+
extract_source_distribution
107+
cd "pyiceberg-${PYICEBERG_RELEASE_VERSION}"
108+
109+
if [ "${VERIFY_LICENSE}" -gt 0 ]; then
110+
verify_license_documentation
111+
fi
112+
113+
if [ "${VERIFY_TEST}" -gt 0 ]; then
114+
test_source_distribution
115+
fi
116+
117+
echo "RC looks good! Cast your vote on the dev mailing list."

mkdocs/docs/configuration.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,26 @@ Iceberg tables support table properties to configure table behavior.
108108

109109
<!-- prettier-ignore-end -->
110110

111+
### Commit retry options
112+
113+
When a concurrent commit is detected, PyIceberg automatically retries the operation with exponential backoff. If the retry detects a real data conflict (e.g. concurrent deletes on the same partition), it raises `ValidationException` instead of retrying.
114+
115+
| Key | Options | Default | Description |
116+
| -------------------------------- | ---------------- | --------- | ------------------------------------------------------------------ |
117+
| `commit.retry.num-retries` | Integer | 4 | Maximum number of retry attempts after a commit conflict |
118+
| `commit.retry.min-wait-ms` | Integer (ms) | 100 | Minimum wait time before the first retry |
119+
| `commit.retry.max-wait-ms` | Integer (ms) | 60000 | Maximum wait time between retries (caps exponential backoff) |
120+
| `commit.retry.total-timeout-ms` | Integer (ms) | 1800000 | Total time allowed for all retry attempts before giving up |
121+
122+
### Isolation level options
123+
124+
These properties control conflict detection behavior during concurrent writes.
125+
126+
| Key | Options | Default | Description |
127+
| -------------------------------- | -------------------------------- | ------------ | ----------------------------------------------------------------------------------------------- |
128+
| `write.delete.isolation-level` | `{serializable,snapshot}` | serializable | Isolation level for delete operations. Under `serializable`, concurrent appends to affected partitions cause `ValidationException`. Under `snapshot`, only conflicting deletes are rejected. |
129+
| `write.update.isolation-level` | `{serializable,snapshot}` | serializable | Isolation level for overwrite operations. Same semantics as `write.delete.isolation-level`. |
130+
111131
## FileIO
112132

113133
Iceberg works with the concept of a FileIO which is a pluggable module for reading, writing, and deleting files. By default, PyIceberg will try to initialize the FileIO that's suitable for the scheme (`s3://`, `gs://`, etc.) and will use the first one that's installed.
@@ -152,6 +172,8 @@ For the FileIO there are several configuration options available:
152172
| s3.force-virtual-addressing | False | Whether to use virtual addressing of buckets. If true, then virtual addressing is always enabled. If false, then virtual addressing is only enabled if endpoint_override is empty. This can be used for non-AWS backends that only support virtual hosted-style access. |
153173
| s3.retry-strategy-impl | None | Ability to set a custom S3 retry strategy. A full path to a class needs to be given that extends the [S3RetryStrategy](https://github.com/apache/arrow/blob/639201bfa412db26ce45e73851432018af6c945e/python/pyarrow/_s3fs.pyx#L110) base class. |
154174
| s3.anonymous | True | Configure whether to use anonymous connection. If False (default), uses key/secret if configured or boto's credential resolver. |
175+
| s3.server-side-encryption | aws:kms | Configure server-side encryption (e.g. `AES256` or `aws:kms`). Only supported by `FsspecFileIO`. |
176+
| s3.sse-kms-key-id | alias/my-key | Configure the SSE-KMS key id (or ARN) for multipart uploads. Only supported by `FsspecFileIO`. |
155177

156178
<!-- markdown-link-check-enable-->
157179

mkdocs/docs/verify-release.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,15 @@ Release announcements include links to the following:
3535

3636
After downloading the source tarball, signature, checksum, and KEYS file, here are instructions on how to verify signatures, checksums, and documentation.
3737

38-
## Verifying signatures
38+
All of the steps below are also available as a single script that should be run from the `iceberg-python` root directory.
39+
40+
```sh
41+
./dev/release/verify_rc.sh 0.6.1rc3
42+
```
43+
44+
The following are the script steps for manual verification.
45+
46+
### Verifying signatures
3947

4048
First, import the keys.
4149

@@ -69,7 +77,7 @@ do
6977
done
7078
```
7179

72-
## Verifying checksums
80+
### Verifying checksums
7381

7482
```sh
7583
cd ${PYICEBERG_VERIFICATION_DIR}
@@ -79,7 +87,7 @@ do
7987
done
8088
```
8189

82-
## Verifying License Documentation
90+
### Verifying License Documentation
8391

8492
```sh
8593
export PYICEBERG_RELEASE_VERSION=${PYICEBERG_VERSION/rc?/} # remove rcX qualifier
@@ -93,7 +101,7 @@ Run RAT checks to validate license header:
93101
./dev/check-license
94102
```
95103

96-
## Testing
104+
### Testing
97105

98106
This section explains how to run the tests of the source distribution.
99107

pyiceberg/catalog/dynamodb.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,10 @@ def _get_update_database_item(namespace_item: dict[str, Any], updated_properties
837837

838838

839839
def _get_namespace_properties(namespace_dict: dict[str, str]) -> Properties:
840-
return {_remove_property_prefix(key): val for key, val in namespace_dict.items() if key.startswith(PROPERTY_KEY_PREFIX)}
840+
# removeprefix removes the literal prefix, unlike lstrip which removes any leading prefix characters
841+
return {
842+
key.removeprefix(PROPERTY_KEY_PREFIX): val for key, val in namespace_dict.items() if key.startswith(PROPERTY_KEY_PREFIX)
843+
}
841844

842845

843846
def _convert_dynamo_item_to_regular_dict(dynamo_json: dict[str, Any]) -> dict[str, str]:
@@ -888,7 +891,3 @@ def _convert_dynamo_item_to_regular_dict(dynamo_json: dict[str, Any]) -> dict[st
888891

889892
def _add_property_prefix(prop: str) -> str:
890893
return PROPERTY_KEY_PREFIX + prop
891-
892-
893-
def _remove_property_prefix(prop: str) -> str:
894-
return prop.lstrip(PROPERTY_KEY_PREFIX)

0 commit comments

Comments
 (0)