Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
test_windows_wrappers.py259 linesDownload Raw Back to tests
1"""2Python Script Wrapper for Windows3=================================4 5setuptools includes wrappers for Python scripts that allows them to be6executed like regular windows programs.  There are 2 wrappers, one7for command-line programs, cli.exe, and one for graphical programs,8gui.exe.  These programs are almost identical, function pretty much9the same way, and are generated from the same source file.  The10wrapper programs are used by copying them to the directory containing11the script they are to wrap and with the same name as the script they12are to wrap.13"""14 15import pathlib16import platform17import subprocess18import sys19import textwrap20 21import pytest22 23from setuptools._importlib import resources24 25pytestmark = pytest.mark.skipif(sys.platform != 'win32', reason="Windows only")26 27 28class WrapperTester:29    @classmethod30    def prep_script(cls, template):31        python_exe = subprocess.list2cmdline([sys.executable])32        return template % locals()33 34    @classmethod35    def create_script(cls, tmpdir):36        """37        Create a simple script, foo-script.py38 39        Note that the script starts with a Unix-style '#!' line saying which40        Python executable to run.  The wrapper will use this line to find the41        correct Python executable.42        """43 44        script = cls.prep_script(cls.script_tmpl)45 46        with (tmpdir / cls.script_name).open('w') as f:47            f.write(script)48 49        # also copy cli.exe to the sample directory50        with (tmpdir / cls.wrapper_name).open('wb') as f:51            w = resources.files('setuptools').joinpath(cls.wrapper_source).read_bytes()52            f.write(w)53 54 55def win_launcher_exe(prefix):56    """A simple routine to select launcher script based on platform."""57    assert prefix in ('cli', 'gui')58    if platform.machine() == "ARM64":59        return f"{prefix}-arm64.exe"60    else:61        return f"{prefix}-32.exe"62 63 64class TestCLI(WrapperTester):65    script_name = 'foo-script.py'66    wrapper_name = 'foo.exe'67    wrapper_source = win_launcher_exe('cli')68 69    script_tmpl = textwrap.dedent(70        """71        #!%(python_exe)s72        import sys73        input = repr(sys.stdin.read())74        print(sys.argv[0][-14:])75        print(sys.argv[1:])76        print(input)77        if __debug__:78            print('non-optimized')79        """80    ).lstrip()81 82    def test_basic(self, tmpdir):83        """84        When the copy of cli.exe, foo.exe in this example, runs, it examines85        the path name it was run with and computes a Python script path name86        by removing the '.exe' suffix and adding the '-script.py' suffix. (For87        GUI programs, the suffix '-script.pyw' is added.)  This is why we88        named out script the way we did.  Now we can run out script by running89        the wrapper:90 91        This example was a little pathological in that it exercised windows92        (MS C runtime) quoting rules:93 94        - Strings containing spaces are surrounded by double quotes.95 96        - Double quotes in strings need to be escaped by preceding them with97          back slashes.98 99        - One or more backslashes preceding double quotes need to be escaped100          by preceding each of them with back slashes.101        """102        self.create_script(tmpdir)103        cmd = [104            str(tmpdir / 'foo.exe'),105            'arg1',106            'arg 2',107            'arg "2\\"',108            'arg 4\\',109            'arg5 a\\\\b',110        ]111        proc = subprocess.Popen(112            cmd,113            stdout=subprocess.PIPE,114            stdin=subprocess.PIPE,115            text=True,116            encoding="utf-8",117        )118        stdout, _stderr = proc.communicate('hello\nworld\n')119        actual = stdout.replace('\r\n', '\n')120        expected = textwrap.dedent(121            r"""122            \foo-script.py123            ['arg1', 'arg 2', 'arg "2\\"', 'arg 4\\', 'arg5 a\\\\b']124            'hello\nworld\n'125            non-optimized126            """127        ).lstrip()128        assert actual == expected129 130    def test_symlink(self, tmpdir):131        """132        Ensure that symlink for the foo.exe is working correctly.133        """134        script_dir = tmpdir / "script_dir"135        script_dir.mkdir()136        self.create_script(script_dir)137        symlink = pathlib.Path(tmpdir / "foo.exe")138        symlink.symlink_to(script_dir / "foo.exe")139 140        cmd = [141            str(tmpdir / 'foo.exe'),142            'arg1',143            'arg 2',144            'arg "2\\"',145            'arg 4\\',146            'arg5 a\\\\b',147        ]148        proc = subprocess.Popen(149            cmd,150            stdout=subprocess.PIPE,151            stdin=subprocess.PIPE,152            text=True,153            encoding="utf-8",154        )155        stdout, _stderr = proc.communicate('hello\nworld\n')156        actual = stdout.replace('\r\n', '\n')157        expected = textwrap.dedent(158            r"""159            \foo-script.py160            ['arg1', 'arg 2', 'arg "2\\"', 'arg 4\\', 'arg5 a\\\\b']161            'hello\nworld\n'162            non-optimized163            """164        ).lstrip()165        assert actual == expected166 167    def test_with_options(self, tmpdir):168        """169        Specifying Python Command-line Options170        --------------------------------------171 172        You can specify a single argument on the '#!' line.  This can be used173        to specify Python options like -O, to run in optimized mode or -i174        to start the interactive interpreter.  You can combine multiple175        options as usual. For example, to run in optimized mode and176        enter the interpreter after running the script, you could use -Oi:177        """178        self.create_script(tmpdir)179        tmpl = textwrap.dedent(180            """181            #!%(python_exe)s  -Oi182            import sys183            input = repr(sys.stdin.read())184            print(sys.argv[0][-14:])185            print(sys.argv[1:])186            print(input)187            if __debug__:188                print('non-optimized')189            sys.ps1 = '---'190            """191        ).lstrip()192        with (tmpdir / 'foo-script.py').open('w') as f:193            f.write(self.prep_script(tmpl))194        cmd = [str(tmpdir / 'foo.exe')]195        proc = subprocess.Popen(196            cmd,197            stdout=subprocess.PIPE,198            stdin=subprocess.PIPE,199            stderr=subprocess.STDOUT,200            text=True,201            encoding="utf-8",202        )203        stdout, _stderr = proc.communicate()204        actual = stdout.replace('\r\n', '\n')205        expected = textwrap.dedent(206            r"""207            \foo-script.py208            []209            ''210            ---211            """212        ).lstrip()213        assert actual == expected214 215 216class TestGUI(WrapperTester):217    """218    Testing the GUI Version219    -----------------------220    """221 222    script_name = 'bar-script.pyw'223    wrapper_source = win_launcher_exe('gui')224    wrapper_name = 'bar.exe'225 226    script_tmpl = textwrap.dedent(227        """228        #!%(python_exe)s229        import sys230        f = open(sys.argv[1], 'wb')231        bytes_written = f.write(repr(sys.argv[2]).encode('utf-8'))232        f.close()233        """234    ).strip()235 236    def test_basic(self, tmpdir):237        """Test the GUI version with the simple script, bar-script.py"""238        self.create_script(tmpdir)239 240        cmd = [241            str(tmpdir / 'bar.exe'),242            str(tmpdir / 'test_output.txt'),243            'Test Argument',244        ]245        proc = subprocess.Popen(246            cmd,247            stdout=subprocess.PIPE,248            stdin=subprocess.PIPE,249            stderr=subprocess.STDOUT,250            text=True,251            encoding="utf-8",252        )253        stdout, stderr = proc.communicate()254        assert not stdout255        assert not stderr256        with (tmpdir / 'test_output.txt').open('rb') as f_out:257            actual = f_out.read().decode('ascii')258        assert actual == repr('Test Argument')259 
codekingpro/portable-devtools · Team Ai