Skip to content

Backport StrEnum + replace enum imports, normalize retry APIs, and add async pytest hook#1

Draft
HrachShah wants to merge 1 commit into
mainfrom
codex/find-stars-or-downloads-for-project
Draft

Backport StrEnum + replace enum imports, normalize retry APIs, and add async pytest hook#1
HrachShah wants to merge 1 commit into
mainfrom
codex/find-stars-or-downloads-for-project

Conversation

@HrachShah

@HrachShah HrachShah commented Apr 8, 2026

Copy link
Copy Markdown
Owner

Motivation

  • Ensure consistent StrEnum availability across supported Python runtimes by providing a small backport for pre-3.11 environments.
  • Remove repeated local imports of enum.StrEnum and centralize compatibility to avoid runtime import errors on older interpreters.
  • Standardize retry helper signatures to use concrete coroutine factories and clearer parameter names for safer retries.
  • Improve test ergonomics for async tests by adding a lightweight pytest hook so coroutine tests can run even without pytest-asyncio installed.

Description

  • Added freerelay/_compat.py which backports StrEnum for Python < 3.11 and exports it for internal use.
  • Replaced scattered from enum import StrEnum and related enum usages with from freerelay._compat import StrEnum across multiple modules (control_plane, data_plane, core, shared, skills, etc.).
  • Updated retry utilities to accept coroutine factories and simplified function signatures by removing generic type parameterization and renaming parameters for clarity (func -> coro_factory), in core/execution/retry.py and data_plane/execution/retry.py.
  • Updated README.md with additional badges and a short "Support FreeRelay" snippet.
  • Adjusted pyproject.toml pytest config by removing asyncio_mode and adding a markers entry for local async tests.
  • Added tests/conftest.py implementing pytest_pyfunc_call to run coroutine test functions with asyncio.run when pytest-asyncio is not available.

Testing

  • Ran the test suite with pytest -q using the new local hook to execute coroutine tests, and the run completed successfully.

Codex Task

Summary by Sourcery

Introduce a StrEnum compatibility layer, align internal usages to it, streamline retry helpers, and improve async testing and project documentation.

New Features:

  • Add a _compat module providing a StrEnum backport for Python versions earlier than 3.11.
  • Introduce a pytest hook that automatically runs async test functions with asyncio.run when pytest-asyncio is not installed.

Enhancements:

  • Replace direct enum.StrEnum imports across models, execution, and resilience modules with the shared StrEnum from the compatibility layer for consistent runtime behavior.
  • Simplify retry helper function signatures in core and data_plane execution modules by removing generic type parameterization and standardizing coroutine factory arguments.
  • Update README with a GitHub stars badge, support call-to-action, and a reusable team documentation snippet.
  • Adjust pytest configuration to declare an asyncio marker for async tests managed by the local hook.

Tests:

  • Add a tests conftest module implementing pytest_pyfunc_call to support running coroutine tests without pytest-asyncio.

@coderabbitai

coderabbitai Bot commented Apr 8, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: edf7790c-4800-43cc-b1fc-2b6574934202

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/find-stars-or-downloads-for-project

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sourcery-ai

sourcery-ai Bot commented Apr 8, 2026

Copy link
Copy Markdown

Reviewer's Guide

Backports and centralizes a StrEnum implementation for compatibility across Python versions, standardizes retry helper APIs, and improves async test support while also making minor README and pytest configuration updates.

Sequence diagram for retry_with_config and retry_with_backoff

sequenceDiagram
    participant Caller
    participant RetryAPI as retry_with_config
    participant Backoff as retry_with_backoff
    participant CFactory as coro_factory

    Caller->>RetryAPI: call(coro_factory, config, on_retry)
    RetryAPI->>Backoff: retry_with_backoff(coro_factory, config.max_retries, config.base_delay, config.max_delay, on_retry)
    loop up_to_max_retries
        Backoff->>CFactory: create coroutine
        CFactory-->>Backoff: coroutine
        Backoff->>CFactory: await coroutine
        alt success
            Backoff-->>RetryAPI: result
            RetryAPI-->>Caller: result
            Backoff->>Backoff: break
        else retryable_exception
            Backoff->>RetryAPI: notify on_retry(retry_count, exception)
            RetryAPI-->>Backoff: ack
            Backoff->>Backoff: compute_next_delay_with_jitter()
            Backoff->>Backoff: asyncio.sleep(delay)
        else non_retryable_exception
            Backoff-->>RetryAPI: raise exception
            RetryAPI-->>Caller: propagate exception
            Backoff->>Backoff: break
        end
    end
Loading

Sequence diagram for pytest async test execution via local hook

sequenceDiagram
    actor Dev as Developer
    participant Pytest as pytest_runner
    participant Hook as pytest_pyfunc_call
    participant TestFunc as async_test
    participant AsyncIO as asyncio_run

    Dev->>Pytest: run tests
    Pytest->>Hook: pytest_pyfunc_call(pyfuncitem)
    alt test_is_coroutine_function and pytest_asyncio_not_installed
        Hook->>AsyncIO: asyncio.run(TestFunc())
        AsyncIO-->>Hook: test_result
        Hook-->>Pytest: handled
    else not_coroutine_or_other_plugin_handles
        Hook-->>Pytest: fall_through
        Pytest->>TestFunc: call synchronously
        TestFunc-->>Pytest: test_result
    end
    Pytest-->>Dev: report results
