Skip to content

Conversation

@patrick91
Copy link
Member

@patrick91 patrick91 commented Oct 26, 2025

Summary by Sourcery

Introduce an optimized awaitable detection helper and wire it into schema execution to improve performance on large, mostly-synchronous result sets.

Enhancements:

  • Add an optimized_is_awaitable utility that short-circuits checks for common non-awaitable primitive and container types before delegating to graphql-core.
  • Update async and sync schema execution paths to use the optimized awaitable checker when invoking the GraphQL execution engine.
  • Expose optimized_is_awaitable via the strawberry.execution package for reuse across the codebase.

Chores:

  • Add a new uv.lock file to the repository.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Oct 26, 2025

Reviewer's Guide

Adds a new optimized is_awaitable helper and wires it into the async and sync execution paths to reduce overhead when checking awaitables during GraphQL execution, exposing it via the execution utilities package.

File-Level Changes

Change Details Files
Introduce an optimized is_awaitable implementation focused on fast-path handling of common non-awaitable primitive and collection types.
  • Create a new execution.is_awaitable module defining optimized_is_awaitable
  • Maintain an internal frozenset of common non-awaitable types for O(1) type checks
  • Delegate to graphql-core's is_awaitable for values not covered by the fast-path set
  • Document performance characteristics and behavior of the new helper
strawberry/execution/is_awaitable.py
Expose the optimized is_awaitable helper from the execution package.
  • Add execution package init that re-exports optimized_is_awaitable via all
strawberry/execution/__init__.py
Integrate the optimized is_awaitable into schema execution for both async and sync code paths.
  • Pass optimized_is_awaitable into the async execute function when creating the execution context
  • Pass optimized_is_awaitable into the sync execute_sync function when creating the execution context
strawberry/schema/schema.py
Introduce a new lockfile to the repository.
  • Add uv.lock file to version control (contents not shown in diff)
uv.lock

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

@codecov
Copy link

codecov bot commented Oct 26, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.30%. Comparing base (f3b494c) to head (dd8351d).
⚠️ Report is 9 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4035   +/-   ##
=======================================
  Coverage   94.30%   94.30%           
=======================================
  Files         541      543    +2     
  Lines       35641    35653   +12     
  Branches     1884     1885    +1     
=======================================
+ Hits        33610    33622   +12     
  Misses       1714     1714           
  Partials      317      317           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@codspeed-hq
Copy link

codspeed-hq bot commented Oct 26, 2025

Merging this PR will improve performance by 10.52%

⚡ 2 improved benchmarks
✅ 29 untouched benchmarks

Performance Changes

Benchmark BASE HEAD Efficiency
test_stadium[seats_per_row_500] 13.3 s 12 s +10.52%
test_stadium[seats_per_row_250] 6.6 s 6 s +10.41%

Comparing test-is-awaitable (dd8351d) with main (f3b494c)

Open in CodSpeed

Instead of duplicating the awaitable detection logic from graphql-core,
import and use their is_awaitable function as a fallback. This keeps
the fast path for common non-awaitable types while reducing code
duplication and ensuring we stay in sync with graphql-core.
@patrick91 patrick91 marked this pull request as ready for review January 14, 2026 20:54
@botberry
Copy link
Member

botberry commented Jan 14, 2026

Thanks for adding the RELEASE.md file!

Here's a preview of the changelog:


Improved execution performance by up to 10% by adding an optimized is_awaitable check with a fast path for common synchronous types (such as int, str, list, dict, etc.).

This optimization reduces overhead when processing large result sets containing mostly basic values by avoiding expensive awaitable checks for types that are known to never be awaitable.

Here's the tweet text:

🆕 Release (next) is out! Thanks to @patrick91 for the PR 👏

Get it here 👉 https://strawberry.rocks/release/(next)

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `strawberry/execution/is_awaitable.py:18-27` </location>
<code_context>
+
+# Common synchronous types that are never awaitable
+# Using a frozenset for O(1) lookup
+_NON_AWAITABLE_TYPES: frozenset[type] = frozenset(
+    {
+        type(None),
+        bool,
+        int,
+        float,
+        str,
+        bytes,
+        bytearray,
+        list,
+        tuple,
+        dict,
+        set,
+        frozenset,
+    }
+)
+
</code_context>

