diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 9bb2fc627b5..90e59ef5c24 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1470,8 +1470,8 @@ written in Python, such as a mail server's external command delivery program. (Note that the :mod:`subprocess` module provides more powerful facilities for spawning new processes and retrieving their results; using that module is - preferable to using these functions. Check specially the *Replacing Older - Functions with the subprocess Module* section in that documentation page.) + preferable to using these functions. Check especially the + :ref:`subprocess-replacements` section.) If *mode* is :const:`P_NOWAIT`, this function returns the process id of the new process; if *mode* is :const:`P_WAIT`, returns the process's exit code if it diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index 3318d430ec1..d0e655d1e29 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -412,8 +412,8 @@ Replacing shell pipeline output = p2.communicate()[0] -Replacing os.system() -^^^^^^^^^^^^^^^^^^^^^ +Replacing :func:`os.system` +^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: @@ -440,8 +440,8 @@ A more realistic example would look like this:: print("Execution failed:", e, file=sys.stderr) -Replacing the os.spawn family -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Replacing the :func:`os.spawn ` family +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ P_NOWAIT example:: @@ -468,17 +468,85 @@ Environment example:: Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"}) -Replacing os.popen -^^^^^^^^^^^^^^^^^^ + +Replacing :func:`os.popen`, :func:`os.popen2`, :func:`os.popen3` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: - pipe = os.popen(cmd, 'r', bufsize) + (child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize) ==> - pipe = Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout + p = Popen(cmd, shell=True, bufsize=bufsize, + stdin=PIPE, stdout=PIPE, close_fds=True) + (child_stdin, child_stdout) = (p.stdin, p.stdout) :: - pipe = os.popen(cmd, 'w', bufsize) + (child_stdin, + child_stdout, + child_stderr) = os.popen3(cmd, mode, bufsize) ==> - pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin + p = Popen(cmd, shell=True, bufsize=bufsize, + stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) + (child_stdin, + child_stdout, + child_stderr) = (p.stdin, p.stdout, p.stderr) + +:: + + (child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize) + ==> + p = Popen(cmd, shell=True, bufsize=bufsize, + stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) + (child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout) + +Return code handling translates as follows:: + + pipe = os.popen(cmd, 'w') + ... + rc = pipe.close() + if rc != None and rc % 256: + print "There were some errors" + ==> + process = Popen(cmd, 'w', stdin=PIPE) + ... + process.stdin.close() + if process.wait() != 0: + print "There were some errors" + + +Replacing functions from the :mod:`popen2` module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. note:: + + If the cmd argument to popen2 functions is a string, the command is executed + through /bin/sh. If it is a list, the command is directly executed. + +:: + + (child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode) + ==> + p = Popen(["somestring"], shell=True, bufsize=bufsize, + stdin=PIPE, stdout=PIPE, close_fds=True) + (child_stdout, child_stdin) = (p.stdout, p.stdin) + +:: + + (child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode) + ==> + p = Popen(["mycmd", "myarg"], bufsize=bufsize, + stdin=PIPE, stdout=PIPE, close_fds=True) + (child_stdout, child_stdin) = (p.stdout, p.stdin) + +:class:`popen2.Popen3` and :class:`popen2.Popen4` basically work as +:class:`subprocess.Popen`, except that: + +* :class:`Popen` raises an exception if the execution fails. + +* the *capturestderr* argument is replaced with the *stderr* argument. + +* ``stdin=PIPE`` and ``stdout=PIPE`` must be specified. + +* popen2 closes all file descriptors by default, but you have to specify + ``close_fds=True`` with :class:`Popen`. diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst index 9182c45349d..f5f7d198398 100644 --- a/Doc/whatsnew/2.7.rst +++ b/Doc/whatsnew/2.7.rst @@ -663,7 +663,11 @@ Porting to Python 2.7 This section lists previously described changes and other bugfixes that may require changes to your code: -To be written. +* Because of an optimization for the :keyword:`with` statement, the special + methods :meth:`__enter__` and :meth:`__exit__` must belong to the object's + type, and cannot be directly attached to the object's instance. This + affects new-style classes (derived from :class:`object`) and C extension + types. (:issue:`6101`.) .. ====================================================================== diff --git a/Grammar/Grammar b/Grammar/Grammar index 1b196e53182..1f226b80b1f 100644 --- a/Grammar/Grammar +++ b/Grammar/Grammar @@ -116,8 +116,9 @@ classdef: 'class' NAME ['(' [arglist] ')'] ':' suite arglist: (argument ',')* (argument [','] |'*' test (',' argument)* [',' '**' test] |'**' test) +# The reason that keywords are test nodes instead of NAME is that using NAME +# results in an ambiguity. ast.c makes sure it's a NAME. argument: test [comp_for] | test '=' test # Really [keyword '='] test - comp_iter: comp_for | comp_if comp_for: 'for' exprlist 'in' or_test [comp_iter] comp_if: 'if' test_nocond [comp_iter] diff --git a/Lib/multiprocessing/queues.py b/Lib/multiprocessing/queues.py index a3393d45854..bbaf6d5550f 100644 --- a/Lib/multiprocessing/queues.py +++ b/Lib/multiprocessing/queues.py @@ -109,7 +109,7 @@ class Queue(object): self._rlock.release() def qsize(self): - # Raises NotImplementError on Mac OSX because of broken sem_getvalue() + # Raises NotImplementedError on Mac OSX because of broken sem_getvalue() return self._maxsize - self._sem._semlock._get_value() def empty(self): diff --git a/Lib/os.py b/Lib/os.py index 65f88ba1892..5dce0c1f24d 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -437,11 +437,7 @@ def getenv(key, default=None): __all__.append("getenv") def _exists(name): - try: - eval(name) - return True - except NameError: - return False + return name in globals() # Supply spawn*() (probably only for Unix) if _exists("fork") and not _exists("spawnv") and _exists("execv"): diff --git a/Lib/symbol.py b/Lib/symbol.py index 1b773d05de5..4b4c2198632 100755 --- a/Lib/symbol.py +++ b/Lib/symbol.py @@ -52,7 +52,7 @@ while_stmt = 294 for_stmt = 295 try_stmt = 296 with_stmt = 297 -with_var = 298 +with_item = 298 except_clause = 299 suite = 300 test = 301 diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index 9b4e3428aff..84028e85386 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -1584,7 +1584,7 @@ SyntaxError: can't assign to yield expression >>> def f(): (yield bar) += y Traceback (most recent call last): ... -SyntaxError: augmented assignment to yield expression not possible +SyntaxError: can't assign to yield expression Now check some throw() conditions: diff --git a/Lib/test/test_genexps.py b/Lib/test/test_genexps.py index 61e9fe5e70a..1f46af13e34 100644 --- a/Lib/test/test_genexps.py +++ b/Lib/test/test_genexps.py @@ -142,7 +142,7 @@ Verify that syntax error's are raised for genexps used as lvalues >>> (y for y in (1,2)) += 10 Traceback (most recent call last): ... - SyntaxError: augmented assignment to generator expression not possible + SyntaxError: can't assign to generator expression ########### Tests borrowed from or inspired by test_generators.py ############ diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index c82787e5486..c55171a7210 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -222,17 +222,17 @@ Traceback (most recent call last): SyntaxError: keyword can't be an expression -From ast_for_expr_stmt(): +More set_context(): >>> (x for x in x) += 1 Traceback (most recent call last): -SyntaxError: augmented assignment to generator expression not possible +SyntaxError: can't assign to generator expression >>> None += 1 Traceback (most recent call last): SyntaxError: assignment to keyword >>> f() += 1 Traceback (most recent call last): -SyntaxError: illegal expression for augmented assignment +SyntaxError: can't assign to function call Test continue in finally in weird combinations. diff --git a/Makefile.pre.in b/Makefile.pre.in index 2f5ccccf30e..41fc51eddc6 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -562,7 +562,7 @@ $(AST_H): $(AST_ASDL) $(ASDLGEN_FILES) $(AST_C): $(AST_ASDL) $(ASDLGEN_FILES) $(ASDLGEN) -c $(AST_C_DIR) $(AST_ASDL) -Python/compile.o Python/symtable.o: $(GRAMMAR_H) $(AST_H) +Python/compile.o Python/symtable.o Python/ast.o: $(GRAMMAR_H) $(AST_H) Python/getplatform.o: $(srcdir)/Python/getplatform.c $(CC) -c $(PY_CFLAGS) -DPLATFORM='"$(MACHDEP)"' -o $@ $(srcdir)/Python/getplatform.c diff --git a/Objects/dictobject.c b/Objects/dictobject.c index f21cea24c3d..ce6760fdbd6 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -717,7 +717,7 @@ PyDict_GetItem(PyObject *op, PyObject *key) /* We can arrive here with a NULL tstate during initialization: try running "python -Wi" for an example related to string interning. Let's just hope that no exception occurs then... */ - tstate = _PyThreadState_Current; + tstate = PyThreadState_GET(); if (tstate != NULL && tstate->curexc_type != NULL) { /* preserve the existing exception */ PyObject *err_type, *err_value, *err_tb; diff --git a/Parser/asdl.py b/Parser/asdl.py index ce9d0d37f5e..28a71387978 100644 --- a/Parser/asdl.py +++ b/Parser/asdl.py @@ -20,7 +20,7 @@ def output(string): sys.stdout.write(string + "\n") -class Token: +class Token(object): # spark seems to dispatch in the parser based on a token's # type attribute def __init__(self, type, lineno): @@ -221,20 +221,20 @@ class ASDLParser(spark.GenericParser, object): def p_field_2(self, info): " field ::= Id * Id " type, _, name = info - return Field(type, name, seq=1) + return Field(type, name, seq=True) def p_field_3(self, info): " field ::= Id ? Id " type, _, name = info - return Field(type, name, opt=1) + return Field(type, name, opt=True) def p_field_4(self, type_): " field ::= Id * " - return Field(type_[0], seq=1) + return Field(type_[0], seq=True) def p_field_5(self, type_): " field ::= Id ? " - return Field(type[0], opt=1) + return Field(type[0], opt=True) builtin_types = ("identifier", "string", "int", "bool", "object") @@ -242,7 +242,7 @@ builtin_types = ("identifier", "string", "int", "bool", "object") # not sure if any of the methods are useful yet, but I'm adding them # piecemeal as they seem helpful -class AST: +class AST(object): pass # a marker class class Module(AST): @@ -274,7 +274,7 @@ class Constructor(AST): return "Constructor(%s, %s)" % (self.name, self.fields) class Field(AST): - def __init__(self, type, name=None, seq=0, opt=0): + def __init__(self, type, name=None, seq=False, opt=False): self.type = type self.name = name self.seq = seq @@ -282,9 +282,9 @@ class Field(AST): def __repr__(self): if self.seq: - extra = ", seq=1" + extra = ", seq=True" elif self.opt: - extra = ", opt=1" + extra = ", opt=True" else: extra = "" if self.name is None: @@ -312,7 +312,7 @@ class Product(AST): class VisitorBase(object): - def __init__(self, skip=0): + def __init__(self, skip=False): self.cache = {} self.skip = skip @@ -347,7 +347,7 @@ class VisitorBase(object): class Check(VisitorBase): def __init__(self): - super(Check, self).__init__(skip=1) + super(Check, self).__init__(skip=True) self.cons = {} self.errors = 0 self.types = {} diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index af0b349b495..8ccb3ea0458 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -86,7 +86,7 @@ class EmitVisitor(asdl.VisitorBase): self.file = file super(EmitVisitor, self).__init__() - def emit(self, s, depth, reflow=1): + def emit(self, s, depth, reflow=True): # XXX reflow long lines? if reflow: lines = reflow_lines(s, depth) @@ -255,7 +255,7 @@ class PrototypeVisitor(EmitVisitor): ctype = get_c_type(type) self.emit_function(cons.name, ctype, args, attrs) - def emit_function(self, name, ctype, args, attrs, union=1): + def emit_function(self, name, ctype, args, attrs, union=True): args = args + attrs if args: argstr = ", ".join(["%s %s" % (atype, aname) @@ -267,19 +267,19 @@ class PrototypeVisitor(EmitVisitor): for i in range(1, len(args)+1): margs += ", a%d" % i self.emit("#define %s(%s) _Py_%s(%s)" % (name, margs, name, margs), 0, - reflow = 0) - self.emit("%s _Py_%s(%s);" % (ctype, name, argstr), 0) + reflow=False) + self.emit("%s _Py_%s(%s);" % (ctype, name, argstr), False) def visitProduct(self, prod, name): self.emit_function(name, get_c_type(name), - self.get_args(prod.fields), [], union=0) + self.get_args(prod.fields), [], union=False) class FunctionVisitor(PrototypeVisitor): """Visitor to generate constructor functions for AST.""" - def emit_function(self, name, ctype, args, attrs, union=1): - def emit(s, depth=0, reflow=1): + def emit_function(self, name, ctype, args, attrs, union=True): + def emit(s, depth=0, reflow=True): self.emit(s, depth, reflow) argstr = ", ".join(["%s %s" % (atype, aname) for atype, aname, opt in args + attrs]) @@ -297,7 +297,7 @@ class FunctionVisitor(PrototypeVisitor): emit("PyErr_SetString(PyExc_ValueError,", 2) msg = "field %s is required for %s" % (argname, name) emit(' "%s");' % msg, - 2, reflow=0) + 2, reflow=False) emit('return NULL;', 2) emit('}', 1) @@ -313,7 +313,7 @@ class FunctionVisitor(PrototypeVisitor): emit("") def emit_body_union(self, name, args, attrs): - def emit(s, depth=0, reflow=1): + def emit(s, depth=0, reflow=True): self.emit(s, depth, reflow) emit("p->kind = %s_kind;" % name, 1) for argtype, argname, opt in args: @@ -322,7 +322,7 @@ class FunctionVisitor(PrototypeVisitor): emit("p->%s = %s;" % (argname, argname), 1) def emit_body_struct(self, name, args, attrs): - def emit(s, depth=0, reflow=1): + def emit(s, depth=0, reflow=True): self.emit(s, depth, reflow) for argtype, argname, opt in args: emit("p->%s = %s;" % (argname, argname), 1) diff --git a/Python/ast.c b/Python/ast.c index ff412b3d983..83572ee8821 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -2103,29 +2103,6 @@ ast_for_expr_stmt(struct compiling *c, const node *n) expr1 = ast_for_testlist(c, ch); if (!expr1) return NULL; - /* TODO(nas): Remove duplicated error checks (set_context does it) */ - switch (expr1->kind) { - case GeneratorExp_kind: - ast_error(ch, "augmented assignment to generator " - "expression not possible"); - return NULL; - case Yield_kind: - ast_error(ch, "augmented assignment to yield " - "expression not possible"); - return NULL; - case Name_kind: { - if (forbidden_name(expr1, ch)) - return NULL; - break; - } - case Attribute_kind: - case Subscript_kind: - break; - default: - ast_error(ch, "illegal expression for augmented " - "assignment"); - return NULL; - } if(!set_context(c, expr1, Store, ch)) return NULL; @@ -3086,7 +3063,6 @@ ast_for_stmt(struct compiling *c, const node *n) n = CHILD(n, 0); } if (TYPE(n) == small_stmt) { - REQ(n, small_stmt); n = CHILD(n, 0); /* small_stmt: expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt