Coverage Report

Created: 2026-08-31 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cpython3/Python/future.c
Line
Count
Source
1
#include "Python.h"
2
#include "pycore_ast.h"           // _PyAST_GetDocString()
3
#include "pycore_symtable.h"      // _PyFutureFeatures
4
#include "pycore_unicodeobject.h" // _PyUnicode_EqualToASCIIString()
5
6
15
#define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
7
8
static int
9
future_check_features(_PyFutureFeatures *ff, stmt_ty s, PyObject *filename)
10
1.49k
{
11
1.49k
    Py_ssize_t i;
12
13
1.49k
    assert(s->kind == ImportFrom_kind);
14
15
1.49k
    asdl_alias_seq *names = s->v.ImportFrom.names;
16
2.97k
    for (i = 0; i < asdl_seq_LEN(names); i++) {
17
1.49k
        alias_ty name = (alias_ty)asdl_seq_GET(names, i);
18
1.49k
        const char *feature = PyUnicode_AsUTF8(name->name);
19
1.49k
        if (!feature)
20
0
            return 0;
21
1.49k
        if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
22
0
            continue;
23
1.49k
        } else if (strcmp(feature, FUTURE_GENERATORS) == 0) {
24
0
            continue;
25
1.49k
        } else if (strcmp(feature, FUTURE_DIVISION) == 0) {
26
0
            continue;
27
1.49k
        } else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) {
28
0
            continue;
29
1.49k
        } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) {
30
0
            continue;
31
1.49k
        } else if (strcmp(feature, FUTURE_PRINT_FUNCTION) == 0) {
32
1
            continue;
33
1.49k
        } else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) {
34
0
            continue;
35
1.49k
        } else if (strcmp(feature, FUTURE_BARRY_AS_BDFL) == 0) {
36
0
            ff->ff_features |= CO_FUTURE_BARRY_AS_BDFL;
37
1.49k
        } else if (strcmp(feature, FUTURE_GENERATOR_STOP) == 0) {
38
0
            continue;
39
1.49k
        } else if (strcmp(feature, FUTURE_ANNOTATIONS) == 0) {
40
1.47k
            ff->ff_features |= CO_FUTURE_ANNOTATIONS;
41
1.47k
        } else if (strcmp(feature, "braces") == 0) {
42
0
            PyErr_SetString(PyExc_SyntaxError,
43
0
                            "not a chance");
44
0
            PyErr_RangedSyntaxLocationObject(filename,
45
0
                                             name->lineno,
46
0
                                             name->col_offset + 1,
47
0
                                             name->end_lineno,
48
0
                                             name->end_col_offset + 1);
49
0
            return 0;
50
15
        } else {
51
15
            PyErr_Format(PyExc_SyntaxError,
52
15
                         UNDEFINED_FUTURE_FEATURE, feature);
53
15
            PyErr_RangedSyntaxLocationObject(filename,
54
15
                                             name->lineno,
55
15
                                             name->col_offset + 1,
56
15
                                             name->end_lineno,
57
15
                                             name->end_col_offset + 1);
58
15
            return 0;
59
15
        }
60
1.49k
    }
61
1.48k
    return 1;
62
1.49k
}
63
64
static int
65
future_parse(_PyFutureFeatures *ff, mod_ty mod, PyObject *filename)
66
12.7k
{
67
12.7k
    if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) {
68
1.74k
        return 1;
69
1.74k
    }
70
71
11.0k
    Py_ssize_t n = asdl_seq_LEN(mod->v.Module.body);
72
11.0k
    if (n == 0) {
73
359
        return 1;
74
359
    }
75
76
10.6k
    Py_ssize_t i = 0;
77
10.6k
    if (_PyAST_GetDocString(mod->v.Module.body) != NULL) {
78
204
        i++;
79
204
    }
80
81
12.1k
    for (; i < n; i++) {
82
11.9k
        stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);
83
84
        /* The only things that can precede a future statement
85
         *  are another future statement and a doc string.
86
         */
87
88
11.9k
        if (s->kind == ImportFrom_kind && s->v.ImportFrom.level == 0) {
89
1.57k
            identifier modname = s->v.ImportFrom.module;
90
1.57k
            if (modname &&
91
1.57k
                _PyUnicode_EqualToASCIIString(modname, "__future__")) {
92
1.49k
                if (!future_check_features(ff, s, filename)) {
93
15
                    return 0;
94
15
                }
95
1.48k
                ff->ff_location = SRC_LOCATION_FROM_AST(s);
96
1.48k
            }
97
83
            else {
98
83
                return 1;
99
83
            }
100
1.57k
        }
101
10.3k
        else {
102
10.3k
            return 1;
103
10.3k
        }
104
11.9k
    }
105
192
    return 1;
106
10.6k
}
107
108
109
int
110
_PyFuture_FromAST(mod_ty mod, PyObject *filename, _PyFutureFeatures *ff)
111
12.7k
{
112
12.7k
    ff->ff_features = 0;
113
12.7k
    ff->ff_location = (_Py_SourceLocation){-1, -1, -1, -1};
114
115
12.7k
    if (!future_parse(ff, mod, filename)) {
116
15
        return 0;
117
15
    }
118
12.7k
    return 1;
119
12.7k
}