Skip to content

Fix sanic adapter casting files to io.BytesIO #3751

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

Merged
merged 8 commits into from
Apr 15, 2025

Conversation

Maypher
Copy link
Contributor

@Maypher Maypher commented Jan 10, 2025

The current implementation of strawberry.sanic.utils.convert_request_to_files_dict casts uploaded files to io.BytesIO, making it return a type that doesn't coincide with the docs. This commit removes this casting and makes the function work in accordance with the docs.

Description

Changed files_dict[field_name] = BytesIO(file_list[0].body) to files_dict[field_name] = file_list[0]

Types of Changes

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

Issues Fixed or Closed by This PR

Fix #3750

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

Bug Fixes:

  • Uploaded files are now correctly handled as Sanic File objects instead of being cast to io.BytesIO.

Copy link
Contributor

sourcery-ai bot commented Jan 10, 2025

Reviewer's Guide by Sourcery

This PR fixes a bug in the strawberry.sanic.utils.convert_request_to_files_dict function where uploaded files were incorrectly cast to io.BytesIO. The change ensures the function returns the correct sanic.request.File type, aligning it with the documentation.

Sequence diagram for Sanic file upload handling before and after fix

sequenceDiagram
    participant Client
    participant SanicServer
    participant FileHandler

    Note over Client,FileHandler: Before Fix
    Client->>SanicServer: Upload file
    SanicServer->>FileHandler: convert_request_to_files_dict()
    FileHandler->>FileHandler: Convert to BytesIO
    FileHandler-->>SanicServer: Return BytesIO object

    Note over Client,FileHandler: After Fix
    Client->>SanicServer: Upload file
    SanicServer->>FileHandler: convert_request_to_files_dict()
    FileHandler-->>SanicServer: Return original Sanic File object
Loading

Class diagram showing the file handling type changes

classDiagram
    class Request {
        +files: dict
    }

    class FileHandler {
        +convert_request_to_files_dict(request: Request) dict
    }

    class File {
        +body: bytes
        +name: str
        +type: str
    }

    note for FileHandler "Changed return type from\ndict[str, BytesIO] to\ndict[str, File]"

    Request -- FileHandler
    FileHandler -- File
Loading

File-Level Changes

Change Details Files
Removed the casting of uploaded files to io.BytesIO.
  • Changed files_dict[field_name] = BytesIO(file_list[0].body) to files_dict[field_name] = file_list[0]
strawberry/sanic/utils.py
Added tests to verify the fix and ensure the function behaves as expected.
  • Created a new test file test_file_upload.py with tests covering the file upload functionality.
  • Added a test case to check that files are correctly converted to sanic.request.File objects.
  • Added a test case to verify that the GraphQL API handles file uploads correctly end-to-end.
  • Added a test case to verify that the file name is correctly returned after the upload process is completed
tests/sanic/test_file_upload.py
Updated the documentation to reflect the change.
  • Added a new release note in RELEASE.md to document the bug fix and the change in the returned file type
RELEASE.md

Possibly linked issues

  • #0: The PR fixes the bug where uploaded files were cast to io.BytesIO instead of sanic.request.File.

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.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a 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. You can also use
    this command to specify where the summary should be inserted.

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
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 @Maypher - I've reviewed your changes and they look great!

Here's what I looked at during the review
  • 🟡 General issues: 2 issues found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟢 Complexity: all looks good
  • 🟢 Documentation: all looks good

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.

@@ -29,12 +28,12 @@ def convert_request_to_files_dict(request: Request) -> dict[str, Any]:
if not request_files:
return {}

files_dict: dict[str, Union[BytesIO, list[BytesIO]]] = {}
files_dict: dict[str, Union[File, list[File]]] = {}

for field_name, file_list in request_files.items():
assert len(file_list) == 1
Copy link
Contributor

Choose a reason for hiding this comment

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

issue: Consider handling multiple files per field name instead of asserting there will be exactly one

The assertion could cause server crashes if multiple files are uploaded with the same field name. Consider returning a list of File objects when multiple files are present, matching the type hint Union[File, list[File]].

Release type: patch

Fix bug where files would be converted into io.BytesIO when using the sanic GraphQLView
instead of using the sanic File type
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Check casing and specific name for "sanic File type"

Should it be "Sanic File", "Sanic file type", or something more specific? Referencing the Sanic documentation might help.

@botberry
Copy link
Member

botberry commented Jan 10, 2025

Thanks for adding the RELEASE.md file!

Here's a preview of the changelog:


Fix bug where files would be converted into io.BytesIO when using the sanic GraphQLView
instead of using the sanic File type

Here's the tweet text:

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

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

@botberry
Copy link
Member

Thanks for adding the RELEASE.md file!

Here's a preview of the changelog:


Fix bug where files would be converted into io.BytesIO when using the sanic GraphQLView
instead of using the sanic File type

Here's the tweet text:

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

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

Copy link
Member

@patrick91 patrick91 left a comment

Choose a reason for hiding this comment

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

This looks great, I might spend a bit of time moving the tests to the http tests, so we have one test for all integrations 😊

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.

LGTM :)

Will leave final review to @patrick91

Copy link

codecov bot commented Feb 9, 2025

Codecov Report

Attention: Patch coverage is 85.45455% with 8 lines in your changes missing coverage. Please review.

Project coverage is 95.04%. Comparing base (ca04c88) to head (dcde0cb).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3751      +/-   ##
==========================================
- Coverage   95.05%   95.04%   -0.02%     
==========================================
  Files         501      502       +1     
  Lines       32632    32682      +50     
  Branches     1694     1695       +1     
==========================================
+ Hits        31019    31061      +42     
- Misses       1341     1348       +7     
- Partials      272      273       +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 Feb 9, 2025

CodSpeed Performance Report

Merging #3751 will not alter performance

Comparing Maypher:sanic-file-fix (dcde0cb) with main (ca04c88)

Summary

✅ 21 untouched benchmarks

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.

Hey @Maypher ,

I was revisiting this, just marking as "changes requested" to make sure I remember to check it again for any changes.

I think the only thing missing is to adjust the RELEASE.md file

bellini666

This comment was marked as duplicate.

@Maypher
Copy link
Contributor Author

Maypher commented Feb 18, 2025

@bellini666 What exactly is there to change about RELEASE.md?

@bellini666
Copy link
Member

@bellini666 What exactly is there to change about RELEASE.md?

Hey @Maypher

Sorry for taking long to see this. I meant this comment here: https://github.com/strawberry-graphql/strawberry/pull/3751/files#r1912412757

Maypher and others added 4 commits April 15, 2025 17:28
io.BytesIO which is the filetype used by AIOHTTP. This commit fixes this
issue by directly assigning the file instead of casting it.
Copy link
Member

@patrick91 patrick91 left a comment

Choose a reason for hiding this comment

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

Thanks you for this! I think it is fine to keep the release file as it is 😊

on-my-way-smile-gif-by-xbox

@patrick91 patrick91 merged commit a7ba489 into strawberry-graphql:main Apr 15, 2025
100 of 101 checks passed
@botberry
Copy link
Member

Thanks for contributing to Strawberry! 🎉 You've been invited to join
the Strawberry GraphQL organisation 😊

You can also request a free sticker by filling this form: https://forms.gle/dmnfQUPoY5gZbVT67

And don't forget to join our discord server: https://strawberry.rocks/discord 🔥

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.

Upload type not being correctly converted into Sanic File type at runtime
4 participants