]> granicus.if.org Git - python/commitdiff
from __future__ import with_statement addon for 'with', mostly written by
authorThomas Wouters <thomas@python.org>
Tue, 28 Feb 2006 19:02:24 +0000 (19:02 +0000)
committerThomas Wouters <thomas@python.org>
Tue, 28 Feb 2006 19:02:24 +0000 (19:02 +0000)
Neal.

16 files changed:
Include/code.h
Include/compile.h
Include/modsupport.h
Include/parsetok.h
Include/pythonrun.h
Lib/__future__.py
Lib/compiler/future.py
Lib/test/test_with.py
Misc/NEWS
Parser/parser.c
Parser/parser.h
Parser/parsetok.c
Python/Python-ast.c
Python/compile.c
Python/future.c
Python/pythonrun.c

index e81b576747f0a4987edbeb980d00dbb501980e36..9e6cb5637e83f24252082d8782c563100b0d182e 100644 (file)
@@ -46,6 +46,12 @@ typedef struct {
 #endif
 #define CO_FUTURE_DIVISION     0x2000
 #define CO_FUTURE_ABSIMPORT    0x4000 /* absolute import by default */
+#define CO_FUTURE_WITH_STATEMENT  0x8000
+
+/* This should be defined if a future statement modifies the syntax.
+   For example, when a keyword is added.
+*/
+#define PY_PARSER_REQUIRES_FUTURE_KEYWORD
 
 #define CO_MAXBLOCKS 20 /* Max static block nesting within a function */
 
index 66b445e43e91e3f8e73a49acff01cc930b9cfeda..01ba25c6e02e80cf4d9e99f17e8f840f87c7e279 100644 (file)
@@ -23,6 +23,7 @@ typedef struct {
 #define FUTURE_GENERATORS "generators"
 #define FUTURE_DIVISION "division"
 #define FUTURE_ABSIMPORT "absolute_import"
+#define FUTURE_WITH_STATEMENT "with_statement"
 
 struct _mod; /* Declare the existence of this type */
 PyAPI_FUNC(PyCodeObject *) PyAST_Compile(struct _mod *, const char *,
index a56d07cf12c38fa3c71ee7bb7eaa6e4547a6a245..c31c5be1be1b99051898548dc08a60eb7065651b 100644 (file)
@@ -39,8 +39,8 @@ PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long);
 PyAPI_FUNC(int) PyModule_AddStringConstant(PyObject *, const char *, const char *);
 
 
-#define PYTHON_API_VERSION 1012
-#define PYTHON_API_STRING "1012"
+#define PYTHON_API_VERSION 1013
+#define PYTHON_API_STRING "1013"
 /* The API version is maintained (independently from the Python version)
    so we can detect mismatches between the interpreter and dynamically
    loaded modules.  These are diagnosed by an error message but
@@ -54,6 +54,8 @@ PyAPI_FUNC(int) PyModule_AddStringConstant(PyObject *, const char *, const char
    Please add a line or two to the top of this log for each API
    version change:
 
+   22-Feb-2006  GvR    1013    PEP 353 - long indices for sequence lengths
+
    19-Aug-2002  GvR    1012    Changes to string object struct for
                                interning changes, saving 3 bytes.
 
index b78856685e985347441d44b3e2584ffefc013132..0f87e81f035a9b86c8f656564ca33082c8679c29 100644 (file)
@@ -23,6 +23,8 @@ typedef struct {
 
 #define PyPARSE_DONT_IMPLY_DEDENT      0x0002
 
+#define PyPARSE_WITH_IS_KEYWORD                0x0003
+
 PyAPI_FUNC(node *) PyParser_ParseString(const char *, grammar *, int,
                                               perrdetail *);
 PyAPI_FUNC(node *) PyParser_ParseFile (FILE *, const char *, grammar *, int,
index 5949d5b4a4cb98333ccf730cbf2d1f7056008b29..feb79ae6da352ddc35111268eafba4e214fd9455 100644 (file)
@@ -7,7 +7,8 @@
 extern "C" {
 #endif
 
-#define PyCF_MASK (CO_FUTURE_DIVISION | CO_FUTURE_ABSIMPORT)
+#define PyCF_MASK (CO_FUTURE_DIVISION | CO_FUTURE_ABSIMPORT | \
+                   CO_FUTURE_WITH_STATEMENT)
 #define PyCF_MASK_OBSOLETE (CO_NESTED)
 #define PyCF_SOURCE_IS_UTF8  0x0100
 #define PyCF_DONT_IMPLY_DEDENT 0x0200
index e49c66364549c5901b84e7309ac594ec53a578bc..e661260df7fca8bb897af717c626d23fa3ab4ef7 100644 (file)
@@ -52,6 +52,7 @@ all_feature_names = [
     "generators",
     "division",
     "absolute_import",
+    "with_statement",
 ]
 
 __all__ = ["all_feature_names"] + all_feature_names
@@ -64,6 +65,7 @@ CO_NESTED            = 0x0010   # nested_scopes
 CO_GENERATOR_ALLOWED = 0        # generators (obsolete, was 0x1000)
 CO_FUTURE_DIVISION   = 0x2000   # division
 CO_FUTURE_ABSIMPORT  = 0x4000   # absolute_import
+CO_FUTURE_WITH_STATEMENT  = 0x8000   # with statement added in 2.5
 
 class _Feature:
     def __init__(self, optionalRelease, mandatoryRelease, compiler_flag):
@@ -108,3 +110,7 @@ division = _Feature((2, 2, 0, "alpha", 2),
 absolute_import = _Feature((2, 5, 0, "alpha", 1),
                            (2, 7, 0, "alpha", 0),
                            CO_FUTURE_ABSIMPORT)
+
+with_statement = _Feature((2, 5, 0, "alpha", 2),
+                          (2, 6, 0, "alpha", 0),
+                          CO_FUTURE_WITH_STATEMENT)
index 414e64e8880815ba229f6ada37d9185391458ec2..39c3bb9bdc390337433430d7464810f90d75afa7 100644 (file)
@@ -15,7 +15,8 @@ def is_future(stmt):
 
 class FutureParser:
 
-    features = ("nested_scopes", "generators", "division")
+    features = ("nested_scopes", "generators", "division",
+                "absolute_import", "with_statement")
 
     def __init__(self):
         self.found = {} # set
index 8423ee1d290eff858559e51b3599a4dccfc7b81c..ed072c9573d7171cda3fae09733f803fc4f38576 100644 (file)
@@ -2,6 +2,8 @@
 
 """Unit tests for the with statement specified in PEP 343."""
 
+from __future__ import with_statement
+
 __author__ = "Mike Bland"
 __email__ = "mbland at acm dot org"
 
index 1a08651e34387f0edba1e5df3ed46dadf53f2029..b9c424b11888520e28c611133ee953e430c87264 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -32,7 +32,8 @@ Core and builtins
   - dict.__getitem__ now looks for a __missing__ hook before raising
     KeyError.
 
-- PEP 343: with statement implemented.
+- PEP 343: with statement implemented. Needs 'from __future__ import
+  with_statement'. Use of 'with' as a variable will generate a warning.
 
 - Fix the encodings package codec search function to only search
   inside its own package. Fixes problem reported in patch #1433198.
index 686161b2bbfebfa453fbe51e811b013c4fa85455..cad5ce20646c298c7db9ccf250ee136fc0a6d6d2 100644 (file)
@@ -79,8 +79,8 @@ PyParser_New(grammar *g, int start)
        if (ps == NULL)
                return NULL;
        ps->p_grammar = g;
-#if 0 /* future keyword */
-       ps->p_generators = 0;
+#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
+       ps->p_flags = 0;
 #endif
        ps->p_tree = PyNode_New(start);
        if (ps->p_tree == NULL) {
@@ -147,10 +147,10 @@ classify(parser_state *ps, int type, char *str)
                        if (l->lb_type == NAME && l->lb_str != NULL &&
                                        l->lb_str[0] == s[0] &&
                                        strcmp(l->lb_str, s) == 0) {
-#if 0 /* future keyword */
-                               if (!ps->p_generators &&
-                                   s[0] == 'y' &&
-                                   strcmp(s, "yield") == 0)
+#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
+                               if (!(ps->p_flags & CO_FUTURE_WITH_STATEMENT) &&
+                                   s[0] == 'w' &&
+                                   strcmp(s, "with") == 0)
                                        break; /* not a keyword */
 #endif
                                D(printf("It's a keyword\n"));
@@ -174,7 +174,7 @@ classify(parser_state *ps, int type, char *str)
        return -1;
 }
 
-#if 0 /* future keyword */
+#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
 static void
 future_hack(parser_state *ps)
 {
@@ -182,16 +182,27 @@ future_hack(parser_state *ps)
        node *ch;
        int i;
 
-       if (strcmp(STR(CHILD(n, 0)), "from") != 0)
+       /* from __future__ import ..., must have at least 4 children */
+       n = CHILD(n, 0);
+       if (NCH(n) < 4)
+               return;
+       ch = CHILD(n, 0);
+       if (STR(ch) == NULL || strcmp(STR(ch), "from") != 0)
                return;
        ch = CHILD(n, 1);
-       if (strcmp(STR(CHILD(ch, 0)), "__future__") != 0)
+       if (NCH(ch) == 1 && STR(CHILD(ch, 0)) &&
+           strcmp(STR(CHILD(ch, 0)), "__future__") != 0)
                return;
        for (i = 3; i < NCH(n); i += 2) {
+               /* XXX: assume we don't have parentheses in import:
+                       from __future__ import (x, y, z)
+               */
                ch = CHILD(n, i);
+               if (NCH(ch) == 1)
+                       ch = CHILD(ch, 0);
                if (NCH(ch) >= 1 && TYPE(CHILD(ch, 0)) == NAME &&
-                   strcmp(STR(CHILD(ch, 0)), "generators") == 0) {
-                       ps->p_generators = 1;
+                   strcmp(STR(CHILD(ch, 0)), "with_statement") == 0) {
+                       ps->p_flags |= CO_FUTURE_WITH_STATEMENT;
                        break;
                }
        }
@@ -255,7 +266,7 @@ PyParser_AddToken(register parser_state *ps, register int type, char *str,
                                                 "Direct pop.\n",
                                                 d->d_name,
                                                 ps->p_stack.s_top->s_state));
-#if 0 /* future keyword */
+#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
                                        if (d->d_name[0] == 'i' &&
                                            strcmp(d->d_name,
                                                   "import_stmt") == 0)
@@ -273,7 +284,7 @@ PyParser_AddToken(register parser_state *ps, register int type, char *str,
                }
                
                if (s->s_accept) {
-#if 0 /* future keyword */
+#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
                        if (d->d_name[0] == 'i' &&
                            strcmp(d->d_name, "import_stmt") == 0)
                                future_hack(ps);
index 95ec2477d89aa0276fdb567aa1329d1439a1af61..f5d2d0d0da3ce21607cc01d930cdcf169616c610 100644 (file)
@@ -25,8 +25,8 @@ typedef struct {
        stack           p_stack;        /* Stack of parser states */
        grammar         *p_grammar;     /* Grammar to use */
        node            *p_tree;        /* Top of parse tree */
-#if 0 /* future keyword */
-       int             p_generators;   /* 1 if yield is a keyword */
+#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
+       unsigned long   p_flags;        /* see co_flags in Include/code.h */
 #endif
 } parser_state;
 
index 4c533f10e116d6248f5789faaaabde6b4f4e148f..cf445e1bfbed9721871f0a1e7d4827920b60fb35 100644 (file)
@@ -92,10 +92,19 @@ PyParser_ParseFileFlags(FILE *fp, const char *filename, grammar *g, int start,
 /* Parse input coming from the given tokenizer structure.
    Return error code. */
 
-#if 0 /* future keyword */
-static char yield_msg[] =
-"%s:%d: Warning: 'yield' will become a reserved keyword in the future\n";
-#endif
+static char with_msg[] =
+"%s:%d: Warning: 'with' will become a reserved keyword in Python 2.6\n";
+
+static char as_msg[] =
+"%s:%d: Warning: 'as' will become a reserved keyword in Python 2.6\n";
+
+static void
+warn(const char *msg, const char *filename, int lineno)
+{
+       if (filename == NULL)
+               filename = "<string>";
+       PySys_WriteStderr(msg, filename, lineno);
+}
 
 static node *
 parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
@@ -103,7 +112,7 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
 {
        parser_state *ps;
        node *n;
-       int started = 0;
+       int started = 0, handling_import = 0, handling_with = 0;
 
        if ((ps = PyParser_New(g, start)) == NULL) {
                fprintf(stderr, "no mem for new parser\n");
@@ -111,9 +120,9 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
                PyTokenizer_Free(tok);
                return NULL;
        }
-#if 0 /* future keyword */
-       if (flags & PyPARSE_YIELD_IS_KEYWORD)
-               ps->p_generators = 1;
+#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
+       if (flags & PyPARSE_WITH_IS_KEYWORD)
+               ps->p_flags |= CO_FUTURE_WITH_STATEMENT;
 #endif
 
        for (;;) {
@@ -129,6 +138,7 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
                }
                if (type == ENDMARKER && started) {
                        type = NEWLINE; /* Add an extra newline */
+                       handling_with = handling_import = 0;
                        started = 0;
                        /* Add the right number of dedent tokens,
                           except if a certain flag is given --
@@ -153,14 +163,27 @@ parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret,
                        strncpy(str, a, len);
                str[len] = '\0';
 
-#if 0 /* future keyword */
-               /* Warn about yield as NAME */
-               if (type == NAME && !ps->p_generators &&
-                   len == 5 && str[0] == 'y' && strcmp(str, "yield") == 0)
-                       PySys_WriteStderr(yield_msg,
-                                         err_ret->filename==NULL ?
-                                         "<string>" : err_ret->filename,
-                                         tok->lineno);
+#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD
+               /* This is only necessary to support the "as" warning, but
+                  we don't want to warn about "as" in import statements. */
+               if (type == NAME &&
+                   len == 6 && str[0] == 'i' && strcmp(str, "import") == 0)
+                       handling_import = 1;
+
+               /* Warn about with as NAME */
+               if (type == NAME &&
+                   !(ps->p_flags & CO_FUTURE_WITH_STATEMENT)) {
+                   if (len == 4 && str[0] == 'w' && strcmp(str, "with") == 0)
+                       warn(with_msg, err_ret->filename, tok->lineno);
+                   else if (!(handling_import || handling_with) &&
+                            len == 2 &&
+                            str[0] == 'a' && strcmp(str, "as") == 0)
+                       warn(as_msg, err_ret->filename, tok->lineno);
+               }
+               else if (type == NAME &&
+                        (ps->p_flags & CO_FUTURE_WITH_STATEMENT) &&
+                        len == 4 && str[0] == 'w' && strcmp(str, "with") == 0)
+                       handling_with = 1;
 #endif
 
                if ((err_ret->error =
index 07de6cb6adca99ba94505ac566522fb2f84e53a2..c4861c3ae1100177fbb8de8c7ba8511bab382d57 100644 (file)
@@ -371,7 +371,7 @@ static PyTypeObject* make_type(char *type, PyTypeObject* base, char**fields, int
         }
         PyTuple_SET_ITEM(fnames, i, field);
     }
-    result = PyObject_CallFunction((PyObject*)&PyType_Type, "s(O){sOss}", 
+    result = PyObject_CallFunction((PyObject*)&PyType_Type, "s(O){sOss}",
                     type, base, "_fields", fnames, "__module__", "_ast");
     Py_DECREF(fnames);
     return (PyTypeObject*)result;
@@ -2956,7 +2956,7 @@ init_ast(void)
         if (PyDict_SetItemString(d, "AST", (PyObject*)AST_type) < 0) return;
         if (PyModule_AddIntConstant(m, "PyCF_ONLY_AST", PyCF_ONLY_AST) < 0)
                 return;
-        if (PyModule_AddStringConstant(m, "__version__", "42635") < 0)
+        if (PyModule_AddStringConstant(m, "__version__", "42649") < 0)
                 return;
         if(PyDict_SetItemString(d, "mod", (PyObject*)mod_type) < 0) return;
         if(PyDict_SetItemString(d, "Module", (PyObject*)Module_type) < 0)
index 78ae6a7f7f6b52ccad2ec1d58984962ba9ec855a..13e0f6d34d79fb08696674f645fc865d9a42ee22 100644 (file)
@@ -4286,6 +4286,8 @@ compute_code_flags(struct compiler *c)
                flags |= CO_GENERATOR;
         if (c->c_flags->cf_flags & CO_FUTURE_DIVISION)
                 flags |= CO_FUTURE_DIVISION;
+        if (c->c_flags->cf_flags & CO_FUTURE_WITH_STATEMENT)
+                flags |= CO_FUTURE_WITH_STATEMENT;
        n = PyDict_Size(c->u->u_freevars);
        if (n < 0)
            return -1;
index 0a87b10066870178eccd1466f09e1763db9b4180..4a48ba53e4c9ba206caab081a94eb0896f7b7d57 100644 (file)
@@ -31,6 +31,8 @@ future_check_features(PyFutureFeatures *ff, stmt_ty s, const char *filename)
                        ff->ff_features |= CO_FUTURE_DIVISION;
                } else if (strcmp(feature, FUTURE_ABSIMPORT) == 0) {
                        ff->ff_features |= CO_FUTURE_ABSIMPORT;
+               } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) {
+                       ff->ff_features |= CO_FUTURE_WITH_STATEMENT;
                } else if (strcmp(feature, "braces") == 0) {
                        PyErr_SetString(PyExc_SyntaxError,
                                        "not a chance");
index 2a6afe24a4a09b91830bb39844947c227c82cd00..d5c86f2a1f6cd04bcb9e4bac39c063e073a5c3c0 100644 (file)
@@ -690,8 +690,10 @@ PyRun_InteractiveLoopFlags(FILE *fp, const char *filename, PyCompilerFlags *flag
 
 /* compute parser flags based on compiler flags */
 #define PARSER_FLAGS(flags) \
-       (((flags) && (flags)->cf_flags & PyCF_DONT_IMPLY_DEDENT) ? \
-               PyPARSE_DONT_IMPLY_DEDENT : 0)
+       ((flags) ? ((((flags)->cf_flags & PyCF_DONT_IMPLY_DEDENT) ? \
+                     PyPARSE_DONT_IMPLY_DEDENT : 0) \
+                   | ((flags)->cf_flags & CO_FUTURE_WITH_STATEMENT ? \
+                      PyPARSE_WITH_IS_KEYWORD : 0)) : 0)
 
 int
 PyRun_InteractiveOneFlags(FILE *fp, const char *filename, PyCompilerFlags *flags)