Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Variadic arguments that aren't objects are passed as objects (stringWithFormat_ with %d / %f)

Open Beginner friendly
#195 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
72/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
python
Domain
tooling

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:

https://github.com/kivy/pyobjus/blob/9fb061997d78d5156a24419a0cfd6416f3b3ec5b/pyobjus/pyobjus.pyx#L378-L383

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 → int
  • bytes → char *
  • objects, str and None → @, 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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from kivy/pyobjus

All issues in kivy/pyobjus

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.