Loading

Class diagram for StrEnum backport and enum users

classDiagram
    class Enum
    class StrEnum {
    }
    class TaskFamily {
      <<enum>>
      CHAT
      COMPLETION
      EMBEDDING
      EVAL
      AGENT_LOOP
    }
    class Depth {
      <<enum>>
      SHALLOW
      MEDIUM
      DEEP
    }
    class Sensitivity {
      <<enum>>
      LOW
      MEDIUM
      HIGH
    }
    class LatencyClass {
      <<enum>>
      INTERACTIVE
      NEARLINE
      BATCH
    }
    class ContextTopology {
      <<enum>>
      SHORT
      LONG
      MULTI_TURN
      MULTIMODAL
    }
    class ToolDependence {
      <<enum>>
      NONE
      OPTIONAL
      MANDATORY
    }
    class Determinism {
      <<enum>>
      LOW
      MEDIUM
      STRICT
    }
    class SafetyPosture {
      <<enum>>
      PERMISSIVE
      STANDARD
      LOCKED_DOWN
    }
    class OutputContract {
      <<enum>>
      PROSE
      JSON
      TOOL_CALLS
    }
    class EconomicPolicy {
      <<enum>>
      CHEAPEST
    }
    class CircuitState {
      <<enum>>
      CLOSED
    }
    class BenchmarkType {
      <<enum>>
      JSON_SCHEMA
    }

    Enum <|-- StrEnum
    StrEnum <|-- TaskFamily
    StrEnum <|-- Depth
    StrEnum <|-- Sensitivity
    StrEnum <|-- LatencyClass
    StrEnum <|-- ContextTopology
    StrEnum <|-- ToolDependence
    StrEnum <|-- Determinism
    StrEnum <|-- SafetyPosture
    StrEnum <|-- OutputContract
    StrEnum <|-- EconomicPolicy
    StrEnum <|-- CircuitState
    StrEnum <|-- BenchmarkType

    class CompatModule {
      _compat
      +StrEnum
    }
    CompatModule ..> StrEnum
Loading

Flow diagram for async test marker and local hook interaction

flowchart LR
    A["Async test function
marked with asyncio"] --> B["pytest collects tests
using testpaths"]
    B --> C["pytest_pyfunc_call hook
in tests.conftest"]
    C --> D{Is function
coroutine?}
    D -->|no| E["Run test normally"]
    D -->|yes| F{pytest-asyncio
installed?}
    F -->|yes| G["Let pytest-asyncio
manage async execution"]
    F -->|no| H["Use asyncio.run
on coroutine"]
    G --> I["Test result"]
    H --> I
    E --> I
    I --> J["Report outcome
in pytest summary"]
Loading

File-Level Changes

Change Details Files
Introduce a central StrEnum compatibility layer and update enums to use it.
  • Added a new _compat module that conditionally exposes StrEnum, using the stdlib on Python 3.11+ and a small backport otherwise.
  • Replaced direct imports of enum.StrEnum or enum usage for string enums with imports from the new compatibility module across control_plane, data_plane, core, shared, and skills packages.
  • Updated enum class definitions (e.g., TaskFamily, CircuitState, BenchmarkType, and other internal enums) to inherit from the centralized StrEnum.
freerelay/_compat.py
freerelay/shared/models/internal.py
freerelay/shared/models/capability.py
freerelay/core/resilience/circuit_breaker.py
freerelay/data_plane/execution/cancellation.py
freerelay/skills/__init__.py
freerelay/control_plane/benchmark/suite.py
freerelay/control_plane/experiments/ab_router.py
freerelay/control_plane/leaderboard/models.py
freerelay/control_plane/topology/__init__.py
freerelay/data_plane/execution/dag_engine.py
freerelay/data_plane/routing/policy.py
Normalize retry helper function APIs to use coroutine factories and simpler signatures.
  • Removed generic type parameter syntax from async retry_with_backoff and retry_with_config definitions for better compatibility and readability.
  • Standardized retry helpers to accept a zero-arg coroutine factory (coro_factory/func) instead of a bare coroutine for safer retries and easier reuse.
  • Adjusted retry configuration usage to pass RetryConfig objects and on_retry hooks into the new signatures in both core and data_plane retry modules.
freerelay/core/execution/retry.py
freerelay/data_plane/execution/retry.py
Add a local pytest hook to run async tests without pytest-asyncio and align pytest configuration.
  • Introduced a tests/conftest.py defining pytest_pyfunc_call that detects coroutine test functions and runs them via asyncio.run with resolved fixtures.
  • Updated pytest configuration in pyproject.toml by removing asyncio_mode and adding an asyncio marker for async tests to document the local hook behavior.
tests/conftest.py
pyproject.toml
Refresh documentation to encourage community support and expose repository engagement status.
  • Added a GitHub stars badge alongside existing CI and metadata badges in the README header.
  • Inserted a centered call-to-action block with links to star the repo and open issues.
  • Added a 'Support FreeRelay' section with guidance for users to star the repo and a copy-paste team docs snippet.
README.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant