1#include "Python.h"
2#include "frameobject.h"
3
4#define MODULE_NAME "_warnings"
5
6PyDoc_STRVAR(warnings__doc__,
7MODULE_NAME " provides basic warning filtering support.\n"
8"It is a helper module to speed up interpreter start-up.");
9
10/* Both 'filters' and 'onceregistry' can be set in warnings.py;
11   get_warnings_attr() will reset these variables accordingly. */
12static PyObject *_filters;  /* List */
13static PyObject *_once_registry;  /* Dict */
14static PyObject *_default_action; /* String */
15
16
17static int
18check_matched(PyObject *obj, PyObject *arg)
19{
20    PyObject *result;
21    int rc;
22
23    if (obj == Py_None)
24        return 1;
25    result = PyObject_CallMethod(obj, "match", "O", arg);
26    if (result == NULL)
27        return -1;
28
29    rc = PyObject_IsTrue(result);
30    Py_DECREF(result);
31    return rc;
32}
33
34/*
35   Returns a new reference.
36   A NULL return value can mean false or an error.
37*/
38static PyObject *
39get_warnings_attr(const char *attr)
40{
41    static PyObject *warnings_str = NULL;
42    PyObject *all_modules;
43    PyObject *warnings_module;
44    int result;
45
46    if (warnings_str == NULL) {
47        warnings_str = PyString_InternFromString("warnings");
48        if (warnings_str == NULL)
49            return NULL;
50    }
51
52    all_modules = PyImport_GetModuleDict();
53    result = PyDict_Contains(all_modules, warnings_str);
54    if (result == -1 || result == 0)
55        return NULL;
56
57    warnings_module = PyDict_GetItem(all_modules, warnings_str);
58    if (!PyObject_HasAttrString(warnings_module, attr))
59            return NULL;
60    return PyObject_GetAttrString(warnings_module, attr);
61}
62
63
64static PyObject *
65get_once_registry(void)
66{
67    PyObject *registry;
68
69    registry = get_warnings_attr("onceregistry");
70    if (registry == NULL) {
71        if (PyErr_Occurred())
72            return NULL;
73        return _once_registry;
74    }
75    Py_DECREF(_once_registry);
76    _once_registry = registry;
77    return registry;
78}
79
80
81static PyObject *
82get_default_action(void)
83{
84    PyObject *default_action;
85
86    default_action = get_warnings_attr("defaultaction");
87    if (default_action == NULL) {
88        if (PyErr_Occurred()) {
89            return NULL;
90        }
91        return _default_action;
92    }
93
94    Py_DECREF(_default_action);
95    _default_action = default_action;
96    return default_action;
97}
98
99
100/* The item is a borrowed reference. */
101static const char *
102get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno,
103           PyObject *module, PyObject **item)
104{
105    PyObject *action;
106    Py_ssize_t i;
107    PyObject *warnings_filters;
108
109    warnings_filters = get_warnings_attr("filters");
110    if (warnings_filters == NULL) {
111        if (PyErr_Occurred())
112            return NULL;
113    }
114    else {
115        Py_DECREF(_filters);
116        _filters = warnings_filters;
117    }
118
119    if (!PyList_Check(_filters)) {
120        PyErr_SetString(PyExc_ValueError,
121                        MODULE_NAME ".filters must be a list");
122        return NULL;
123    }
124
125    /* _filters could change while we are iterating over it. */
126    for (i = 0; i < PyList_GET_SIZE(_filters); i++) {
127        PyObject *tmp_item, *action, *msg, *cat, *mod, *ln_obj;
128        Py_ssize_t ln;
129        int is_subclass, good_msg, good_mod;
130
131        tmp_item = *item = PyList_GET_ITEM(_filters, i);
132        if (PyTuple_Size(tmp_item) != 5) {
133            PyErr_Format(PyExc_ValueError,
134                         MODULE_NAME ".filters item %zd isn't a 5-tuple", i);
135            return NULL;
136        }
137
138        /* Python code: action, msg, cat, mod, ln = item */
139        action = PyTuple_GET_ITEM(tmp_item, 0);
140        msg = PyTuple_GET_ITEM(tmp_item, 1);
141        cat = PyTuple_GET_ITEM(tmp_item, 2);
142        mod = PyTuple_GET_ITEM(tmp_item, 3);
143        ln_obj = PyTuple_GET_ITEM(tmp_item, 4);
144
145        good_msg = check_matched(msg, text);
146        good_mod = check_matched(mod, module);
147        is_subclass = PyObject_IsSubclass(category, cat);
148        ln = PyInt_AsSsize_t(ln_obj);
149        if (good_msg == -1 || good_mod == -1 || is_subclass == -1 ||
150            (ln == -1 && PyErr_Occurred()))
151            return NULL;
152
153        if (good_msg && is_subclass && good_mod && (ln == 0 || lineno == ln))
154            return PyString_AsString(action);
155    }
156
157    action = get_default_action();
158    if (action != NULL) {
159        return PyString_AsString(action);
160    }
161
162    PyErr_SetString(PyExc_ValueError,
163                    MODULE_NAME ".defaultaction not found");
164    return NULL;
165}
166
167
168static int
169already_warned(PyObject *registry, PyObject *key, int should_set)
170{
171    PyObject *already_warned;
172
173    if (key == NULL)
174        return -1;
175
176    already_warned = PyDict_GetItem(registry, key);
177    if (already_warned != NULL) {
178        int rc = PyObject_IsTrue(already_warned);
179        if (rc != 0)
180            return rc;
181    }
182
183    /* This warning wasn't found in the registry, set it. */
184    if (should_set)
185        return PyDict_SetItem(registry, key, Py_True);
186    return 0;
187}
188
189/* New reference. */
190static PyObject *
191normalize_module(PyObject *filename)
192{
193    PyObject *module;
194    const char *mod_str;
195    Py_ssize_t len;
196
197    int rc = PyObject_IsTrue(filename);
198    if (rc == -1)
199        return NULL;
200    else if (rc == 0)
201        return PyString_FromString("<unknown>");
202
203    mod_str = PyString_AsString(filename);
204    if (mod_str == NULL)
205        return NULL;
206    len = PyString_Size(filename);
207    if (len < 0)
208        return NULL;
209    if (len >= 3 &&
210            strncmp(mod_str + (len - 3), ".py", 3) == 0) {
211        module = PyString_FromStringAndSize(mod_str, len-3);
212    }
213    else {
214        module = filename;
215        Py_INCREF(module);
216    }
217    return module;
218}
219
220static int
221update_registry(PyObject *registry, PyObject *text, PyObject *category,
222                int add_zero)
223{
224    PyObject *altkey, *zero = NULL;
225    int rc;
226
227    if (add_zero) {
228        zero = PyInt_FromLong(0);
229        if (zero == NULL)
230            return -1;
231        altkey = PyTuple_Pack(3, text, category, zero);
232    }
233    else
234        altkey = PyTuple_Pack(2, text, category);
235
236    rc = already_warned(registry, altkey, 1);
237    Py_XDECREF(zero);
238    Py_XDECREF(altkey);
239    return rc;
240}
241
242static void
243show_warning(PyObject *filename, int lineno, PyObject *text, PyObject
244                *category, PyObject *sourceline)
245{
246    PyObject *f_stderr;
247    PyObject *name;
248    char lineno_str[128];
249
250    PyOS_snprintf(lineno_str, sizeof(lineno_str), ":%d: ", lineno);
251
252    name = PyObject_GetAttrString(category, "__name__");
253    if (name == NULL)  /* XXX Can an object lack a '__name__' attribute? */
254        return;
255
256    f_stderr = PySys_GetObject("stderr");
257    if (f_stderr == NULL) {
258        fprintf(stderr, "lost sys.stderr\n");
259        Py_DECREF(name);
260        return;
261    }
262
263    /* Print "filename:lineno: category: text\n" */
264    PyFile_WriteObject(filename, f_stderr, Py_PRINT_RAW);
265    PyFile_WriteString(lineno_str, f_stderr);
266    PyFile_WriteObject(name, f_stderr, Py_PRINT_RAW);
267    PyFile_WriteString(": ", f_stderr);
268    PyFile_WriteObject(text, f_stderr, Py_PRINT_RAW);
269    PyFile_WriteString("\n", f_stderr);
270    Py_XDECREF(name);
271
272    /* Print "  source_line\n" */
273    if (sourceline) {
274        char *source_line_str = PyString_AS_STRING(sourceline);
275        while (*source_line_str == ' ' || *source_line_str == '\t' ||
276                *source_line_str == '\014')
277            source_line_str++;
278
279        PyFile_WriteString(source_line_str, f_stderr);
280        PyFile_WriteString("\n", f_stderr);
281    }
282    else
283        _Py_DisplaySourceLine(f_stderr, PyString_AS_STRING(filename),
284                              lineno, 2);
285    PyErr_Clear();
286}
287
288static PyObject *
289warn_explicit(PyObject *category, PyObject *message,
290              PyObject *filename, int lineno,
291              PyObject *module, PyObject *registry, PyObject *sourceline)
292{
293    PyObject *key = NULL, *text = NULL, *result = NULL, *lineno_obj = NULL;
294    PyObject *item = Py_None;
295    const char *action;
296    int rc;
297
298    if (registry && !PyDict_Check(registry) && (registry != Py_None)) {
299        PyErr_SetString(PyExc_TypeError, "'registry' must be a dict");
300        return NULL;
301    }
302
303    /* Normalize module. */
304    if (module == NULL) {
305        module = normalize_module(filename);
306        if (module == NULL)
307            return NULL;
308    }
309    else
310        Py_INCREF(module);
311
312    /* Normalize message. */
313    Py_INCREF(message);  /* DECREF'ed in cleanup. */
314    rc = PyObject_IsInstance(message, PyExc_Warning);
315    if (rc == -1) {
316        goto cleanup;
317    }
318    if (rc == 1) {
319        text = PyObject_Str(message);
320        if (text == NULL)
321            goto cleanup;
322        category = (PyObject*)message->ob_type;
323    }
324    else {
325        text = message;
326        message = PyObject_CallFunction(category, "O", message);
327        if (message == NULL)
328            goto cleanup;
329    }
330
331    lineno_obj = PyInt_FromLong(lineno);
332    if (lineno_obj == NULL)
333        goto cleanup;
334
335    /* Create key. */
336    key = PyTuple_Pack(3, text, category, lineno_obj);
337    if (key == NULL)
338        goto cleanup;
339
340    if ((registry != NULL) && (registry != Py_None)) {
341        rc = already_warned(registry, key, 0);
342        if (rc == -1)
343            goto cleanup;
344        else if (rc == 1)
345            goto return_none;
346        /* Else this warning hasn't been generated before. */
347    }
348
349    action = get_filter(category, text, lineno, module, &item);
350    if (action == NULL)
351        goto cleanup;
352
353    if (strcmp(action, "error") == 0) {
354        PyErr_SetObject(category, message);
355        goto cleanup;
356    }
357
358    /* Store in the registry that we've been here, *except* when the action
359       is "always". */
360    rc = 0;
361    if (strcmp(action, "always") != 0) {
362        if (registry != NULL && registry != Py_None &&
363                PyDict_SetItem(registry, key, Py_True) < 0)
364            goto cleanup;
365        else if (strcmp(action, "ignore") == 0)
366            goto return_none;
367        else if (strcmp(action, "once") == 0) {
368            if (registry == NULL || registry == Py_None) {
369                registry = get_once_registry();
370                if (registry == NULL)
371                    goto cleanup;
372            }
373            /* _once_registry[(text, category)] = 1 */
374            rc = update_registry(registry, text, category, 0);
375        }
376        else if (strcmp(action, "module") == 0) {
377            /* registry[(text, category, 0)] = 1 */
378            if (registry != NULL && registry != Py_None)
379                rc = update_registry(registry, text, category, 0);
380        }
381        else if (strcmp(action, "default") != 0) {
382            PyObject *to_str = PyObject_Str(item);
383            const char *err_str = "???";
384
385            if (to_str != NULL)
386                err_str = PyString_AS_STRING(to_str);
387            PyErr_Format(PyExc_RuntimeError,
388                        "Unrecognized action (%s) in warnings.filters:\n %s",
389                        action, err_str);
390            Py_XDECREF(to_str);
391            goto cleanup;
392        }
393    }
394
395    if (rc == 1)  /* Already warned for this module. */
396        goto return_none;
397    if (rc == 0) {
398        PyObject *show_fxn = get_warnings_attr("showwarning");
399        if (show_fxn == NULL) {
400            if (PyErr_Occurred())
401                goto cleanup;
402            show_warning(filename, lineno, text, category, sourceline);
403        }
404        else {
405              PyObject *res;
406
407              if (!PyMethod_Check(show_fxn) && !PyFunction_Check(show_fxn)) {
408                  PyErr_SetString(PyExc_TypeError,
409                                  "warnings.showwarning() must be set to a "
410                                  "function or method");
411                  Py_DECREF(show_fxn);
412                  goto cleanup;
413              }
414
415              res = PyObject_CallFunctionObjArgs(show_fxn, message, category,
416                                                  filename, lineno_obj,
417                                                  NULL);
418              Py_DECREF(show_fxn);
419              Py_XDECREF(res);
420              if (res == NULL)
421                  goto cleanup;
422        }
423    }
424    else /* if (rc == -1) */
425        goto cleanup;
426
427 return_none:
428    result = Py_None;
429    Py_INCREF(result);
430
431 cleanup:
432    Py_XDECREF(key);
433    Py_XDECREF(text);
434    Py_XDECREF(lineno_obj);
435    Py_DECREF(module);
436    Py_XDECREF(message);
437    return result;  /* Py_None or NULL. */
438}
439
440/* filename, module, and registry are new refs, globals is borrowed */
441/* Returns 0 on error (no new refs), 1 on success */
442static int
443setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
444              PyObject **module, PyObject **registry)
445{
446    PyObject *globals;
447
448    /* Setup globals and lineno. */
449    PyFrameObject *f = PyThreadState_GET()->frame;
450    while (--stack_level > 0 && f != NULL)
451        f = f->f_back;
452
453    if (f == NULL) {
454        globals = PyThreadState_Get()->interp->sysdict;
455        *lineno = 1;
456    }
457    else {
458        globals = f->f_globals;
459        *lineno = PyFrame_GetLineNumber(f);
460    }
461
462    *module = NULL;
463
464    /* Setup registry. */
465    assert(globals != NULL);
466    assert(PyDict_Check(globals));
467    *registry = PyDict_GetItemString(globals, "__warningregistry__");
468    if (*registry == NULL) {
469        int rc;
470
471        *registry = PyDict_New();
472        if (*registry == NULL)
473            return 0;
474
475         rc = PyDict_SetItemString(globals, "__warningregistry__", *registry);
476         if (rc < 0)
477            goto handle_error;
478    }
479    else
480        Py_INCREF(*registry);
481
482    /* Setup module. */
483    *module = PyDict_GetItemString(globals, "__name__");
484    if (*module == NULL) {
485        *module = PyString_FromString("<string>");
486        if (*module == NULL)
487            goto handle_error;
488    }
489    else
490        Py_INCREF(*module);
491
492    /* Setup filename. */
493    *filename = PyDict_GetItemString(globals, "__file__");
494    if (*filename != NULL) {
495            Py_ssize_t len = PyString_Size(*filename);
496        const char *file_str = PyString_AsString(*filename);
497            if (file_str == NULL || (len < 0 && PyErr_Occurred()))
498            goto handle_error;
499
500        /* if filename.lower().endswith((".pyc", ".pyo")): */
501        if (len >= 4 &&
502            file_str[len-4] == '.' &&
503            tolower(file_str[len-3]) == 'p' &&
504            tolower(file_str[len-2]) == 'y' &&
505            (tolower(file_str[len-1]) == 'c' ||
506                tolower(file_str[len-1]) == 'o'))
507        {
508            *filename = PyString_FromStringAndSize(file_str, len-1);
509            if (*filename == NULL)
510                goto handle_error;
511        }
512        else
513            Py_INCREF(*filename);
514    }
515    else {
516        const char *module_str = PyString_AsString(*module);
517        if (module_str && strcmp(module_str, "__main__") == 0) {
518            PyObject *argv = PySys_GetObject("argv");
519            if (argv != NULL && PyList_Size(argv) > 0) {
520                int is_true;
521                *filename = PyList_GetItem(argv, 0);
522                Py_INCREF(*filename);
523                /* If sys.argv[0] is false, then use '__main__'. */
524                is_true = PyObject_IsTrue(*filename);
525                if (is_true < 0) {
526                    Py_DECREF(*filename);
527                    goto handle_error;
528                }
529                else if (!is_true) {
530                    Py_DECREF(*filename);
531                    *filename = PyString_FromString("__main__");
532                    if (*filename == NULL)
533                        goto handle_error;
534                }
535            }
536            else {
537                /* embedded interpreters don't have sys.argv, see bug #839151 */
538                *filename = PyString_FromString("__main__");
539                if (*filename == NULL)
540                    goto handle_error;
541            }
542        }
543        if (*filename == NULL) {
544            *filename = *module;
545            Py_INCREF(*filename);
546        }
547    }
548
549    return 1;
550
551 handle_error:
552    /* filename not XDECREF'ed here as there is no way to jump here with a
553       dangling reference. */
554    Py_XDECREF(*registry);
555    Py_XDECREF(*module);
556    return 0;
557}
558
559static PyObject *
560get_category(PyObject *message, PyObject *category)
561{
562    int rc;
563
564    /* Get category. */
565    rc = PyObject_IsInstance(message, PyExc_Warning);
566    if (rc == -1)
567        return NULL;
568
569    if (rc == 1)
570        category = (PyObject*)message->ob_type;
571    else if (category == NULL)
572        category = PyExc_UserWarning;
573
574    /* Validate category. */
575    rc = PyObject_IsSubclass(category, PyExc_Warning);
576    if (rc == -1)
577        return NULL;
578    if (rc == 0) {
579        PyErr_SetString(PyExc_ValueError,
580                        "category is not a subclass of Warning");
581        return NULL;
582    }
583
584    return category;
585}
586
587static PyObject *
588do_warn(PyObject *message, PyObject *category, Py_ssize_t stack_level)
589{
590    PyObject *filename, *module, *registry, *res;
591    int lineno;
592
593    if (!setup_context(stack_level, &filename, &lineno, &module, &registry))
594        return NULL;
595
596    res = warn_explicit(category, message, filename, lineno, module, registry,
597                        NULL);
598    Py_DECREF(filename);
599    Py_DECREF(registry);
600    Py_DECREF(module);
601    return res;
602}
603
604static PyObject *
605warnings_warn(PyObject *self, PyObject *args, PyObject *kwds)
606{
607    static char *kw_list[] = { "message", "category", "stacklevel", 0 };
608    PyObject *message, *category = NULL;
609    Py_ssize_t stack_level = 1;
610
611    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|On:warn", kw_list,
612                                     &message, &category, &stack_level))
613        return NULL;
614
615    category = get_category(message, category);
616    if (category == NULL)
617        return NULL;
618    return do_warn(message, category, stack_level);
619}
620
621static PyObject *
622warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)
623{
624    static char *kwd_list[] = {"message", "category", "filename", "lineno",
625                                "module", "registry", "module_globals", 0};
626    PyObject *message;
627    PyObject *category;
628    PyObject *filename;
629    int lineno;
630    PyObject *module = NULL;
631    PyObject *registry = NULL;
632    PyObject *module_globals = NULL;
633
634    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOi|OOO:warn_explicit",
635                kwd_list, &message, &category, &filename, &lineno, &module,
636                &registry, &module_globals))
637        return NULL;
638
639    if (module_globals) {
640        static PyObject *get_source_name = NULL;
641        static PyObject *splitlines_name = NULL;
642        PyObject *loader;
643        PyObject *module_name;
644        PyObject *source;
645        PyObject *source_list;
646        PyObject *source_line;
647        PyObject *returned;
648
649        if (get_source_name == NULL) {
650            get_source_name = PyString_InternFromString("get_source");
651            if (!get_source_name)
652                return NULL;
653        }
654        if (splitlines_name == NULL) {
655            splitlines_name = PyString_InternFromString("splitlines");
656            if (!splitlines_name)
657                return NULL;
658        }
659
660        /* Check/get the requisite pieces needed for the loader. */
661        loader = PyDict_GetItemString(module_globals, "__loader__");
662        module_name = PyDict_GetItemString(module_globals, "__name__");
663
664        if (loader == NULL || module_name == NULL)
665            goto standard_call;
666
667        /* Make sure the loader implements the optional get_source() method. */
668        if (!PyObject_HasAttrString(loader, "get_source"))
669                goto standard_call;
670        /* Call get_source() to get the source code. */
671        source = PyObject_CallMethodObjArgs(loader, get_source_name,
672                                                module_name, NULL);
673        if (!source)
674            return NULL;
675        else if (source == Py_None) {
676            Py_DECREF(Py_None);
677            goto standard_call;
678        }
679
680        /* Split the source into lines. */
681        source_list = PyObject_CallMethodObjArgs(source, splitlines_name,
682                                                    NULL);
683        Py_DECREF(source);
684        if (!source_list)
685            return NULL;
686
687        /* Get the source line. */
688        source_line = PyList_GetItem(source_list, lineno-1);
689        if (!source_line) {
690            Py_DECREF(source_list);
691            return NULL;
692        }
693
694        /* Handle the warning. */
695        returned = warn_explicit(category, message, filename, lineno, module,
696                            registry, source_line);
697        Py_DECREF(source_list);
698        return returned;
699    }
700
701 standard_call:
702    return warn_explicit(category, message, filename, lineno, module,
703                                registry, NULL);
704}
705
706
707/* Function to issue a warning message; may raise an exception. */
708int
709PyErr_WarnEx(PyObject *category, const char *text, Py_ssize_t stack_level)
710{
711    PyObject *res;
712    PyObject *message = PyString_FromString(text);
713    if (message == NULL)
714        return -1;
715
716    if (category == NULL)
717        category = PyExc_RuntimeWarning;
718
719    res = do_warn(message, category, stack_level);
720    Py_DECREF(message);
721    if (res == NULL)
722        return -1;
723    Py_DECREF(res);
724
725    return 0;
726}
727
728/* PyErr_Warn is only for backwards compatibility and will be removed.
729   Use PyErr_WarnEx instead. */
730
731#undef PyErr_Warn
732
733PyAPI_FUNC(int)
734PyErr_Warn(PyObject *category, char *text)
735{
736    return PyErr_WarnEx(category, text, 1);
737}
738
739/* Warning with explicit origin */
740int
741PyErr_WarnExplicit(PyObject *category, const char *text,
742                   const char *filename_str, int lineno,
743                   const char *module_str, PyObject *registry)
744{
745    PyObject *res;
746    PyObject *message = PyString_FromString(text);
747    PyObject *filename = PyString_FromString(filename_str);
748    PyObject *module = NULL;
749    int ret = -1;
750
751    if (message == NULL || filename == NULL)
752        goto exit;
753    if (module_str != NULL) {
754        module = PyString_FromString(module_str);
755            if (module == NULL)
756                goto exit;
757    }
758
759    if (category == NULL)
760        category = PyExc_RuntimeWarning;
761    res = warn_explicit(category, message, filename, lineno, module, registry,
762                        NULL);
763    if (res == NULL)
764        goto exit;
765    Py_DECREF(res);
766    ret = 0;
767
768 exit:
769    Py_XDECREF(message);
770    Py_XDECREF(module);
771    Py_XDECREF(filename);
772    return ret;
773}
774
775
776PyDoc_STRVAR(warn_doc,
777"Issue a warning, or maybe ignore it or raise an exception.");
778
779PyDoc_STRVAR(warn_explicit_doc,
780"Low-level inferface to warnings functionality.");
781
782static PyMethodDef warnings_functions[] = {
783    {"warn", (PyCFunction)warnings_warn, METH_VARARGS | METH_KEYWORDS,
784        warn_doc},
785    {"warn_explicit", (PyCFunction)warnings_warn_explicit,
786        METH_VARARGS | METH_KEYWORDS, warn_explicit_doc},
787    /* XXX(brett.cannon): add showwarning? */
788    /* XXX(brett.cannon): Reasonable to add formatwarning? */
789    {NULL, NULL}	        /* sentinel */
790};
791
792
793static PyObject *
794create_filter(PyObject *category, const char *action)
795{
796    static PyObject *ignore_str = NULL;
797    static PyObject *error_str = NULL;
798    static PyObject *default_str = NULL;
799    PyObject *action_obj = NULL;
800    PyObject *lineno, *result;
801
802    if (!strcmp(action, "ignore")) {
803        if (ignore_str == NULL) {
804            ignore_str = PyString_InternFromString("ignore");
805            if (ignore_str == NULL)
806                return NULL;
807        }
808        action_obj = ignore_str;
809    }
810    else if (!strcmp(action, "error")) {
811        if (error_str == NULL) {
812            error_str = PyString_InternFromString("error");
813            if (error_str == NULL)
814                return NULL;
815        }
816        action_obj = error_str;
817    }
818    else if (!strcmp(action, "default")) {
819        if (default_str == NULL) {
820            default_str = PyString_InternFromString("default");
821            if (default_str == NULL)
822                return NULL;
823        }
824        action_obj = default_str;
825    }
826    else {
827        Py_FatalError("unknown action");
828    }
829
830    /* This assumes the line number is zero for now. */
831    lineno = PyInt_FromLong(0);
832    if (lineno == NULL)
833        return NULL;
834    result = PyTuple_Pack(5, action_obj, Py_None, category, Py_None, lineno);
835    Py_DECREF(lineno);
836    return result;
837}
838
839static PyObject *
840init_filters(void)
841{
842    /* Don't silence DeprecationWarning if -3 or -Q were used. */
843    PyObject *filters = PyList_New(Py_Py3kWarningFlag ||
844                                    Py_DivisionWarningFlag ? 3 : 4);
845    unsigned int pos = 0;  /* Post-incremented in each use. */
846    unsigned int x;
847    const char *bytes_action;
848
849    if (filters == NULL)
850        return NULL;
851
852    /* If guard changes, make sure to update 'filters' initialization above. */
853    if (!Py_Py3kWarningFlag && !Py_DivisionWarningFlag) {
854        PyList_SET_ITEM(filters, pos++,
855                        create_filter(PyExc_DeprecationWarning, "ignore"));
856    }
857    PyList_SET_ITEM(filters, pos++,
858                    create_filter(PyExc_PendingDeprecationWarning, "ignore"));
859    PyList_SET_ITEM(filters, pos++,
860                    create_filter(PyExc_ImportWarning, "ignore"));
861    if (Py_BytesWarningFlag > 1)
862        bytes_action = "error";
863    else if (Py_BytesWarningFlag)
864        bytes_action = "default";
865    else
866        bytes_action = "ignore";
867    PyList_SET_ITEM(filters, pos++, create_filter(PyExc_BytesWarning,
868                    bytes_action));
869
870    for (x = 0; x < pos; x += 1) {
871        if (PyList_GET_ITEM(filters, x) == NULL) {
872            Py_DECREF(filters);
873            return NULL;
874        }
875    }
876
877    return filters;
878}
879
880
881PyMODINIT_FUNC
882_PyWarnings_Init(void)
883{
884    PyObject *m;
885
886    m = Py_InitModule3(MODULE_NAME, warnings_functions, warnings__doc__);
887    if (m == NULL)
888        return;
889
890    _filters = init_filters();
891    if (_filters == NULL)
892        return;
893    Py_INCREF(_filters);
894    if (PyModule_AddObject(m, "filters", _filters) < 0)
895        return;
896
897    _once_registry = PyDict_New();
898    if (_once_registry == NULL)
899        return;
900    Py_INCREF(_once_registry);
901    if (PyModule_AddObject(m, "once_registry", _once_registry) < 0)
902        return;
903
904    _default_action = PyString_FromString("default");
905    if (_default_action == NULL)
906        return;
907    if (PyModule_AddObject(m, "default_action", _default_action) < 0)
908        return;
909}
910