[Python-checkins] bpo-39313: Add an option to RefactoringTool for using exec as a function (GH-17967)

Miss Islington (bot) webhook-mailer at python.org
Sun Jan 12 17:13:36 EST 2020

commit: 61b14151cc92021a10f94765eaa152ed04eb262a
branch: master
author: Batuhan Taşkaya <47358913+isidentical at users.noreply.github.com>
committer: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
date: 2020-01-12T14:13:31-08:00

bpo-39313: Add an option to RefactoringTool for using exec as a function (GH-17967)


Automerge-Triggered-By: @pablogsal

A Misc/NEWS.d/next/Library/2020-01-12-18-17-00.bpo-39313.DCTsnm.rst
M Doc/library/2to3.rst
M Lib/lib2to3/main.py
M Lib/lib2to3/refactor.py
M Lib/lib2to3/tests/test_refactor.py

diff --git a/Doc/library/2to3.rst b/Doc/library/2to3.rst
index c3ff3e607e797..eb4c9185f48bf 100644
--- a/Doc/library/2to3.rst
+++ b/Doc/library/2to3.rst
@@ -102,7 +102,7 @@ presence of the ``from __future__ import print_function`` compiler directive, it
 modifies its internal grammar to interpret :func:`print` as a function.  This
 change can also be enabled manually with the :option:`!-p` flag.  Use
 :option:`!-p` to run fixers on code that already has had its print statements
+converted. Also :option:`!-e` can be used to make :func:`exec` a function.
 The :option:`!-o` or :option:`!--output-dir` option allows specification of an
 alternate directory for processed output files to be written to.  The
diff --git a/Lib/lib2to3/main.py b/Lib/lib2to3/main.py
index c51626babf8ec..f2849fd6be3fd 100644
--- a/Lib/lib2to3/main.py
+++ b/Lib/lib2to3/main.py
@@ -154,6 +154,8 @@ def main(fixer_pkg, args=None):
                       help="List available transformations")
     parser.add_option("-p", "--print-function", action="store_true",
                       help="Modify the grammar so that print() is a function")
+    parser.add_option("-e", "--exec-function", action="store_true",
+                      help="Modify the grammar so that exec() is a function")
     parser.add_option("-v", "--verbose", action="store_true",
                       help="More verbose logging")
     parser.add_option("--no-diffs", action="store_true",
@@ -211,6 +213,9 @@ def main(fixer_pkg, args=None):
     if options.print_function:
         flags["print_function"] = True
+    if options.exec_function:
+        flags["exec_function"] = True
     # Set up logging handler
     level = logging.DEBUG if options.verbose else logging.INFO
     logging.basicConfig(format='%(name)s: %(message)s', level=level)
diff --git a/Lib/lib2to3/refactor.py b/Lib/lib2to3/refactor.py
index 55fd60fa27c3d..3a5aafffc6df0 100644
--- a/Lib/lib2to3/refactor.py
+++ b/Lib/lib2to3/refactor.py
@@ -155,6 +155,7 @@ class FixerError(Exception):
 class RefactoringTool(object):
     _default_options = {"print_function" : False,
+                        "exec_function": False,
                         "write_unchanged_files" : False}
     CLASS_PREFIX = "Fix" # The prefix for fixer classes
@@ -173,10 +174,13 @@ def __init__(self, fixer_names, options=None, explicit=None):
         self.options = self._default_options.copy()
         if options is not None:
-        if self.options["print_function"]:
-            self.grammar = pygram.python_grammar_no_print_statement
-        else:
-            self.grammar = pygram.python_grammar
+        self.grammar = pygram.python_grammar.copy()
+        if self.options['print_function']:
+            del self.grammar.keywords["print"]
+        elif self.options['exec_function']:
+            del self.grammar.keywords["exec"]
         # When this is True, the refactor*() methods will call write_file() for
         # files processed even if they were not changed during refactoring. If
         # and only if the refactor method's write parameter was True.
diff --git a/Lib/lib2to3/tests/test_refactor.py b/Lib/lib2to3/tests/test_refactor.py
index 9e3b8fbb90b2f..be705679f06db 100644
--- a/Lib/lib2to3/tests/test_refactor.py
+++ b/Lib/lib2to3/tests/test_refactor.py
@@ -44,9 +44,13 @@ def rt(self, options=None, fixers=_DEFAULT_FIXERS, explicit=None):
     def test_print_function_option(self):
         rt = self.rt({"print_function" : True})
-        self.assertIs(rt.grammar, pygram.python_grammar_no_print_statement)
-        self.assertIs(rt.driver.grammar,
-                      pygram.python_grammar_no_print_statement)
+        self.assertNotIn("print", rt.grammar.keywords)
+        self.assertNotIn("print", rt.driver.grammar.keywords)
+    def test_exec_function_option(self):
+        rt = self.rt({"exec_function" : True})
+        self.assertNotIn("exec", rt.grammar.keywords)
+        self.assertNotIn("exec", rt.driver.grammar.keywords)
     def test_write_unchanged_files_option(self):
         rt = self.rt()
diff --git a/Misc/NEWS.d/next/Library/2020-01-12-18-17-00.bpo-39313.DCTsnm.rst b/Misc/NEWS.d/next/Library/2020-01-12-18-17-00.bpo-39313.DCTsnm.rst
new file mode 100644
index 0000000000000..784d73c7b3f96
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-01-12-18-17-00.bpo-39313.DCTsnm.rst
@@ -0,0 +1,2 @@
+Add a new ``exec_function`` option (*--exec-function* in the CLI) to
+``RefactoringTool`` for making ``exec`` a function. Patch by Batuhan Taskaya.

More information about the Python-checkins mailing list