[Python-checkins] bpo-37064: Add option -a to pathfix.py tool (GH-15717)

Victor Stinner webhook-mailer at python.org
Wed Sep 25 08:26:44 EDT 2019


https://github.com/python/cpython/commit/1dc1acbd73f05f14c974b7ce1041787d7abef31e
commit: 1dc1acbd73f05f14c974b7ce1041787d7abef31e
branch: master
author: PatrikKopkan <kopkanpatrik at gmail.com>
committer: Victor Stinner <vstinner at redhat.com>
date: 2019-09-25T14:26:28+02:00
summary:

bpo-37064: Add option -a to pathfix.py tool (GH-15717)

Add option -a to Tools/Scripts/pathfix.py script: add flags.

files:
M Lib/test/test_tools/test_pathfix.py
M Misc/NEWS.d/next/Tools-Demos/2019-05-27-15-26-12.bpo-37064.k_SPW2.rst
M Tools/scripts/pathfix.py

diff --git a/Lib/test/test_tools/test_pathfix.py b/Lib/test/test_tools/test_pathfix.py
index 0c1aea721170..a87992491344 100644
--- a/Lib/test/test_tools/test_pathfix.py
+++ b/Lib/test/test_tools/test_pathfix.py
@@ -17,51 +17,90 @@ def setUp(self):
         self.temp_file = support.TESTFN
         self.addCleanup(support.unlink, support.TESTFN)
 
-    def pathfix(self, shebang, pathfix_flags):
+    def pathfix(self, shebang, pathfix_flags, exitcode=0, stdout='', stderr=''):
         with open(self.temp_file, 'w', encoding='utf8') as f:
             f.write(f'{shebang}\n' + 'print("Hello world")\n')
 
         proc = subprocess.run(
             [sys.executable, self.script,
              *pathfix_flags, '-n', self.temp_file],
-            capture_output=True)
-        self.assertEqual(proc.returncode, 0, proc)
+            capture_output=True, text=1)
+
+        if stdout == '' and proc.returncode == 0:
+            stdout = f'{self.temp_file}: updating\n'
+        self.assertEqual(proc.returncode, exitcode, proc)
+        self.assertEqual(proc.stdout, stdout, proc)
+        self.assertEqual(proc.stderr, stderr, proc)
 
         with open(self.temp_file, 'r', encoding='utf8') as f:
             output = f.read()
 
         lines = output.split('\n')
         self.assertEqual(lines[1:], ['print("Hello world")', ''])
-        shebang = lines[0]
-        return shebang
+        new_shebang = lines[0]
+
+        if proc.returncode != 0:
+            self.assertEqual(shebang, new_shebang)
+
+        return new_shebang
 
     def test_pathfix(self):
         self.assertEqual(
             self.pathfix(
                 '#! /usr/bin/env python',
-                ['-i', '/usr/bin/python3',]),
-            '#! /usr/bin/python3',
-        )
+                ['-i', '/usr/bin/python3']),
+            '#! /usr/bin/python3')
         self.assertEqual(
             self.pathfix(
                 '#! /usr/bin/env python -R',
-                ['-i', '/usr/bin/python3', ]),
-            '#! /usr/bin/python3',
-        )
+                ['-i', '/usr/bin/python3']),
+            '#! /usr/bin/python3')
 
     def test_pathfix_keeping_flags(self):
         self.assertEqual(
             self.pathfix(
                 '#! /usr/bin/env python -R',
-                ['-i', '/usr/bin/python3', '-k',]),
-            '#! /usr/bin/python3 -R',
-        )
+                ['-i', '/usr/bin/python3', '-k']),
+            '#! /usr/bin/python3 -R')
         self.assertEqual(
             self.pathfix(
                 '#! /usr/bin/env python',
-                ['-i', '/usr/bin/python3', '-k',]),
-            '#! /usr/bin/python3',
-        )
+                ['-i', '/usr/bin/python3', '-k']),
+            '#! /usr/bin/python3')
+
+    def test_pathfix_adding_flag(self):
+        self.assertEqual(
+            self.pathfix(
+                '#! /usr/bin/env python',
+                ['-i', '/usr/bin/python3', '-a', 's']),
+            '#! /usr/bin/python3 -s')
+        self.assertEqual(
+            self.pathfix(
+                '#! /usr/bin/env python -S',
+                ['-i', '/usr/bin/python3', '-a', 's']),
+            '#! /usr/bin/python3 -s')
+        self.assertEqual(
+            self.pathfix(
+                '#! /usr/bin/env python -V',
+                ['-i', '/usr/bin/python3', '-a', 'v', '-k']),
+            '#! /usr/bin/python3 -vV')
+        self.assertEqual(
+            self.pathfix(
+                '#! /usr/bin/env python',
+                ['-i', '/usr/bin/python3', '-a', 'Rs']),
+            '#! /usr/bin/python3 -Rs')
+        self.assertEqual(
+            self.pathfix(
+                '#! /usr/bin/env python -W default',
+                ['-i', '/usr/bin/python3', '-a', 's', '-k']),
+            '#! /usr/bin/python3 -sW default')
+
+    def test_pathfix_adding_errors(self):
+        self.pathfix(
+            '#! /usr/bin/env python -E',
+            ['-i', '/usr/bin/python3', '-a', 'W default', '-k'],
+            exitcode=2,
+            stderr="-a option doesn't support whitespaces")
 
 
 if __name__ == '__main__':
