python / cpython

The Python programming language
https://www.python.org
Other
63.18k stars 30.25k forks source link

Setting a `int` type value to `message` argument of `warnings.warn()` gets a wrong or abstract error message #125827

Open hyperkai opened 3 days ago

hyperkai commented 3 days ago

Bug report

Bug description:

Setting the int type value 100 to message argument of warnings.warn() gets the 1st error message as shown below:

import warnings
#             ↓ ↓ ↓ ↓ ↓ ↓
warnings.warn(message=100) # Error

TypeError: expected string or bytes-like object, got 'int'

But, setting a bytes-like object to message argument of warnings.warn() gets the 2nd error message as shown below:

import warnings

warnings.warn(message=b"Hello World") # Error
warnings.warn(message=bytes(source="Hello World", encoding="utf-8")) # Error

print(type(b"Hello World"))  # <class 'bytes'>
print(type(bytes(source="Hello World", encoding="utf-8"))) # <class 'bytes'>

TypeError: cannot use a string pattern on a bytes-like object

So, I set a str type value using decode() to message argument of warnings.warn(), then it works as shown below:

import warnings

warnings.warn(message=b"Hello World".decode(encoding="utf-8")) # Works
warnings.warn(message=bytes(source="Hello World", encoding="utf-8").decode(encoding="utf-8")) # Works

print(type(b"Hello World".decode(encoding="utf-8"))) # <class 'str'>
print(type(bytes(source="Hello World", encoding="utf-8").decode(encoding="utf-8"))) # <class 'str'>

So, the 1st error message should be something like below:

TypeError: expected string, got 'int'

Or, It's better to say str which is more exact(precise) than string:

TypeError: expected str, got 'int'

CPython versions tested on:

3.12

Operating systems tested on:

Windows

picnixz commented 3 days ago

Actually, the error message seems to stem from the re module, not the warnings module. So we need, at some point, to normalize the inputs, or just sanitize the message before it is being given (namely, use some isinstance(message, str)).

EDIT: Actually, after some investigation, it appears that I cannot reproduce the issue again (neither on 3.12.6 nor on main):

>>> import warnings
>>> warnings.warn(5)
<python-input-1>:1: UserWarning: 5
  warnings.warn(5)

@hyperkai Can you confirm the exact version of Python? as well as whether you have filters enabled? (namely, the exact state of the warnings module)

picnixz commented 2 days ago

Related: https://github.com/python/cpython/issues/47889 which added the following test:

    def test_warn_nonstandard_types(self):
        # warn() should handle non-standard types without issue.
        for ob in (Warning, None, 42):
            with original_warnings.catch_warnings(record=True,
                    module=self.module) as w:
                self.module.simplefilter("once")
                self.module.warn(ob)
                # Don't directly compare objects since
                # ``Warning() != Warning()``.
                self.assertEqual(str(w[-1].message), str(UserWarning(ob)))