Skip to content

Add support for Python 3.14 #3828

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open

Add support for Python 3.14 #3828

wants to merge 12 commits into from

Conversation

patrick91
Copy link
Member

@patrick91 patrick91 commented Apr 1, 2025

Description

Types of Changes

  • Core
  • Bugfix
  • New feature
  • Enhancement/optimization
  • Documentation

Issues Fixed or Closed by This PR

Checklist

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • I have tested the changes and verified that they work and don't break anything (as well as I can manage).

Summary by Sourcery

Add support for Python 3.14 by updating test environments, applying compatibility fixes, and publishing a release announcement.

Bug Fixes:

  • Include the required doc keyword for dataclass fields on Python 3.14

Enhancements:

  • Add an optional codeflash dependency group in pyproject.toml
  • Bump graphql-core version requirement to 3.2.6

CI:

  • Update noxfile and GitHub Actions workflow to include Python 3.14 in the test matrix

Documentation:

  • Add TWEET.md to announce the new release with Python 3.14 support

Copy link
Contributor

sourcery-ai bot commented Apr 1, 2025

Reviewer's Guide

This PR enables Python 3.14 support by updating CI workflows and test sessions, adapting code compatibility, bumping test dependencies, extending poetry configuration, and adding a release announcement template.

Class diagram for Field class Python 3.14 compatibility update

classDiagram
    class Field {
        <<dataclass>>
        +__init__(...)
        +default
        +default_factory
        +doc  <<added in 3.14>>
    }
Loading

File-Level Changes

Change Details Files
Extend testing to Python 3.14 across CI and nox
  • Include 3.14-dev in GitHub Actions test matrix
  • Prepend 3.14 to nox PYTHON_VERSIONS
.github/workflows/test.yml
noxfile.py
Update GraphQL core version in test sessions
  • Bump GQL_CORE_VERSIONS from 3.2.3 to 3.2.6
noxfile.py
Add doc parameter for dataclasses in Python 3.14
  • Set kwargs['doc'] = None for Python >=3.14
strawberry/types/field.py
Enhance poetry configuration with optional codeflash group
  • Add tool.poetry.group.codeflash section and dependencies
pyproject.toml
Introduce TWEET.md release announcement template
  • Add stub for release tweet with placeholders
TWEET.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

Copy link

codecov bot commented Apr 1, 2025

Codecov Report

Attention: Patch coverage is 75.00000% with 2 lines in your changes missing coverage. Please review.

Project coverage is 94.75%. Comparing base (79214e6) to head (f14a729).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3828      +/-   ##
==========================================
- Coverage   94.76%   94.75%   -0.01%     
==========================================
  Files         520      520              
  Lines       33951    33953       +2     
  Branches     1759     1760       +1     
==========================================
  Hits        32172    32172              
- Misses       1497     1498       +1     
- Partials      282      283       +1     
🚀 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.

Copy link

codspeed-hq bot commented Apr 1, 2025

CodSpeed Performance Report

Merging #3828 will not alter performance

Comparing feature/314 (f14a729) with main (79214e6)

Summary

✅ 26 untouched benchmarks

@botberry
Copy link
Member

botberry commented Jul 15, 2025

Apollo Federation Subgraph Compatibility Results

Federation 1 Support Federation 2 Support
_service🟢
@key (single)🟢
@key (multi)🟢
@key (composite)🟢
repeatable @key🟢
@requires🟢
@provides🟢
federated tracing🔲
@link🟢
@shareable🟢
@tag🟢
@override🟢
@inaccessible🟢
@composeDirective🟢
@interfaceObject🟢

Learn more:

@bellini666
Copy link
Member

It seems that we have 2 issues here:

  1. TypeError: Field.__init__() missing 1 required positional argument: 'doc'

the new field api has an optional doc keyword, which we need to add there.

Wondering if we should add doc and deprecate description? Wdyt? As field has doc now, it seems a good kw to retrieve it =P

  1. ImportError: cannot import name 'ByteString' from 'typing'

This is an issue from graphql-core, which has been fixed for 3.3.x.

Should we mark 3.14 only available with graphql-core 3.3.x+? Otherwise we might need to ask Cito to backport the fix to 3.2.x

@patrick91
Copy link
Member Author

It seems that we have 2 issues here:

  1. TypeError: Field.__init__() missing 1 required positional argument: 'doc'

the new field api has an optional doc keyword, which we need to add there.

Wondering if we should add doc and deprecate description? Wdyt? As field has doc now, it seems a good kw to retrieve it =P

Mmh, I don't really like doc :D I think I'd keep the same behaviour as it is now (so just passing None)

  1. ImportError: cannot import name 'ByteString' from 'typing'

This is an issue from graphql-core, which has been fixed for 3.3.x.