diff --git a/Misc/NEWS.d/next/Tools-Demos/2019-05-27-15-26-12.bpo-37064.k_SPW2.rst b/Misc/NEWS.d/next/Tools-Demos/2019-05-27-15-26-12.bpo-37064.k_SPW2.rst
index 02599077c9d5..d1210e29532b 100644
--- a/Misc/NEWS.d/next/Tools-Demos/2019-05-27-15-26-12.bpo-37064.k_SPW2.rst
+++ b/Misc/NEWS.d/next/Tools-Demos/2019-05-27-15-26-12.bpo-37064.k_SPW2.rst
@@ -1 +1,2 @@
-Add flag -k to pathscript.py script: preserve shebang flags.
\ No newline at end of file
+Add option -k to pathscript.py script: preserve shebang flags.
+Add option -a to pathscript.py script: add flags.
diff --git a/Tools/scripts/pathfix.py b/Tools/scripts/pathfix.py
index eee684e3502d..237a3d96e9fa 100755
--- a/Tools/scripts/pathfix.py
+++ b/Tools/scripts/pathfix.py
@@ -14,6 +14,7 @@
 # Sometimes you may find shebangs with flags such as `#! /usr/bin/env python -si`.
 # Normally, pathfix overwrites the entire line, including the flags.
 # To change interpreter and keep flags from the original shebang line, use -k.
+# If you want to keep flags and add to them one single literal flag, use option -a.
 
 
 # Undoubtedly you can do this using find and sed or perl, but this is
@@ -39,6 +40,7 @@
 preserve_timestamps = False
 create_backup = True
 keep_flags = False
+add_flags = b''
 
 
 def main():
@@ -46,11 +48,12 @@ def main():
     global preserve_timestamps
     global create_backup
     global keep_flags
+    global add_flags
 
-    usage = ('usage: %s -i /interpreter -p -n -k file-or-directory ...\n' %
+    usage = ('usage: %s -i /interpreter -p -n -k -a file-or-directory ...\n' %
              sys.argv[0])
     try:
-        opts, args = getopt.getopt(sys.argv[1:], 'i:kpn')
+        opts, args = getopt.getopt(sys.argv[1:], 'i:a:kpn')
     except getopt.error as msg:
         err(str(msg) + '\n')
         err(usage)
@@ -64,6 +67,11 @@ def main():
             create_backup = False
         if o == '-k':
             keep_flags = True
+        if o == '-a':
+            add_flags = a.encode()
+            if b' ' in add_flags:
+                err("-a option doesn't support whitespaces")
+                sys.exit(2)
     if not new_interpreter or not new_interpreter.startswith(b'/') or \
            not args:
         err('-i option or file-or-directory missing\n')
@@ -188,15 +196,32 @@ def parse_shebang(shebangline):
     return shebangline[start:]
 
 
+def populate_flags(shebangline):
+    old_flags = b''
+    if keep_flags:
+        old_flags = parse_shebang(shebangline)
+        if old_flags:
+            old_flags = old_flags[2:]
+    if not (old_flags or add_flags):
+        return b''
+    # On Linux, the entire string following the interpreter name
+    # is passed as a single argument to the interpreter.
+    # e.g. "#! /usr/bin/python3 -W Error -s" runs "/usr/bin/python3 "-W Error -s"
+    # so shebang should have single '-' where flags are given and
+    # flag might need argument for that reasons adding new flags is
+    # between '-' and original flags
+    # e.g. #! /usr/bin/python3 -sW Error
+    return b' -' + add_flags + old_flags
+
+
 def fixline(line):
     if not line.startswith(b'#!'):
         return line
 
     if b"python" not in line:
         return line
-    flags = b''
-    if keep_flags:
-        flags = parse_shebang(line)
+
+    flags = populate_flags(line)
     return b'#! ' + new_interpreter + flags + b'\n'
 
 



More information about the Python-checkins mailing list