Skip to content

Conversation

@MattiHayes
Copy link

@MattiHayes MattiHayes commented Mar 22, 2025

gh-131540 : Improve type checking error for args in threading.Thread objects

Issue: python/cpython#131540

Original Proposal This change adds a validation check in the `threading.Thread` constructor to ensure that the args parameter is either a tuple or a list. This helps avoid confusion when a string or other non-iterable is accidentally passed.
import threading

def greet(name):
    print(f"Hello, {name}!")

# Common mistake: passing a string instead of a tuple
t = threading.Thread(target=greet, args="World")
t.start()

Current behaviour:

TypeError: greet() takes 1 positional argument but 5 were given

which is raised when the thread is started.

New behaviour:

TypeError: 'args' must be a non-string iterable like a tuple or list, not str

Which is raised in the Thread constructor.

Compatibility note:

This introduces a stricter check and may break code that intentionally relies on passing a string or bytes as an iterable. However, this usage is not documented and it is unclear if people purposefully do this.

New Proposal

This change adds early validation in threading.Thread.__init__ to ensure that the args parameter is an iterable. If a non-iterable value (such as an int or None) is passed, a TypeError is now raised at construction time instead of at thread start.

This improves consistency with how other type errors are handled in Python and provides earlier feedback for developers, especially when the error would otherwise occur asynchronously at thread start.

Motivation

Previously, non-iterable values passed to args would raise an error only when thread.start() was called:

# Before: raises at .start(), not at creation
threading.Thread(target=func, args=42)  # No error here
t.start()  # TypeError: argument after * must be an iterable, not int

With this change, the error is raised immediately in __init__:

# Now: fails early
threading.Thread(target=func, args=42)
# TypeError: 'args' must be an iterable, not int

What this PR changes:

  • Adds a check in Thread.__init__ to ensure args has an __iter__ attribute
  • Raises TypeError immediately if not
  • Does not block str or bytes (for compatibility)
  • Adds unit tests for:
    -Non-iterables raising TypeError (e.g., int, None, float)
    -Valid iterables (e.g., tuple, list, and a custom iterable) being accepted

Let me know if anything else is needed.

@ghost
Copy link

ghost commented Mar 22, 2025

All commit authors signed the Contributor License Agreement.
CLA signed

@bedevere-app
Copy link

bedevere-app bot commented Mar 22, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@bedevere-app
Copy link

bedevere-app bot commented Mar 22, 2025

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@picnixz picnixz changed the title gh-131540 gh-131540: Improve type checking error for args in threading.Thread objects Mar 22, 2025
Copy link
Member

@ZeroIntensity ZeroIntensity left a comment

Choose a reason for hiding this comment

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

It's not terribly uncommon to arg-splat a string into a function, so I don't think it's safe to change that for threads without a deprecation period. Please change this to solely a check for __iter__.

I'm not opposed to deprecating use of str/bytes for a better error message in the future, but I don't know what kinds of use-cases people have for that right now. If you want to go that route, open a thread on DPO (under the Core Development category) so we can get some more opinions.

@rhettinger
Copy link
Contributor

Thank you for the suggestion, but I'm going to decline for several reasons. First, this is a breaking change. Any sequence is automatically iterable even if it doesn't define __iter__. Second, though unusual and likely a mistake, strings could possibly be used as valid input. Third, the norm for pure python code is late checking of values when used. Fourth, we really want the minimum possible overhead and to not slow down correct code that is launching many threads.

Perhaps suggest this as a rule for one of the Python linters. They are better at identifying code that smells bad even though it might only be valid in a rare case.

@rhettinger rhettinger closed this Apr 3, 2025
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