Skip to content

Commit

Permalink
Fix version checker (#2080)
Browse files Browse the repository at this point in the history
  • Loading branch information
haakonvt authored Jan 6, 2025
1 parent 49c87bd commit cd4d2c2
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 103 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ Changes are grouped as follows
- `Fixed` for any bug fixes.
- `Security` in case of vulnerabilities.


## [7.71.1] - 2025-01-07
### Fixed
- Version checker (stopped working after 5.3.1 due to subtle package naming change)

## [7.71.0] - 2025-01-06
### Added
- Support for InstanceReferences filter for Data Modeling
Expand Down
2 changes: 1 addition & 1 deletion cognite/client/_version.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from __future__ import annotations

__version__ = "7.71.0"
__version__ = "7.71.1"

__api_subversion__ = "20230101"
9 changes: 3 additions & 6 deletions cognite/client/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import pprint
import re
import warnings
from contextlib import suppress
from typing import Any

from cognite.client._version import __api_subversion__
Expand Down Expand Up @@ -142,16 +141,14 @@ def __init__(
self.headers = headers or {}
self.timeout = timeout or 30
self.file_transfer_timeout = file_transfer_timeout or 600

if debug:
self.debug = True
self._validate_config()

if not global_config.disable_pypi_version_check:
with suppress(Exception): # PyPI might be unreachable, if so, skip version check
from cognite.client.utils._auxiliary import _check_client_has_newest_major_version
from cognite.client.utils._version_checker import check_client_is_running_latest_version

_check_client_has_newest_major_version()
self._validate_config()
check_client_is_running_latest_version()

@property
def max_workers(self) -> int:
Expand Down
20 changes: 0 additions & 20 deletions cognite/client/utils/_auxiliary.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import platform
import warnings
from collections.abc import Hashable, Iterable, Iterator, Sequence
from threading import Thread
from typing import (
TYPE_CHECKING,
Any,
Expand All @@ -23,7 +22,6 @@
to_camel_case,
to_snake_case,
)
from cognite.client.utils._version_checker import get_newest_version_in_major_release
from cognite.client.utils.useful_types import SequenceNotStr

if TYPE_CHECKING:
Expand Down Expand Up @@ -158,24 +156,6 @@ def get_user_agent() -> str:
return f"{sdk_version} {python_version} {operating_system}"


# Wrap in a cache to ensure we only ever run the version check once.
@functools.lru_cache(1)
def _check_client_has_newest_major_version() -> None:
def run() -> None:
version = get_current_sdk_version()
newest_version = get_newest_version_in_major_release("cognite-sdk", version)
if newest_version != version:
warnings.warn(
f"You are using {version=} of the SDK, however version='{newest_version}' is available. "
"To suppress this warning, either upgrade or do the following:\n"
">>> from cognite.client.config import global_config\n"
">>> global_config.disable_pypi_version_check = True",
stacklevel=3,
)

Thread(target=run, daemon=True).start()


@overload
def split_into_n_parts(seq: list[T], *, n: int) -> Iterator[list[T]]: ...

Expand Down
98 changes: 27 additions & 71 deletions cognite/client/utils/_version_checker.py
Original file line number Diff line number Diff line change
@@ -1,89 +1,45 @@
from __future__ import annotations

import argparse
import functools
import re
import warnings
from contextlib import suppress
from threading import Thread

import requests
from packaging import version


def check_if_version_exists(package_name: str, version: str) -> bool:
versions = get_all_versions(package_name=package_name)
return version in versions


@functools.lru_cache(maxsize=1)
def get_newest_version_in_major_release(package_name: str, version: str) -> str:
major, minor, micro, pr_cycle, pr_version = _parse_version(version)
versions = get_all_versions(package_name)
for v in versions:
if _is_newer_major(v, version):
major, minor, micro, pr_cycle, pr_version = _parse_version(v)
return _format_version(major, minor, micro, pr_cycle, pr_version)


def get_all_versions(package_name: str) -> list[str]:
def get_all_sdk_versions() -> list[version.Version]:
from cognite.client.config import global_config

verify_ssl = not global_config.disable_ssl
res = requests.get(f"https://pypi.python.org/simple/{package_name}/#history", verify=verify_ssl, timeout=5)
return re.findall(r"cognite-sdk-(\d+\.\d+.[\dabrc]+)", res.content.decode())


def _is_newer_major(version_a: str, version_b: str) -> bool:
major_a, minor_a, micro_a, pr_cycle_a, pr_version_a = _parse_version(version_a)
major_b, minor_b, micro_b, pr_cycle_b, pr_version_b = _parse_version(version_b)
is_newer = False
if major_a == major_b and minor_a >= minor_b and micro_a >= micro_b:
if minor_a > minor_b:
is_newer = True
else:
if micro_a > micro_b:
is_newer = True
else:
is_newer = _is_newer_pre_release(pr_cycle_a, pr_version_a, pr_cycle_b, pr_version_b)
return is_newer


def _is_newer_pre_release(
pr_cycle_a: str | None, pr_v_a: int | None, pr_cycle_b: str | None, pr_v_b: int | None
) -> bool:
cycles = ["a", "b", "rc", None]
if pr_cycle_a not in cycles:
raise RuntimeError(f"pr_cycle_a must be one of '{pr_cycle_a}', not '{cycles}'.")
if pr_cycle_b not in cycles:
raise RuntimeError(f"pr_cycle_a must be one of '{pr_cycle_b}', not '{cycles}'.")
is_newer = False
if cycles.index(pr_cycle_a) > cycles.index(pr_cycle_b):
is_newer = True
elif cycles.index(pr_cycle_a) == cycles.index(pr_cycle_b):
if pr_v_a is not None and pr_v_b is not None and pr_v_a > pr_v_b:
is_newer = True
return is_newer

res = requests.get("https://pypi.org/simple/cognite-sdk/", verify=verify_ssl, timeout=5)
return list(map(version.parse, re.findall(r"cognite[_-]sdk-(\d+\.\d+.[\dabrc]+)", res.text)))

def _parse_version(version: str) -> tuple[int, int, int, str, int | None]:
pattern = r"(\d+)\.(\d+)\.(\d+)(?:([abrc]+)(\d+))?"
match = re.match(pattern, version)
if not match:
raise ValueError(f"Could not parse version {version}")
major, minor, micro, pr_cycle, pr_version = match.groups()
return int(major), int(minor), int(micro), pr_cycle, int(pr_version) if pr_version else None

def get_latest_released_stable_version() -> version.Version:
# Filter only stable versions (no pre-releases or dev releases, but post-releases are ok)
return max(v for v in get_all_sdk_versions() if not v.is_prerelease)

def _format_version(major: int, minor: int, micro: int, pr_cycle: str | None, pr_version: int | None) -> str:
return f"{major}.{minor}.{micro}{pr_cycle or ''}{pr_version or ''}"

# Wrap in a cache to ensure we only ever run the version check once.
@functools.cache
def check_client_is_running_latest_version() -> None:
def run() -> None:
from packaging import version

if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-p", "--package", required=True)
parser.add_argument("-v", "--version", required=True)
args = parser.parse_args()
from cognite.client import __version__

version_exists = check_if_version_exists(args.package, args.version)
with suppress(Exception): # PyPI might be unreachable, if so, skip version check
newest_version = get_latest_released_stable_version()
if version.parse(__version__) < newest_version:
warnings.warn(
f"You are using version={__version__!r} of the SDK, however version={newest_version.public!r} is "
"available. To suppress this warning, either upgrade or do the following:\n"
">>> from cognite.client.config import global_config\n"
">>> global_config.disable_pypi_version_check = True",
stacklevel=3,
)

if version_exists:
print("yes") # noqa: T201
else:
print("no") # noqa: T201
Thread(target=run, daemon=True).start()
8 changes: 4 additions & 4 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tool.poetry]
name = "cognite-sdk"

version = "7.71.0"
version = "7.71.1"

description = "Cognite Python SDK"
readme = "README.md"
Expand All @@ -26,6 +26,7 @@ requests = "^2.27"
requests_oauthlib = "^1"
msal = "^1.31"
protobuf = ">=4"
packaging = ">=20"
pip = ">=20.0.0" # make optional once poetry doesn't auto-remove it on "simple install"
typing_extensions = ">= 4"
# Windows does not have a ANSI database and need tzdata... pyodide also needs it:
Expand Down

0 comments on commit cd4d2c2

Please sign in to comment.