diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 28009144..8b55e9af 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,7 +3,7 @@ name: CI on: push env: - PYTHON_VERSIONS: '[ "3.9", "3.10", "3.11", "3.12", "3.13.3" ]' + PYTHON_VERSIONS: '[ "3.10", "3.11", "3.12", "3.13.3" ]' jobs: @@ -25,10 +25,10 @@ jobs: python-version: ${{ fromJSON(needs.set-python-matrix.outputs.python_versions) }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} @@ -48,10 +48,10 @@ jobs: python-version: ${{ fromJSON(needs.set-python-matrix.outputs.python_versions) }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} @@ -103,11 +103,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v6 with: - python-version: 3.9 + python-version: '3.10' - name: Install dependencies run: pip install -U setuptools wheel build @@ -131,7 +131,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - name: Build run: make docs diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b8478a7..9eaf17fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.1.0] - 2026-01-15 +### Dependency +- Upgraded internal dependency `redis` to version `redis >=7.1.0, <8.0.0` +- Bumped a supported SDK runtime version to minimum `3.10` since new redis lib drops support for `3.9` + + +## [2.0.4] - 2026-01-14 +### Security +- Upgraded internal dependency `urllib3` to version `urllib3 >= 2.6.3, <3.0.0` since `2.5.0` has [these](https://security.snyk.io/package/pip/urllib3/2.5.0) vulnerabilities +### Fixed +- Fixed issue with `MAX_RETRY_COUNT` + + ## [2.0.3] - 2025-12-08 ### Fixed - Fix some deprecation warnings raised by Pydantic V2 diff --git a/docs/antora-playbook.yml b/docs/antora-playbook.yml index 88fcfc86..f4c95352 100644 --- a/docs/antora-playbook.yml +++ b/docs/antora-playbook.yml @@ -7,7 +7,7 @@ content: start_path: docs branches: [] # branches: HEAD # Use this for local development - tags: [v2.0.3] + tags: [v2.1.0] asciidoc: attributes: page-toclevels: 5 diff --git a/docs/antora.yml b/docs/antora.yml index da9cec15..29f1b0f3 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -1,3 +1,3 @@ name: corva-sdk -version: ~ +version: 2.1.0 nav: [modules/ROOT/nav.adoc] diff --git a/pyproject.toml b/pyproject.toml index bed1b888..81d4fca0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,20 +6,20 @@ build-backend = "setuptools.build_meta" name = "corva-sdk" description = "SDK for building Corva DevCenter Python apps." readme = "README.md" -version = "2.0.3" +version = "2.1.0" license = { text = "The Unlicense" } authors = [ { name = "Jordan Ambra", email = "jordan.ambra@corva.ai" } ] keywords = ["corva", "sdk"] -requires-python = ">=3.9,<4.0" +requires-python = ">=3.10,<4.0" dependencies = [ "fakeredis >= 2.30.0, <2.32.0", "pydantic >= 2.0, <3.0", "pydantic-settings >= 2.0, <3.0", - "redis == 6.4.0", + "redis >=7.1.0, <8.0.0", "requests >= 2.32.3, <3.0.0", - "urllib3 == 2.5.0", + "urllib3 >= 2.6.3, <3.0.0", "semver == 3.0.4" ] classifiers = [ diff --git a/src/corva/configuration.py b/src/corva/configuration.py index 6d9e11a3..c4eb8c9c 100644 --- a/src/corva/configuration.py +++ b/src/corva/configuration.py @@ -1,16 +1,44 @@ import datetime +import logging import pydantic_settings from pydantic import AnyHttpUrl, BeforeValidator, TypeAdapter from typing_extensions import Annotated +logger = logging.getLogger("corva") + def validate_http_url_to_str(v: str) -> str: TypeAdapter(AnyHttpUrl).validate_python(v) return v +def _parse_max_retry_count(value) -> int: + + if value is None or value == "": + return DEFAULT_MAX_RETRY_COUNT + try: + if isinstance(value, bool): + raise TypeError + if isinstance(value, int): + return value + if isinstance(value, str): + return int(value.strip()) + except (TypeError, ValueError): + pass + + logger.warning( + "Invalid MAX_RETRY_COUNT value %r; using default %d.", + value, + DEFAULT_MAX_RETRY_COUNT, + ) + return DEFAULT_MAX_RETRY_COUNT + + HttpUrlStr = Annotated[str, BeforeValidator(validate_http_url_to_str)] +MaxRetryValidator = Annotated[int, BeforeValidator(lambda v: _parse_max_retry_count(v))] + +DEFAULT_MAX_RETRY_COUNT = 3 class Settings(pydantic_settings.BaseSettings): @@ -39,8 +67,8 @@ class Settings(pydantic_settings.BaseSettings): POOL_MAX_SIZE: int = 20 # Max connections count per pool/host POOL_BLOCK: bool = True # Wait until connection released - # retry - MAX_RETRY_COUNT: int = 3 # If `0` then retries will be disabled + # retry. If `0` then retries will be disabled + MAX_RETRY_COUNT: MaxRetryValidator = DEFAULT_MAX_RETRY_COUNT BACKOFF_FACTOR: float = 1.0 # OTEL diff --git a/src/version.py b/src/version.py index c129f683..127c148a 100644 --- a/src/version.py +++ b/src/version.py @@ -1 +1 @@ -VERSION = "2.0.3" +VERSION = "2.1.0"