Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,6 @@ htmlcov
pyiceberg/avro/decoder_fast.c
pyiceberg/avro/*.html
pyiceberg/avro/*.so

# Generated version file
pyiceberg/_version.py
14 changes: 14 additions & 0 deletions build-module.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@
allowed_to_fail = os.environ.get("CIBUILDWHEEL", "0") != "1"


def generate_version_file() -> None:
"""Generate the _version.py file using setuptools_scm."""
try:
from setuptools_scm import get_version # type: ignore[import-not-found]

version = get_version(root=".", relative_to=__file__)
print(f"Generated version: {version}")
except Exception as e:
if not allowed_to_fail:
raise
print(f"Warning: Could not generate version file: {e}")


def build_cython_extensions() -> None:
import Cython.Compiler.Options
from Cython.Build import build_ext, cythonize
Expand Down Expand Up @@ -65,6 +78,7 @@ def build_cython_extensions() -> None:


try:
generate_version_file()
build_cython_extensions()
except Exception:
if not allowed_to_fail:
Expand Down
3 changes: 3 additions & 0 deletions pyiceberg/catalog/rest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
)
from pyiceberg.typedef import EMPTY_DICT, UTF8, IcebergBaseModel, Identifier, Properties
from pyiceberg.types import transform_dict_value_to_str
from pyiceberg.utils.build_info import git_commit_short_id
from pyiceberg.utils.deprecated import deprecation_message
from pyiceberg.utils.properties import get_first_property_value, get_header_properties, property_as_bool

Expand Down Expand Up @@ -484,6 +485,8 @@ def _config_headers(self, session: Session) -> None:
session.headers.update(header_properties)
session.headers["Content-type"] = "application/json"
session.headers["User-Agent"] = f"PyIceberg/{__version__}"
session.headers["X-Client-Version"] = __version__
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @jaimeferj for working on this. Wouldn't this make the User-Agent header the line above redundant?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good one, thanks!

session.headers["X-Client-Git-Commit-Short"] = git_commit_short_id()
session.headers.setdefault("X-Iceberg-Access-Delegation", ACCESS_DELEGATION_DEFAULT)

def _create_table(
Expand Down
35 changes: 35 additions & 0 deletions pyiceberg/utils/build_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""Utilities for build information."""

import re
from functools import lru_cache


@lru_cache(maxsize=1)
def git_commit_short_id() -> str:
"""Extract the short git commit ID from the version string."""
try:
from pyiceberg._version import __version__

match = re.search(r"\+g([0-9a-f]{7})", __version__)
if match:
return match.group(1)

return "unknown"
except (ImportError, AttributeError):
return "unknown"
31 changes: 30 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -295,13 +295,38 @@ ignore_missing_imports = true
pyiceberg = "pyiceberg.cli.console:run"

[build-system]
requires = ["poetry-core>=1.0.0", "wheel", "Cython>=3.0.0", "setuptools"]
requires = ["poetry-core>=1.0.0", "wheel", "Cython>=3.0.0", "setuptools", "setuptools-scm>=8.0"]
build-backend = "poetry.core.masonry.api"

[tool.poetry.build]
generate-setup-file = false
script = "build-module.py"

[tool.setuptools_scm]
write_to = "pyiceberg/_version.py"
write_to_template = """# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# Generated by setuptools_scm

__version__ = "{version}"
__version_tuple__ = {version_tuple}
"""
git_describe_command = "git describe --dirty --tags --long --match '*[0-9]*'"

[tool.poetry.extras]
pyarrow = ["pyarrow", "pyiceberg-core"]
pandas = ["pandas", "pyarrow"]
Expand Down Expand Up @@ -535,5 +560,9 @@ ignore_missing_imports = true
module = "pyroaring.*"
ignore_missing_imports = true

[[tool.mypy.overrides]]
module = "pyiceberg._version"
ignore_missing_imports = true

[tool.coverage.run]
source = ['pyiceberg/']
21 changes: 21 additions & 0 deletions tests/catalog/test_rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,27 @@ def test_config_sets_headers(requests_mock: Mocker) -> None:
)


def test_client_version_headers(requests_mock: Mocker) -> None:
import re

from pyiceberg import __version__

requests_mock.get(
f"{TEST_URI}v1/config",
json={"defaults": {}, "overrides": {}},
status_code=200,
)

catalog = RestCatalog("rest", uri=TEST_URI, warehouse="s3://some-bucket")

assert catalog._session.headers.get("X-Client-Version") == __version__
assert "X-Client-Git-Commit-Short" in catalog._session.headers
git_commit = catalog._session.headers.get("X-Client-Git-Commit-Short")
assert git_commit is not None
assert isinstance(git_commit, str)
assert re.match(r"^[0-9a-f]{7}$", git_commit), f"Expected 7-char hex git hash, got: {git_commit}"


@pytest.mark.filterwarnings(
"ignore:Deprecated in 0.8.0, will be removed in 1.0.0. Iceberg REST client is missing the OAuth2 server URI:DeprecationWarning"
)
Expand Down