Should we mark 3.14 only available with graphql-core 3.3.x+? Otherwise we might need to ask Cito to backport the fix to 3.2.x

I'll make a PR to GraphQL-core, not sure when 3.3 will be released (I think it depends on GraphQL js)

@patrick91 patrick91 marked this pull request as ready for review July 16, 2025 22:28
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 @patrick91 - I've reviewed your changes and they look great!

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

### Comment 1
<location> `TWEET.md:3` </location>
<code_context>
+🆕 Release $version is out! Thanks to $contributor for the PR 👏
+
+This releases adds support for Python 3.14!
+
+Get it here 👉 $release_url
</code_context>

<issue_to_address>
Typo: 'releases' should be 'release'.

It should read: 'This release adds support for Python 3.14!'.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
This releases adds support for Python 3.14!
=======
This release adds support for Python 3.14!
>>>>>>> REPLACE

</suggested_fix>

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.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Summary

This PR adds support for Python 3.14 across the Strawberry GraphQL codebase through several key changes:

  1. Added compatibility for Python 3.14's dataclasses.Field by handling the new required 'doc' parameter
  2. Updated CI configuration to test against Python 3.14-dev
  3. Dropped Python 3.9 support and updated graphql-core dependency to 3.2.6
  4. Added an optional codeflash dependency group in pyproject.toml

The most significant change is in strawberry/types/field.py where a version check was added to handle Python 3.14's new required 'doc' parameter for dataclasses.Field. This change is crucial for maintaining compatibility while not affecting older Python versions.

Confidence score: 4/5

  1. This PR is safe to merge as it primarily adds forward compatibility
  2. The score of 4 reflects solid implementation but some uncertainty around testing against a development version of Python
  3. Files needing attention:
    • strawberry/types/field.py: Verify the version check logic
    • noxfile.py: Consider if dropping Python 3.9 support warrants a breaking change notice

5 files reviewed, 1 comment
Edit PR Review Bot Settings | Greptile

@botberry
Copy link
Member

botberry commented Jul 16, 2025

Thanks for adding the RELEASE.md file!

Here's a preview of the changelog:


This release adds support for the upcoming Python 3.14

Here's the tweet text:

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

This release adds support for Python 3.14!

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

patrick91 and others added 3 commits July 16, 2025 23:34
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
@patrick91 patrick91 changed the title Run tests on 3.14 Add support for Python 3.14 Jul 16, 2025
@@ -51,7 +51,8 @@ def _check_field_annotations(cls: builtins.type[Any]) -> None:

https://github.com/python/cpython/blob/6fed3c85402c5ca704eb3f3189ca3f5c67a08d19/Lib/dataclasses.py#L881-L884
"""
cls_annotations = cls.__dict__.get("__annotations__", {})
cls_annotations = get_annotations(cls)
# TODO: do we need this?
Copy link
Member

Choose a reason for hiding this comment

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

If I'm not mistaken, on Python 3.9 or less, __annotations__ will not exist in the class unless we have at least one annotation defined in it. Even if the parent classes have one

So either this is to work around that, or because we are relying on the class' annotations instead of getting from parents as well, which now that we have get_annotations, we can probably refactor?

Let me know what you think and I can try to refactor the codebase to use get_annotations only, basing on top of this branch in another PR

Copy link
Member Author

Choose a reason for hiding this comment

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

we are using get_annotations, because __annotations__ is not working anymore (or at least it is not working in the same way) in Python 3.14

Copy link
Member

Choose a reason for hiding this comment

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

Hrmm I assumed get_annotations was going to work like I described, just saw this and now I understand its purpose.

# /// script
# dependencies = ["typing-extensions"]
# ///

from typing_extensions import get_annotations, Format


class A:
    foo: str
    bar: int


class B(A):
    bar: "float"
    baz: bool


for format in [Format.VALUE, Format.FORWARDREF, Format.STRING]:
    print(f"Format: {format}")
    print(get_annotations(A, format=format))
    print(get_annotations(B, format=format))
    print()

Gives:

Format: 1
{'foo': <class 'str'>, 'bar': <class 'int'>}
{'bar': 'float', 'baz': <class 'bool'>}

Format: 3
{'foo': <class 'str'>, 'bar': <class 'int'>}
{'bar': 'float', 'baz': <class 'bool'>}

Format: 4
{'foo': 'str', 'bar': 'int'}
{'bar': 'float', 'baz': 'bool'}

So it doesn't automatically get annotations from parents, we still need to go through the MRO to get the final dict

So the reason of this TODO is indeed python 3.9, but unless we are going to use get_annotations in other places where we retrieve the annotations from the class, we still need to have this to make sure when we do cls.__annotations__ again, we get what get_annotations returned

Copy link
Member Author

Choose a reason for hiding this comment

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

ah, right :) feel free to send another PR, maybe after merging this? :D

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.

3 participants