LCOV - code coverage report
Current view: top level - Python - future.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 72 75 96.0 %
Date: 2022-07-07 18:19:46 Functions: 3 3 100.0 %

          Line data    Source code
       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        1043 : future_check_features(PyFutureFeatures *ff, stmt_ty s, PyObject *filename)
      10             : {
      11             :     int i;
      12             : 
      13        1043 :     assert(s->kind == ImportFrom_kind);
      14             : 
      15        1043 :     asdl_alias_seq *names = s->v.ImportFrom.names;
      16        2718 :     for (i = 0; i < asdl_seq_LEN(names); i++) {
      17        1683 :         alias_ty name = (alias_ty)asdl_seq_GET(names, i);
      18        1683 :         const char *feature = PyUnicode_AsUTF8(name->name);
      19        1683 :         if (!feature)
      20           0 :             return 0;
      21        1683 :         if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
      22          15 :             continue;
      23        1668 :         } else if (strcmp(feature, FUTURE_GENERATORS) == 0) {
      24           3 :             continue;
      25        1665 :         } else if (strcmp(feature, FUTURE_DIVISION) == 0) {
      26         330 :             continue;
      27        1335 :         } else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) {
      28         656 :             continue;
      29         679 :         } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) {
      30           1 :             continue;
      31         678 :         } else if (strcmp(feature, FUTURE_PRINT_FUNCTION) == 0) {
      32         105 :             continue;
      33         573 :         } else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) {
      34         311 :             continue;
      35         262 :         } else if (strcmp(feature, FUTURE_BARRY_AS_BDFL) == 0) {
      36           1 :             ff->ff_features |= CO_FUTURE_BARRY_AS_BDFL;
      37         261 :         } else if (strcmp(feature, FUTURE_GENERATOR_STOP) == 0) {
      38           2 :             continue;
      39         259 :         } else if (strcmp(feature, FUTURE_ANNOTATIONS) == 0) {
      40         251 :             ff->ff_features |= CO_FUTURE_ANNOTATIONS;
      41           8 :         } else if (strcmp(feature, "braces") == 0) {
      42           3 :             PyErr_SetString(PyExc_SyntaxError,
      43             :                             "not a chance");
      44           3 :             PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset + 1);
      45           3 :             return 0;
      46             :         } else {
      47           5 :             PyErr_Format(PyExc_SyntaxError,
      48             :                          UNDEFINED_FUTURE_FEATURE, feature);
      49           5 :             PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset + 1);
      50           5 :             return 0;
      51             :         }
      52             :     }
      53        1035 :     return 1;
      54             : }
      55             : 
      56             : static int
      57      114701 : future_parse(PyFutureFeatures *ff, mod_ty mod, PyObject *filename)
      58             : {
      59      114701 :     int i, done = 0, prev_line = 0;
      60             : 
      61      114701 :     if (!(mod->kind == Module_kind || mod->kind == Interactive_kind))
      62       72424 :         return 1;
      63             : 
      64       42277 :     if (asdl_seq_LEN(mod->v.Module.body) == 0)
      65         678 :         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       41599 :     i = 0;
      76       41599 :     if (_PyAST_GetDocString(mod->v.Module.body) != NULL)
      77        4945 :         i++;
      78             : 
      79       86440 :     for (; i < asdl_seq_LEN(mod->v.Module.body); i++) {
      80       56750 :         stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);
      81             : 
      82       56750 :         if (done && s->lineno > prev_line)
      83       11899 :             return 1;
      84       44851 :         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       44851 :         if (s->kind == ImportFrom_kind) {
      93        4635 :             identifier modname = s->v.ImportFrom.module;
      94        9092 :             if (modname &&
      95        4457 :                 _PyUnicode_EqualToASCIIString(modname, "__future__")) {
      96        1045 :                 if (done) {
      97           2 :                     PyErr_SetString(PyExc_SyntaxError,
      98             :                                     ERR_LATE_FUTURE);
      99           2 :                     PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset);
     100           2 :                     return 0;
     101             :                 }
     102        1043 :                 if (!future_check_features(ff, s, filename))
     103           8 :                     return 0;
     104        1035 :                 ff->ff_lineno = s->lineno;
     105             :             }
     106             :             else {
     107        3590 :                 done = 1;
     108             :             }
     109             :         }
     110             :         else {
     111       40216 :             done = 1;
     112             :         }
     113             :     }
     114       29690 :     return 1;
     115             : }
     116             : 
     117             : 
     118             : PyFutureFeatures *
     119      114701 : _PyFuture_FromAST(mod_ty mod, PyObject *filename)
     120             : {
     121             :     PyFutureFeatures *ff;
     122             : 
     123      114701 :     ff = (PyFutureFeatures *)PyObject_Malloc(sizeof(PyFutureFeatures));
     124      114701 :     if (ff == NULL) {
     125           0 :         PyErr_NoMemory();
     126           0 :         return NULL;
     127             :     }
     128      114701 :     ff->ff_features = 0;
     129      114701 :     ff->ff_lineno = -1;
     130             : 
     131      114701 :     if (!future_parse(ff, mod, filename)) {
     132          10 :         PyObject_Free(ff);
     133          10 :         return NULL;
     134             :     }
     135      114691 :     return ff;
     136             : }

Generated by: LCOV version 1.14