<issue_to_address>
**suggestion (performance):** Expand the fast-path set to cover additional common primitive/iterable types

You’ve covered many common built-ins, but types like `complex`, `range`, and `memoryview` are also frequent non-awaitable primitives/iterables that will still hit `graphql_core_is_awaitable`. Consider adding them to `_NON_AWAITABLE_TYPES` to further reduce fall-through in numeric/iterator-heavy code paths without changing behavior, since these types can’t be awaitable.

Suggested implementation:

```python
# Common synchronous types that are never awaitable
# Using a frozenset for O(1) lookup
_NON_AWAITABLE_TYPES: frozenset[type] = frozenset(
    {
        type(None),
        bool,
        int,
        float,
        complex,
        str,
        bytes,
        bytearray,
        memoryview,
        range,
        list,
        tuple,
        dict,
        set,
        frozenset,
    }
)

```

If `_NON_AWAITABLE_TYPES` is referenced elsewhere in this file (e.g., inside `optimized_is_awaitable`), no further changes are required. If a different constant name was used in other parts of the PR, those references should be updated to `_NON_AWAITABLE_TYPES` for consistency.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 14, 2026

Greptile Summary

Added an optimized is_awaitable helper that provides a fast-path check for common synchronous types (int, str, list, dict, etc.) before delegating to graphql-core's implementation. The optimization is cleanly integrated into both async and sync execution paths in schema.py by passing optimized_is_awaitable to the GraphQL execution engine via the is_awaitable parameter.

  • Introduced strawberry/execution/is_awaitable.py with optimized_is_awaitable() function that checks against a frozenset of non-awaitable types for O(1) lookup
  • Wired the optimization into Schema.execute() and Schema.execute_sync() methods
  • Exposed the utility via strawberry.execution package for reusability
  • Clean implementation that maintains correctness by falling back to graphql-core for non-primitive types
  • Performance improvement of up to 10% on queries returning large result sets with mostly primitive values

Confidence Score: 5/5

  • This PR is safe to merge with no risk
  • The implementation is simple, well-documented, and correctly delegates to graphql-core for non-primitive types. The optimization only adds a fast-path check that never changes behavior, just improves performance. Integration points are minimal and follow existing patterns.
  • No files require special attention

Important Files Changed

Filename Overview
strawberry/execution/is_awaitable.py Adds optimized is_awaitable with fast-path for common synchronous types; clean implementation with proper fallback
strawberry/execution/init.py New module exports optimized_is_awaitable utility; straightforward package initialization
strawberry/schema/schema.py Integrates optimized_is_awaitable into both async and sync execution paths via is_awaitable parameter

Sequence Diagram

sequenceDiagram
    participant Client
    participant Schema
    participant execute/execute_sync
    participant optimized_is_awaitable
    participant graphql_core_is_awaitable
    
    Client->>Schema: execute() or execute_sync()
    Schema->>Schema: Import optimized_is_awaitable
    Schema->>execute/execute_sync: Call with is_awaitable=optimized_is_awaitable
    
    loop For each result value in GraphQL execution
        execute/execute_sync->>optimized_is_awaitable: Check if value is awaitable
        
        alt Value is primitive (int/str/list/dict/etc)
            optimized_is_awaitable->>optimized_is_awaitable: type(value) in _NON_AWAITABLE_TYPES
            optimized_is_awaitable-->>execute/execute_sync: Return False (fast path)
        else Value is other type
            optimized_is_awaitable->>graphql_core_is_awaitable: Delegate to graphql-core
            graphql_core_is_awaitable-->>optimized_is_awaitable: Return awaitable check result
            optimized_is_awaitable-->>execute/execute_sync: Return result
        end
    end
    
    execute/execute_sync-->>Schema: Return execution result
    Schema-->>Client: Return GraphQL response
Loading

@patrick91 patrick91 requested a review from bellini666 January 14, 2026 21:13
Copy link
Member

@bellini666 bellini666 left a comment

Choose a reason for hiding this comment

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

Image

@patrick91 patrick91 merged commit db5401a into main Jan 19, 2026
89 checks passed
@patrick91 patrick91 deleted the test-is-awaitable branch January 19, 2026 22:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants