Skip to content

Commit 7f7465b

Browse files
committed
Merge origin/main into PR 3503
2 parents dd7bc84 + fe7c749 commit 7f7465b

18 files changed

Lines changed: 821 additions & 431 deletions

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ jobs:
4444
python-version: 3.12
4545

4646
- name: Install UV
47-
uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
47+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
4848

4949
- name: Set version
5050
id: set-version

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
3.14
5555
5656
- name: Install UV
57-
uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
57+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
5858

5959
- name: Set version with RC
6060
shell: bash

.github/workflows/python-ci-docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ jobs:
4545
with:
4646
python-version: 3.12
4747
- name: Install UV
48-
uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
48+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
4949
- name: Build docs
5050
run: make docs-build
5151
- name: Run linters

.github/workflows/python-ci.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ jobs:
6262
with:
6363
python-version: ${{ matrix.python }}
6464
- name: Install UV
65-
uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
65+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
6666
with:
6767
enable-cache: true
6868
- name: Install system dependencies
@@ -88,7 +88,7 @@ jobs:
8888
with:
8989
python-version: '3.12'
9090
- name: Install UV
91-
uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
91+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
9292
with:
9393
enable-cache: true
9494
- name: Install system dependencies
@@ -117,7 +117,7 @@ jobs:
117117
with:
118118
python-version: '3.12'
119119
- name: Install UV
120-
uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
120+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
121121
with:
122122
enable-cache: true
123123
- name: Install system dependencies
@@ -146,7 +146,7 @@ jobs:
146146
with:
147147
python-version: '3.12'
148148
- name: Install UV
149-
uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
149+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
150150
with:
151151
enable-cache: true
152152
- name: Install system dependencies
@@ -175,7 +175,7 @@ jobs:
175175
with:
176176
python-version: '3.12'
177177
- name: Install UV
178-
uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
178+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
179179
with:
180180
enable-cache: true
181181
- name: Install system dependencies
@@ -205,7 +205,7 @@ jobs:
205205
with:
206206
python-version: '3.12'
207207
- name: Install UV
208-
uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
208+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
209209
with:
210210
enable-cache: true
211211
- name: Install dependencies
@@ -228,7 +228,7 @@ jobs:
228228
with:
229229
python-version: '3.12'
230230
- name: Install UV
231-
uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
231+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
232232
with:
233233
enable-cache: true
234234
# Why this exists:

.github/workflows/python-release-docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
with:
4343
python-version: 3.12
4444
- name: Install UV
45-
uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
45+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
4646
- name: Build docs
4747
run: make docs-build
4848
- name: Copy

.github/workflows/python-release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ jobs:
110110
python-version: 3.12
111111

112112
- name: Install UV
113-
uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
113+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
114114
with:
115115
enable-cache: false
116116

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
3.14
5555
5656
- name: Install UV
57-
uses: astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098 # v7.3.1
57+
uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0
5858

5959
# Publish the source distribution with the version that's in
6060
# the repository, otherwise the tests will fail

mkdocs/docs/api.md

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,15 +1529,69 @@ cleanup_old_snapshots("analytics.user_events", [12345, 67890, 11111])
15291529

15301530
## Views
15311531

1532-
PyIceberg supports view operations.
1532+
If PyIceberg is unable to automatically determine view support on your REST Catalog, you can manually specify, `"view-endpoints-supported": "true"`:
15331533

1534-
### Check if a view exists
1534+
```python
1535+
from pyiceberg.catalog import load_catalog
1536+
1537+
catalog = load_catalog(
1538+
"docs",
1539+
**{
1540+
"uri": "http://127.0.0.1:8181",
1541+
"py-io-impl": "pyiceberg.io.pyarrow.PyArrowFileIO",
1542+
"s3.endpoint": "http://127.0.0.1:9000",
1543+
"s3.access-key-id": "admin",
1544+
"s3.secret-access-key": "password",
1545+
"view-endpoints-supported": "true",
1546+
}
1547+
)
1548+
```
1549+
1550+
## Create a view
1551+
1552+
To create a view from the catalog:
15351553

15361554
```python
15371555
from pyiceberg.catalog import load_catalog
1556+
from pyiceberg.schema import Schema
1557+
from pyiceberg.types import IntegerType, NestedField
1558+
from pyiceberg.view import SQLViewRepresentation, ViewVersion
15381559

15391560
catalog = load_catalog("default")
1540-
catalog.view_exists("default.bar")
1561+
1562+
schema = Schema(NestedField(field_id=1, name="some_col", field_type=IntegerType(), required=False))
1563+
view_version = ViewVersion(
1564+
schema_id=1,
1565+
summary={"engine-name": "pyiceberg", "engine-version": "0.11.1"},
1566+
representations=[
1567+
SQLViewRepresentation(
1568+
type="sql",
1569+
sql="SELECT 1 as some_col",
1570+
dialect="spark",
1571+
)
1572+
],
1573+
default_namespace=["default"],
1574+
)
1575+
1576+
catalog.create_view(
1577+
identifier="default.some_view",
1578+
schema=schema,
1579+
view_version=view_version,
1580+
)
1581+
```
1582+
1583+
`catalog.create_view` also accepts a PyArrow schema, so the following is equivalent:
1584+
1585+
```python
1586+
import pyarrow as pa
1587+
1588+
schema = pa.schema([pa.field("some_col", pa.int32())])
1589+
1590+
catalog.create_view(
1591+
identifier="default.some_view",
1592+
schema=schema,
1593+
view_version=view_version,
1594+
)
15411595
```
15421596

15431597
## Register a view
@@ -1551,6 +1605,48 @@ catalog.register_view(
15511605
)
15521606
```
15531607

1608+
## Load a view
1609+
1610+
Loading the `some_view` view:
1611+
1612+
```python
1613+
view = catalog.load_view("default.some_view")
1614+
# Equivalent to:
1615+
view = catalog.load_view(("default", "some_view"))
1616+
# The tuple syntax can be used if the namespace or view contains a dot.
1617+
```
1618+
1619+
This returns a `View` that represents an Iceberg view. You can access the SQL representation for a specific dialect:
1620+
1621+
```python
1622+
sql_representation = view.sql_for("spark")
1623+
print(sql_representation.sql)
1624+
```
1625+
1626+
## Check if a view exists
1627+
1628+
To check whether the `some_view` view exists:
1629+
1630+
```python
1631+
catalog.view_exists("default.some_view")
1632+
```
1633+
1634+
## List views
1635+
1636+
To list views in the `default` namespace:
1637+
1638+
```python
1639+
catalog.list_views("default")
1640+
```
1641+
1642+
## Drop a view
1643+
1644+
To drop a view:
1645+
1646+
```python
1647+
catalog.drop_view("default.some_view")
1648+
```
1649+
15541650
## Table Statistics Management
15551651

15561652
Manage table statistics with operations through the `Table` API:

mkdocs/docs/configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ catalog:
347347
| warehouse | myWarehouse | Warehouse location or identifier to request from the catalog service. May be used to determine server-side overrides, such as the warehouse location. |
348348
| snapshot-loading-mode | refs | The snapshots to return in the body of the metadata. Setting the value to `all` would return the full set of snapshots currently valid for the table. Setting the value to `refs` would load all snapshots referenced by branches or tags. |
349349
| `header.X-Iceberg-Access-Delegation` | `vended-credentials` | Signal to the server that the client supports delegated access via a comma-separated list of access mechanisms. The server may choose to supply access via any or none of the requested mechanisms. When using `vended-credentials`, the server provides temporary credentials to the client. When using `remote-signing`, the server signs requests on behalf of the client. (default: `vended-credentials`) |
350+
| view-endpoints-supported | false | For backwards compatibility with older REST servers. Set to `true` if the server supports view endpoints but doesn't send the `endpoints` field in the ConfigResponse. |
350351

351352
#### Headers in REST Catalog
352353

pyiceberg/catalog/rest/__init__.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ class Endpoints:
147147
create_table: str = "namespaces/{namespace}/tables"
148148
register_table: str = "namespaces/{namespace}/register"
149149
load_table: str = "namespaces/{namespace}/tables/{table}"
150+
load_credentials: str = "namespaces/{namespace}/tables/{table}/credentials"
150151
update_table: str = "namespaces/{namespace}/tables/{table}"
151152
drop_table: str = "namespaces/{namespace}/tables/{table}"
152153
table_exists: str = "namespaces/{namespace}/tables/{table}"
@@ -181,6 +182,7 @@ class Capability:
181182
V1_DELETE_TABLE = Endpoint(http_method=HttpMethod.DELETE, path=f"{API_PREFIX}/{Endpoints.drop_table}")
182183
V1_RENAME_TABLE = Endpoint(http_method=HttpMethod.POST, path=f"{API_PREFIX}/{Endpoints.rename_table}")
183184
V1_REGISTER_TABLE = Endpoint(http_method=HttpMethod.POST, path=f"{API_PREFIX}/{Endpoints.register_table}")
185+
V1_LOAD_CREDENTIALS = Endpoint(http_method=HttpMethod.GET, path=f"{API_PREFIX}/{Endpoints.load_credentials}")
184186

185187
V1_LIST_VIEWS = Endpoint(http_method=HttpMethod.GET, path=f"{API_PREFIX}/{Endpoints.list_views}")
186188
V1_LOAD_VIEW = Endpoint(http_method=HttpMethod.GET, path=f"{API_PREFIX}/{Endpoints.load_view}")
@@ -293,6 +295,10 @@ class TableResponse(IcebergBaseModel):
293295
storage_credentials: list[StorageCredential] = Field(alias="storage-credentials", default_factory=list)
294296

295297

298+
class LoadCredentialsResponse(IcebergBaseModel):
299+
storage_credentials: list[StorageCredential] = Field(alias="storage-credentials")
300+
301+
296302
class ViewResponse(IcebergBaseModel):
297303
metadata_location: str | None = Field(alias="metadata-location", default=None)
298304
metadata: ViewMetadata
@@ -1094,6 +1100,32 @@ def load_table(self, identifier: str | Identifier) -> Table:
10941100
table_response = TableResponse.model_validate_json(response.text)
10951101
return self._response_to_table(self.identifier_to_tuple(identifier), table_response)
10961102

1103+
@retry(**_RETRY_ARGS)
1104+
def _load_credentials(
1105+
self,
1106+
identifier: str | Identifier,
1107+
) -> LoadCredentialsResponse:
1108+
"""Load raw vended storage credentials for a table."""
1109+
self._check_endpoint(Capability.V1_LOAD_CREDENTIALS)
1110+
response = self._session.get(
1111+
self.url(Endpoints.load_credentials, prefixed=True, **self._split_identifier_for_path(identifier)),
1112+
)
1113+
try:
1114+
response.raise_for_status()
1115+
except HTTPError as exc:
1116+
_handle_non_200_response(exc, {404: NoSuchTableError})
1117+
1118+
return LoadCredentialsResponse.model_validate_json(response.text)
1119+
1120+
def load_credentials(
1121+
self,
1122+
identifier: str | Identifier,
1123+
location: str,
1124+
) -> Properties:
1125+
"""Load vended storage credentials and return the best match for a location."""
1126+
credentials_response = self._load_credentials(identifier)
1127+
return self._resolve_storage_credentials(credentials_response.storage_credentials, location)
1128+
10971129
@retry(**_RETRY_ARGS)
10981130
@override
10991131
def drop_table(self, identifier: str | Identifier, purge_requested: bool = False) -> None:

0 commit comments

Comments
 (0)