Coverage Report

Created: 2026-10-17 06:15

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
108
#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
524
{
12
524
    Py_ssize_t i;
13
14
524
    assert(s->kind == ImportFrom_kind);
15
16
524
    asdl_alias_seq *names = s->v.ImportFrom.names;
17
975
    for (i = 0; i < asdl_seq_LEN(names); i++) {
18
559
        alias_ty name = (alias_ty)asdl_seq_GET(names, i);
19
559
        const char *feature = PyUnicode_AsUTF8(name->name);
20
559
        if (!feature)
21
0
            return 0;
22
559
        if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
23
73
            continue;
24
486
        } else if (strcmp(feature, FUTURE_GENERATORS) == 0) {
25
12
            continue;
26
474
        } else if (strcmp(feature, FUTURE_DIVISION) == 0) {
27
71
            continue;
28
403
        } else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) {
29
67
            continue;
30
336
        } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) {
31
10
            continue;
32
326
        } else if (strcmp(feature, FUTURE_PRINT_FUNCTION) == 0) {
33
10
            continue;
34
316
        } else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) {
35
30
            continue;
36
286
        } else if (strcmp(feature, FUTURE_BARRY_AS_BDFL) == 0) {
37
67
            ff->ff_features |= CO_FUTURE_BARRY_AS_BDFL;
38
219
        } else if (strcmp(feature, FUTURE_GENERATOR_STOP) == 0) {
39
18
            continue;
40
201
        } else if (strcmp(feature, FUTURE_ANNOTATIONS) == 0) {
41
93
            ff->ff_features |= CO_FUTURE_ANNOTATIONS;
42
108
        } 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
108
        } else {
52
            // Keep this list in sync with the feature checks above.
53
108
            PyObject *future_features = Py_BuildValue("[ssssssssss]",
54
108
                                                      FUTURE_NESTED_SCOPES,
55
108
                                                      FUTURE_GENERATORS,
56
108
                                                      FUTURE_DIVISION,
57
108
                                                      FUTURE_ABSOLUTE_IMPORT,
58
108
                                                      FUTURE_WITH_STATEMENT,
59
108
                                                      FUTURE_PRINT_FUNCTION,
60
108
                                                      FUTURE_UNICODE_LITERALS,
61
108
                                                      FUTURE_BARRY_AS_BDFL,
62
108
                                                      FUTURE_GENERATOR_STOP,
63
108
                                                      FUTURE_ANNOTATIONS);
64
108
            PyObject *suggestion = NULL;
65
108
            if (future_features != NULL) {
66
108
                suggestion = _Py_CalculateSuggestions(future_features,
67
108
                                                      name->name);
68
108
            }
69
108
            if (suggestion != NULL) {
70
29
                PyErr_Format(PyExc_SyntaxError,
71
29
                             UNDEFINED_FUTURE_FEATURE ". Did you mean: %R?",
72
29
                             feature, suggestion);
73
29
                Py_DECREF(suggestion);
74
29
            }
75
79
            else {
76
                // Do not fail on missing suggestion,
77
                // just show the default message.
78
79
                PyErr_Format(PyExc_SyntaxError,
79
79
                             UNDEFINED_FUTURE_FEATURE,
80
79
                             feature);
81
79
            }
82
108
            Py_XDECREF(future_features);
83
108
            PyErr_RangedSyntaxLocationObject(filename,
84
108
                                             name->lineno,
85
108
                                             name->col_offset + 1,
86
108
                                             name->end_lineno,
87
108
                                             name->end_col_offset + 1);
88
108
            return 0;
89
108
        }
90
559
    }
91
416
    return 1;
92
524
}
93
94
static int
95
future_parse(_PyFutureFeatures *ff, mod_ty mod, PyObject *filename)
96
8.23k
{
97
8.23k
    if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) {
98
196
        return 1;
99
196
    }
100
101
8.03k
    Py_ssize_t n = asdl_seq_LEN(mod->v.Module.body);
102
8.03k
    if (n == 0) {
103
1.39k
        return 1;
104
1.39k
    }
105
106
6.64k
    Py_ssize_t i = 0;
107
6.64k
    if (_PyAST_GetDocString(mod->v.Module.body) != NULL) {
108
421
        i++;
109
421
    }
110
111
7.05k
    for (; i < n; i++) {
112
6.74k
        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.74k
        if (s->kind == ImportFrom_kind && s->v.ImportFrom.level == 0) {
119
735
            identifier modname = s->v.ImportFrom.module;
120
735
            if (modname &&
121
735
                _PyUnicode_EqualToASCIIString(modname, "__future__")) {
122
524
                if (!future_check_features(ff, s, filename)) {
123
108
                    return 0;
124
108
                }
125
416
                ff->ff_location = SRC_LOCATION_FROM_AST(s);
126
416
            }
127
211
            else {
128
211
                return 1;
129
211
            }
130
735
        }
131
6.01k
        else {
132
6.01k
            return 1;
133
6.01k
        }
134
6.74k
    }
135
309
    return 1;
136
6.64k
}
137
138
139
int
140
_PyFuture_FromAST(mod_ty mod, PyObject *filename, _PyFutureFeatures *ff)
141
8.23k
{
142
8.23k
    ff->ff_features = 0;
143
8.23k
    ff->ff_location = (_Py_SourceLocation){-1, -1, -1, -1};
144
145
8.23k
    if (!future_parse(ff, mod, filename)) {
146
108
        return 0;
147
108
    }
148
8.12k
    return 1;
149
8.23k
}