From 61b14151cc92021a10f94765eaa152ed04eb262a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Batuhan=20Ta=C5=9Fkaya?= <47358913+isidentical@users.noreply.github.com> Date: Mon, 13 Jan 2020 01:13:31 +0300 Subject: [PATCH] bpo-39313: Add an option to RefactoringTool for using exec as a function (GH-17967) https://bugs.python.org/issue39313 Automerge-Triggered-By: @pablogsal --- Doc/library/2to3.rst | 2 +- Lib/lib2to3/main.py | 5 +++++ Lib/lib2to3/refactor.py | 12 ++++++++---- Lib/lib2to3/tests/test_refactor.py | 10 +++++++--- .../Library/2020-01-12-18-17-00.bpo-39313.DCTsnm.rst | 2 ++ 5 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-01-12-18-17-00.bpo-39313.DCTsnm.rst diff --git a/Doc/library/2to3.rst b/Doc/library/2to3.rst index c3ff3e607e7..eb4c9185f48 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. +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 c51626babf8..f2849fd6be3 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 55fd60fa27c..3a5aafffc6d 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 @@ class RefactoringTool(object): self.options = self._default_options.copy() if options is not None: self.options.update(options) - 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 9e3b8fbb90b..be705679f06 100644 --- a/Lib/lib2to3/tests/test_refactor.py +++ b/Lib/lib2to3/tests/test_refactor.py @@ -44,9 +44,13 @@ class TestRefactoringTool(unittest.TestCase): 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 00000000000..784d73c7b3f --- /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.