Commit 89065d9f authored by Brett Cannon's avatar Brett Cannon

Issue #25099: Skip relevant tests in test_compileall when an entry on

sys.path has an unwritable __pycache__ directory.

This typically comes up when someone runs the test suite from an
administrative install of Python on Windows where the user does not
have write permissions to the stdlib's directory.

Thanks to Zachary Ware and Matthias Klose for reporting bugs related
to this issue.
(grafted from 34bbd537b3e688dfbb6498e9083445a6a72fc4b1)
parent 7b2cfc44
...@@ -2,6 +2,7 @@ import sys ...@@ -2,6 +2,7 @@ import sys
import compileall import compileall
import importlib.util import importlib.util
import os import os
import pathlib
import py_compile import py_compile
import shutil import shutil
import struct import struct
...@@ -133,6 +134,33 @@ class EncodingTest(unittest.TestCase): ...@@ -133,6 +134,33 @@ class EncodingTest(unittest.TestCase):
class CommandLineTests(unittest.TestCase): class CommandLineTests(unittest.TestCase):
"""Test compileall's CLI.""" """Test compileall's CLI."""
@classmethod
def setUpClass(cls):
for path in filter(os.path.isdir, sys.path):
directory_created = False
directory = pathlib.Path(path) / '__pycache__'
path = directory / 'test.try'
try:
if not directory.is_dir():
directory.mkdir()
directory_created = True
with path.open('w') as file:
file.write('# for test_compileall')
except OSError:
sys_path_writable = False
break
finally:
support.unlink(str(path))
if directory_created:
directory.rmdir()
else:
sys_path_writable = True
cls._sys_path_writable = sys_path_writable
def _skip_if_sys_path_not_writable(self):
if not self._sys_path_writable:
raise unittest.SkipTest('not all entries on sys.path are writable')
def _get_run_args(self, args): def _get_run_args(self, args):
interp_args = ['-S'] interp_args = ['-S']
if sys.flags.optimize: if sys.flags.optimize:
...@@ -159,8 +187,8 @@ class CommandLineTests(unittest.TestCase): ...@@ -159,8 +187,8 @@ class CommandLineTests(unittest.TestCase):
self.assertFalse(os.path.exists(path)) self.assertFalse(os.path.exists(path))
def setUp(self): def setUp(self):
self.addCleanup(self._cleanup)
self.directory = tempfile.mkdtemp() self.directory = tempfile.mkdtemp()
self.addCleanup(support.rmtree, self.directory)
self.pkgdir = os.path.join(self.directory, 'foo') self.pkgdir = os.path.join(self.directory, 'foo')
os.mkdir(self.pkgdir) os.mkdir(self.pkgdir)
self.pkgdir_cachedir = os.path.join(self.pkgdir, '__pycache__') self.pkgdir_cachedir = os.path.join(self.pkgdir, '__pycache__')
...@@ -168,11 +196,9 @@ class CommandLineTests(unittest.TestCase): ...@@ -168,11 +196,9 @@ class CommandLineTests(unittest.TestCase):
self.initfn = script_helper.make_script(self.pkgdir, '__init__', '') self.initfn = script_helper.make_script(self.pkgdir, '__init__', '')
self.barfn = script_helper.make_script(self.pkgdir, 'bar', '') self.barfn = script_helper.make_script(self.pkgdir, 'bar', '')
def _cleanup(self):
support.rmtree(self.directory)
def test_no_args_compiles_path(self): def test_no_args_compiles_path(self):
# Note that -l is implied for the no args case. # Note that -l is implied for the no args case.
self._skip_if_sys_path_not_writable()
bazfn = script_helper.make_script(self.directory, 'baz', '') bazfn = script_helper.make_script(self.directory, 'baz', '')
self.assertRunOK(PYTHONPATH=self.directory) self.assertRunOK(PYTHONPATH=self.directory)
self.assertCompiled(bazfn) self.assertCompiled(bazfn)
...@@ -180,6 +206,7 @@ class CommandLineTests(unittest.TestCase): ...@@ -180,6 +206,7 @@ class CommandLineTests(unittest.TestCase):
self.assertNotCompiled(self.barfn) self.assertNotCompiled(self.barfn)
def test_no_args_respects_force_flag(self): def test_no_args_respects_force_flag(self):
self._skip_if_sys_path_not_writable()
bazfn = script_helper.make_script(self.directory, 'baz', '') bazfn = script_helper.make_script(self.directory, 'baz', '')
self.assertRunOK(PYTHONPATH=self.directory) self.assertRunOK(PYTHONPATH=self.directory)
pycpath = importlib.util.cache_from_source(bazfn) pycpath = importlib.util.cache_from_source(bazfn)
...@@ -196,6 +223,7 @@ class CommandLineTests(unittest.TestCase): ...@@ -196,6 +223,7 @@ class CommandLineTests(unittest.TestCase):
self.assertNotEqual(mtime, mtime2) self.assertNotEqual(mtime, mtime2)
def test_no_args_respects_quiet_flag(self): def test_no_args_respects_quiet_flag(self):
self._skip_if_sys_path_not_writable()
script_helper.make_script(self.directory, 'baz', '') script_helper.make_script(self.directory, 'baz', '')
noisy = self.assertRunOK(PYTHONPATH=self.directory) noisy = self.assertRunOK(PYTHONPATH=self.directory)
self.assertIn(b'Listing ', noisy) self.assertIn(b'Listing ', noisy)
......
...@@ -194,6 +194,9 @@ Library ...@@ -194,6 +194,9 @@ Library
Patch from Łukasz Langa. Patch from Łukasz Langa.
- Issue #23888: Handle fractional time in cookie expiry. Patch by ssh. - Issue #23888: Handle fractional time in cookie expiry. Patch by ssh.
- Issue #25099: Make test_compileall not fail when a entry on sys.path cannot
be written to (commonly seen in administrative installs on Windows).
- Issue #23004: mock_open() now reads binary data correctly when the type of - Issue #23004: mock_open() now reads binary data correctly when the type of
read_data is bytes. Initial patch by Aaron Hill. read_data is bytes. Initial patch by Aaron Hill.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment