Coverage Report

Created: 2026-10-31 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython/Python/future.c
Line
Count
Source
1
#include "Python.h"
2
#include "pycore_ast.h"           // _PyAST_GetDocString()
3
#include "pycore_pyerrors.h"      // _Py_CalculateSuggestions()
4
#include "pycore_symtable.h"      // _PyFutureFeatures
5
#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString()
6
7
111
#define UNDEFINED_FUTURE_FEATURE "future feature '%.100s' is not defined"
8
9
static int
10
future_check_features(_PyFutureFeatures *ff, stmt_ty s, PyObject *filename)
11
532
{
12
532
    Py_ssize_t i;
13
14
532
    assert(s->kind == ImportFrom_kind);
15
16
532
    asdl_alias_seq *names = s->v.ImportFrom.names;
17
986
    for (i = 0; i < asdl_seq_LEN(names); i++) {
18
565
        alias_ty name = (alias_ty)asdl_seq_GET(names, i);
19
565
        const char *feature = PyUnicode_AsUTF8(name->name);
20
565
        if (!feature)
21
0
            return 0;
22
565
        if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
23
73
            continue;
24
492
        } else if (strcmp(feature, FUTURE_GENERATORS) == 0) {
25
12
            continue;
26
480
        } else if (strcmp(feature, FUTURE_DIVISION) == 0) {
27
70
            continue;
28
410
        } else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) {
29
77
            continue;
30
333
        } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) {
31
11
            continue;
32
322
        } else if (strcmp(feature, FUTURE_PRINT_FUNCTION) == 0) {
33
10
            continue;
34
312
        } else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) {
35
28
            continue;
36
284
        } else if (strcmp(feature, FUTURE_BARRY_AS_BDFL) == 0) {
37
66
            ff->ff_features |= CO_FUTURE_BARRY_AS_BDFL;
38
218
        } else if (strcmp(feature, FUTURE_GENERATOR_STOP) == 0) {
39
18
            continue;
40
200
        } else if (strcmp(feature, FUTURE_ANNOTATIONS) == 0) {
41
89
            ff->ff_features |= CO_FUTURE_ANNOTATIONS;
42
111
        } else if (strcmp(feature, "braces") == 0) {
43
0
            PyErr_SetString(PyExc_SyntaxError,
44
0
                            "not a chance");
45
0
            PyErr_RangedSyntaxLocationObject(filename,
46
0
                                             name->lineno,
47
0
                                             name->col_offset + 1,
48
0
                                             name->end_lineno,
49
0
                                             name->end_col_offset + 1);
50
0
            return 0;
51
111
        } else {
52
            // Keep this list in sync with the feature checks above.
53
111
            PyObject *future_features = Py_BuildValue("[ssssssssss]",
54
111
                                                      FUTURE_NESTED_SCOPES,
55
111
                                                      FUTURE_GENERATORS,
56
111
                                                      FUTURE_DIVISION,
57
111
                                                      FUTURE_ABSOLUTE_IMPORT,
58
111
                                                      FUTURE_WITH_STATEMENT,
59
111
                                                      FUTURE_PRINT_FUNCTION,
60
111
                                                      FUTURE_UNICODE_LITERALS,
61
111
                                                      FUTURE_BARRY_AS_BDFL,
62
111
                                                      FUTURE_GENERATOR_STOP,
63
111
                                                      FUTURE_ANNOTATIONS);
64
111
            PyObject *suggestion = NULL;
65
111
            if (future_features != NULL) {
66
111
                suggestion = _Py_CalculateSuggestions(future_features,
67
111
                                                      name->name);
68
111
            }
69
111
            if (suggestion != NULL) {
70
25
                PyErr_Format(PyExc_SyntaxError,
71
25
                             UNDEFINED_FUTURE_FEATURE ". Did you mean: %R?",
72
25
                             feature, suggestion);
73
25
                Py_DECREF(suggestion);
74
25
            }
75
86
            else {
76
                // Do not fail on missing suggestion,
77
                // just show the default message.
78
86
                PyErr_Format(PyExc_SyntaxError,
79
86
                             UNDEFINED_FUTURE_FEATURE,
80
86
                             feature);
81
86
            }
82
111
            Py_XDECREF(future_features);
83
111
            PyErr_RangedSyntaxLocationObject(filename,
84
111
                                             name->lineno,
85
111
                                             name->col_offset + 1,
86
111
                                             name->end_lineno,
87
111
                                             name->end_col_offset + 1);
88
111
            return 0;
89
111
        }
90
565
    }
91
421
    return 1;
92
532
}
93
94
static int
95
future_parse(_PyFutureFeatures *ff, mod_ty mod, PyObject *filename)
96
8.29k
{
97
8.29k
    if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) {
98
172
        return 1;
99
172
    }
100
101
8.12k
    Py_ssize_t n = asdl_seq_LEN(mod->v.Module.body);
102
8.12k
    if (n == 0) {
103
1.42k
        return 1;
104
1.42k
    }
105
106
6.70k
    Py_ssize_t i = 0;
107
6.70k
    if (_PyAST_GetDocString(mod->v.Module.body) != NULL) {
108
435
        i++;
109
435
    }
110
111
7.12k
    for (; i < n; i++) {
112
6.80k
        stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);
113
114
        /* The only things that can precede a future statement
115
         *  are another future statement and a doc string.
116
         */
117
118
6.80k
        if (s->kind == ImportFrom_kind && s->v.ImportFrom.level == 0) {
119
742
            identifier modname = s->v.ImportFrom.module;
120
742
            if (modname &&
121
742
                _PyUnicode_EqualToASCIIString(modname, "__future__")) {
122
532
                if (!future_check_features(ff, s, filename)) {
123
111
                    return 0;
124
111
                }
125
421
                ff->ff_location = SRC_LOCATION_FROM_AST(s);
126
421
            }
127
210
            else {
128
210
                return 1;
129
210
            }
130
742
        }
131
6.06k
        else {
132
6.06k
            return 1;
133
6.06k
        }
134
6.80k
    }
135
321
    return 1;
136
6.70k
}
137
138
139
int
140
_PyFuture_FromAST(mod_ty mod, PyObject *filename, _PyFutureFeatures *ff)
141
8.29k
{
142
8.29k
    ff->ff_features = 0;
143
8.29k
    ff->ff_location = (_Py_SourceLocation){-1, -1, -1, -1};
144
145
8.29k
    if (!future_parse(ff, mod, filename)) {
146
111
        return 0;
147
111
    }
148
8.18k
    return 1;
149
8.29k
}