Variadic arguments that aren't objects are passed as objects (stringWithFormat_ with %d / %f)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 72/100
Research direction
Start in pyobjus/pyobjus.pyx around lines 378-383, where extra arguments are given the type of the last declared argument, and find the nearby ffi_prep_cif_var setup added in #77. Replace the fixed type for variadic arguments with a per-value choice following C default promotions (int→q, float→d, bool→i, bytes→char *, objects/str/None→@), keeping explicit ctypes values as given. Done looks like the issue's reproducer printing 42, 42 and 1.500000 for %d, %ld, %f, plus a new test mixing %d, %ld, %f, %s and %@ that is run on macOS.
Written by the indexing model from the issue text.
Description
Summary
Variadic arguments that aren't objects are passed as objects, so stringWithFormat_ formats garbage for %d, %ld and %f:
from pyobjus import autoclass, objc_str
NSString = autoclass("NSString")
for fmt, args in (("%d", (42,)), ("%ld", (42,)), ("%f", (1.5,)),
("%@ and %d", (objc_str("x"), 7)),
("%@ and %@", (objc_str("x"), objc_str("y")))):
print(fmt, args, "->", NSString.stringWithFormat_(objc_str(fmt), *args).UTF8String())
%d (42,) -> 1893330941
%ld (42,) -> -5191913781573586947
%f (1.5,) -> 0.000000
%@ and %d (<NSTaggedPointerString ...>, 7) -> x and 1893333373
%@ and %@ (<NSTaggedPointerString ...>, <NSTaggedPointerString ...>) -> x and y
The integer results change from run to run; they look like the address of an object, not the number.
(macOS 26, arm64, master at 9fb0619.)
Cause
Extra arguments beyond the method signature get the type of the last declared argument:
For stringWithFormat: (and arrayWithObjects:, dictionaryWithObjectsAndKeys:, …) that is @, so 42 and 1.5 are converted to objects and their pointers are passed. The variadic part is already prepared correctly with ffi_prep_cif_var (since #77), so only the types are wrong.
Possible direction
Pick the type of each extra argument from its Python value, using C's default argument promotions:
int→long(q)float→double(d)bool→intbytes→char *- objects,
strandNone→@, as today
Explicit ctypes values (c_int, c_float, …) could be honored as given, for callers who need an exact type.
A test can format a string with %d, %ld, %f, %s and %@ mixed together and compare the result.
- Dominant language
- Python
- Stars
- 192
- Forks
- 48
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 22
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from kivy/pyobjus
-
Difficulty 2/5 1-3 hours Newbie friendliness 80/100
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 35/100
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 30/100
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 45/100
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 50/100
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
vllm-project/vllm#64845 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
dekobon/big-code-analysis#1729 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
pydantic/pydantic-ai#12091 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100