Skip to content

Fix non-base64 data URIs passing text to BytesIO - #9394

Merged
kuzeyron merged 2 commits into
kivy:masterfrom
charan-rathore:fix-9389-data-uri-bytes
Oct 2, 2026
Merged

kuzeyron merged 2 commits into
kivy:masterfrom
charan-rathore:fix-9389-data-uri-bytes

Conversation

@charan-rathore

Copy link
Copy Markdown
Contributor

A data URI without ;base64 leaves its payload as str, and Image.__init__ passes it straight to BytesIO, raising TypeError: a bytes-like object is required, not 'str'.

Per RFC 2397, a non-base64 data URI payload is URL-encoded text, so decode it with urllib.parse.unquote_to_bytes before handing it to BytesIO. Base64 handling is unchanged.

Adds display-free tests for both branches using a percent-encoded and a base64 1x1 GIF.

Closes #9389.

Validation:

  • Fresh run_tests.sh (verified here): baseline 1 failed (TypeError) + 1 passed (base64 control) on the kivy 2.3.1 wheel; patched 2 passed; wheel test_image.py passes (1 passed, 1 pre-existing skip).
  • fix.patch applies cleanly to master base 9bd35c5 (git apply --check in the runner).

Caveat: master needs a native SDL toolchain, so the tests were run against the released 2.3.1 wheel carrying the identical data-URI branch; master's own suite was not run.

@welcome

welcome Bot commented Oct 1, 2026

Copy link
Copy Markdown

Thanks for opening your first pull request here! 💖 Please check out our contributing guidelines.

@ElliotGarbus

Copy link
Copy Markdown
Contributor

Thanks, the fix is right. A data URI without ;base64 should be URL-decoded to bytes (RFC 2397), and unquote_to_bytes does that. This error dates back to the python 2 to python 3 change.

One suggestion for the tests: GIF is loaded by Pillow or ffpyplayer, not the SDL3 loader, so these tests fail in an environment without Pillow. A PNG is always handled by SDL3, which keeps the test focused on the data URI decoding. For example:

png_path = os.path.join(kivy.kivy_data_dir, 'logo', 'kivy-icon-16.png')
with open(png_path, 'rb') as f:
    png = f.read()

CoreImage("data:image/png;base64," + b64encode(png).decode("ascii"))  # size (16, 16)
CoreImage("data:image/png," + quote_from_bytes(png))                  # size (16, 16)

I checked this on master: the percent-encoded PNG raises TypeError without your change and loads at 16x16 with it.

@ElliotGarbus
ElliotGarbus requested a review from kuzeyron October 2, 2026 02:55
@charan-rathore

Copy link
Copy Markdown
Contributor Author

Thanks, switched the tests to the 16x16 PNG from kivy_data_dir in fa96f72, with one base64 and one percent-encoded load, both expecting (16, 16).

What I ran: on an older Kivy build without the fix, the base64 test passes and the percent-encoded one raises the TypeError, as you saw on master. I did not run it against this branch's code, so CI is the check there.

@kuzeyron

kuzeyron commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

LGTM! Thank you.

@kuzeyron
kuzeyron merged commit 60a0b2a into kivy:master Oct 2, 2026
33 checks passed
@welcome

welcome Bot commented Oct 2, 2026

Copy link
Copy Markdown

Congrats on merging your first pull request! 🎉🎉🎉

@kivybot

kivybot commented Nov 12, 2026

Copy link
Copy Markdown

Successfully created backport PR for devel-2.3.x:

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.

CoreImage passes text to BytesIO for non-base64 data URIs

4 participants