# Check category argument
if category is None:
category = UserWarning
- if not (isinstance(category, type) and issubclass(category, Warning)):
- raise TypeError("category must be a Warning subclass, "
- "not '{:s}'".format(type(category).__name__))
+ elif not isinstance(category, type):
+ raise TypeError(f"category must be a Warning subclass, not "
+ f"'{type(category).__name__}'")
+ elif not issubclass(category, Warning):
+ raise TypeError(f"category must be a Warning subclass, not "
+ f"class '{category.__name__}'")
if not isinstance(skip_file_prefixes, tuple):
# The C version demands a tuple for implementation performance.
raise TypeError('skip_file_prefixes must be a tuple of strs.')
class MyWarningClass(Warning):
pass
- class NonWarningSubclass:
- pass
-
# passing a non-subclass of Warning should raise a TypeError
- with self.assertRaises(TypeError) as cm:
+ expected = "category must be a Warning subclass, not 'str'"
+ with self.assertRaisesRegex(TypeError, expected):
self.module.warn('bad warning category', '')
- self.assertIn('category must be a Warning subclass, not ',
- str(cm.exception))
- with self.assertRaises(TypeError) as cm:
- self.module.warn('bad warning category', NonWarningSubclass)
- self.assertIn('category must be a Warning subclass, not ',
- str(cm.exception))
+ expected = "category must be a Warning subclass, not class 'int'"
+ with self.assertRaisesRegex(TypeError, expected):
+ self.module.warn('bad warning category', int)
# check that warning instances also raise a TypeError
- with self.assertRaises(TypeError) as cm:
+ expected = "category must be a Warning subclass, not '.*MyWarningClass'"
+ with self.assertRaisesRegex(TypeError, expected):
self.module.warn('bad warning category', MyWarningClass())
- self.assertIn('category must be a Warning subclass, not ',
- str(cm.exception))
with self.module.catch_warnings():
self.module.resetwarnings()
--- /dev/null
+Improve error messages for invalid category in :func:`warnings.warn`.
/* Normalize message. */
Py_INCREF(message); /* DECREF'ed in cleanup. */
- rc = PyObject_IsInstance(message, PyExc_Warning);
- if (rc == -1) {
- goto cleanup;
- }
- if (rc == 1) {
+ if (PyObject_TypeCheck(message, (PyTypeObject *)PyExc_Warning)) {
text = PyObject_Str(message);
if (text == NULL)
goto cleanup;
static PyObject *
get_category(PyObject *message, PyObject *category)
{
- int rc;
-
- /* Get category. */
- rc = PyObject_IsInstance(message, PyExc_Warning);
- if (rc == -1)
- return NULL;
-
- if (rc == 1)
- category = (PyObject*)Py_TYPE(message);
- else if (category == NULL || category == Py_None)
- category = PyExc_UserWarning;
+ if (PyObject_TypeCheck(message, (PyTypeObject *)PyExc_Warning)) {
+ /* Ignore the category argument. */
+ return (PyObject*)Py_TYPE(message);
+ }
+ if (category == NULL || category == Py_None) {
+ return PyExc_UserWarning;
+ }
/* Validate category. */
- rc = PyObject_IsSubclass(category, PyExc_Warning);
- /* category is not a subclass of PyExc_Warning or
- PyObject_IsSubclass raised an error */
- if (rc == -1 || rc == 0) {
+ if (!PyType_Check(category)) {
+ PyErr_Format(PyExc_TypeError,
+ "category must be a Warning subclass, not '%T'",
+ category);
+ return NULL;
+ }
+ if (!PyType_IsSubtype((PyTypeObject *)category, (PyTypeObject *)PyExc_Warning)) {
PyErr_Format(PyExc_TypeError,
- "category must be a Warning subclass, not '%s'",
- Py_TYPE(category)->tp_name);
+ "category must be a Warning subclass, not class '%N'",
+ (PyTypeObject *)category);
return NULL;
}