Coverage Report

Created: 2022-07-08 09:39

/home/mdboom/Work/builds/cpython/Python/future.c
Line
Count
Source (jump to first uncovered line)
1
#include "Python.h"
2
#include "pycore_ast.h"           // _PyAST_GetDocString()
3
4
#define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
5
#define ERR_LATE_FUTURE \
6
"from __future__ imports must occur at the beginning of the file"
7
8
static int
9
future_check_features(PyFutureFeatures *ff, stmt_ty s, PyObject *filename)
10
{
11
    int i;
12
13
    assert(s->kind == ImportFrom_kind);
14
15
    asdl_alias_seq *names = s->v.ImportFrom.names;
16
    for (i = 0; i < asdl_seq_LEN(names); 
i++216
) {
  Branch (16:17): [True: 224, False: 211]
17
        alias_ty name = (alias_ty)asdl_seq_GET(names, i);
18
        const char *feature = PyUnicode_AsUTF8(name->name);
19
        if (!feature)
  Branch (19:13): [True: 0, False: 224]
20
            return 0;
21
        if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
  Branch (21:13): [True: 11, False: 213]
22
            continue;
23
        } else if (strcmp(feature, FUTURE_GENERATORS) == 0) {
  Branch (23:20): [True: 3, False: 210]
24
            continue;
25
        } else if (strcmp(feature, FUTURE_DIVISION) == 0) {
  Branch (25:20): [True: 1, False: 209]
26
            continue;
27
        } else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) {
  Branch (27:20): [True: 12, False: 197]
28
            continue;
29
        } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) {
  Branch (29:20): [True: 0, False: 197]
30
            continue;
31
        } else if (strcmp(feature, FUTURE_PRINT_FUNCTION) == 0) {
  Branch (31:20): [True: 0, False: 197]
32
            continue;
33
        } else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) {
  Branch (33:20): [True: 1, False: 196]
34
            continue;
35
        } else if (strcmp(feature, FUTURE_BARRY_AS_BDFL) == 0) {
  Branch (35:20): [True: 1, False: 195]
36
            ff->ff_features |= CO_FUTURE_BARRY_AS_BDFL;
37
        } else if (strcmp(feature, FUTURE_GENERATOR_STOP) == 0) {
  Branch (37:20): [True: 1, False: 194]
38
            continue;
39
        } else if (strcmp(feature, FUTURE_ANNOTATIONS) == 0) {
  Branch (39:20): [True: 186, False: 8]
40
            ff->ff_features |= CO_FUTURE_ANNOTATIONS;
41
        } else 
if (8
strcmp(feature, "braces") == 08
) {
  Branch (41:20): [True: 3, False: 5]
42
            PyErr_SetString(PyExc_SyntaxError,
43
                            "not a chance");
44
            PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset + 1);
45
            return 0;
46
        } else {
47
            PyErr_Format(PyExc_SyntaxError,
48
                         UNDEFINED_FUTURE_FEATURE, feature);
49
            PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset + 1);
50
            return 0;
51
        }
52
    }
53
    return 1;
54
}
55
56
static int
57
future_parse(PyFutureFeatures *ff, mod_ty mod, PyObject *filename)
58
{
59
    int i, done = 0, prev_line = 0;
60
61
    if (!(mod->kind == Module_kind || 
mod->kind == Interactive_kind40.0k
))
  Branch (61:11): [True: 8.78k, False: 40.0k]
  Branch (61:39): [True: 4.10k, False: 35.9k]
62
        return 1;
63
64
    if (asdl_seq_LEN(mod->v.Module.body) == 0)
  Branch (64:9): [True: 299, False: 12.5k]
65
        return 1;
66
67
    /* A subsequent pass will detect future imports that don't
68
       appear at the beginning of the file.  There's one case,
69
       however, that is easier to handle here: A series of imports
70
       joined by semi-colons, where the first import is a future
71
       statement but some subsequent import has the future form
72
       but is preceded by a regular import.
73
    */
74
75
    i = 0;
76
    if (_PyAST_GetDocString(mod->v.Module.body) != NULL)
  Branch (76:9): [True: 317, False: 12.2k]
77
        i++;
78
79
    for (; i < asdl_seq_LEN(mod->v.Module.body); 
i++13.0k
) {
  Branch (79:12): [True: 14.6k, False: 11.0k]
80
        stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);
81
82
        if (done && 
s->lineno > prev_line1.87k
)
  Branch (82:13): [True: 1.87k, False: 12.7k]
  Branch (82:21): [True: 1.57k, False: 303]
83
            return 1;
84
        prev_line = s->lineno;
85
86
        /* The tests below will return from this function unless it is
87
           still possible to find a future statement.  The only things
88
           that can precede a future statement are another future
89
           statement and a doc string.
90
        */
91
92
        if (s->kind == ImportFrom_kind) {
  Branch (92:13): [True: 693, False: 12.3k]
93
            identifier modname = s->v.ImportFrom.module;
94
            if (modname &&
  Branch (94:17): [True: 676, False: 17]
95
                
_PyUnicode_EqualToASCIIString(modname, "__future__")676
) {
  Branch (95:17): [True: 221, False: 455]
96
                if (done) {
  Branch (96:21): [True: 2, False: 219]
97
                    PyErr_SetString(PyExc_SyntaxError,
98
                                    ERR_LATE_FUTURE);
99
                    PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset);
100
                    return 0;
101
                }
102
                if (!future_check_features(ff, s, filename))
  Branch (102:21): [True: 8, False: 211]
103
                    return 0;
104
                ff->ff_lineno = s->lineno;
105
            }
106
            else {
107
                done = 1;
108
            }
109
        }
110
        else {
111
            done = 1;
112
        }
113
    }
114
    return 1;
115
}
116
117
118
PyFutureFeatures *
119
_PyFuture_FromAST(mod_ty mod, PyObject *filename)
120
{
121
    PyFutureFeatures *ff;
122
123
    ff = (PyFutureFeatures *)PyObject_Malloc(sizeof(PyFutureFeatures));
124
    if (ff == NULL) {
  Branch (124:9): [True: 0, False: 48.8k]
125
        PyErr_NoMemory();
126
        return NULL;
127
    }
128
    ff->ff_features = 0;
129
    ff->ff_lineno = -1;
130
131
    if (!future_parse(ff, mod, filename)) {
  Branch (131:9): [True: 10, False: 48.7k]
132
        PyObject_Free(ff);
133
        return NULL;
134
    }
135
    return ff;
136
}