Skip to content

Commit 14309d4

Browse files
vstinnerJake Taylor
authored and
Jake Taylor
committed
bpo-38470: Fix test_compileall.test_compile_dir_maxlevels() (pythonGH-16789)
Fix test_compile_dir_maxlevels() on Windows without long path support: only create 3 subdirectories instead of between 20 and 100 subdirectories. Fix also compile_dir() to use the current sys.getrecursionlimit() value as the default maxlevels value, rather than using sys.getrecursionlimit() value read at startup.
1 parent 162aa77 commit 14309d4

File tree

3 files changed

+23
-64
lines changed

3 files changed

+23
-64
lines changed

Lib/compileall.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@
1919
from functools import partial
2020
from pathlib import Path
2121

22-
RECURSION_LIMIT = sys.getrecursionlimit()
23-
2422
__all__ = ["compile_dir","compile_file","compile_path"]
2523

26-
def _walk_dir(dir, maxlevels=RECURSION_LIMIT, quiet=0):
24+
def _walk_dir(dir, maxlevels, quiet=0):
2725
if quiet < 2 and isinstance(dir, os.PathLike):
2826
dir = os.fspath(dir)
2927
if not quiet:
@@ -46,7 +44,7 @@ def _walk_dir(dir, maxlevels=RECURSION_LIMIT, quiet=0):
4644
yield from _walk_dir(fullname, maxlevels=maxlevels - 1,
4745
quiet=quiet)
4846

49-
def compile_dir(dir, maxlevels=RECURSION_LIMIT, ddir=None, force=False,
47+
def compile_dir(dir, maxlevels=None, ddir=None, force=False,
5048
rx=None, quiet=0, legacy=False, optimize=-1, workers=1,
5149
invalidation_mode=None, stripdir=None,
5250
prependdir=None, limit_sl_dest=None):
@@ -83,6 +81,8 @@ def compile_dir(dir, maxlevels=RECURSION_LIMIT, ddir=None, force=False,
8381
from concurrent.futures import ProcessPoolExecutor
8482
except ImportError:
8583
workers = 1
84+
if maxlevels is None:
85+
maxlevels = sys.getrecursionlimit()
8686
files = _walk_dir(dir, quiet=quiet, maxlevels=maxlevels)
8787
success = True
8888
if workers != 1 and ProcessPoolExecutor is not None:
@@ -285,7 +285,7 @@ def main():
285285
parser = argparse.ArgumentParser(
286286
description='Utilities to support installing Python libraries.')
287287
parser.add_argument('-l', action='store_const', const=0,
288-
default=RECURSION_LIMIT, dest='maxlevels',
288+
default=None, dest='maxlevels',
289289
help="don't recurse into subdirectories")
290290
parser.add_argument('-r', type=int, dest='recursion',
291291
help=('control the maximum recursion level. '

Lib/test/test_compileall.py

Lines changed: 15 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -46,57 +46,6 @@ def setUp(self):
4646
def tearDown(self):
4747
shutil.rmtree(self.directory)
4848

49-
def create_long_path(self):
50-
long_path = os.path.join(self.directory, "long")
51-
52-
# Create a long path, 10 directories at a time.
53-
# It will be 100 directories deep, or shorter if the OS limits it.
54-
for i in range(10):
55-
longer_path = os.path.join(
56-
long_path, *(f"dir_{i}_{j}" for j in range(10))
57-
)
58-
59-
# Check if we can open __pycache__/*.pyc.
60-
# Also, put in the source file that we want to compile
61-
longer_source = os.path.join(longer_path, '_test_long.py')
62-
longer_cache = importlib.util.cache_from_source(longer_source)
63-
try:
64-
os.makedirs(longer_path)
65-
shutil.copyfile(self.source_path, longer_source)
66-
os.makedirs(os.path.dirname(longer_cache))
67-
# Make sure we can write to the cache
68-
with open(longer_cache, 'w'):
69-
pass
70-
except FileNotFoundError:
71-
# On Windows, a FileNotFoundError("The filename or extension
72-
# is too long") is raised for long paths
73-
if sys.platform == "win32":
74-
break
75-
else:
76-
raise
77-
except OSError as exc:
78-
if exc.errno == errno.ENAMETOOLONG:
79-
break
80-
else:
81-
raise
82-
83-
# Remove the __pycache__
84-
shutil.rmtree(os.path.dirname(longer_cache))
85-
86-
long_path = longer_path
87-
long_source = longer_source
88-
long_cache = longer_cache
89-
90-
# On Windows, MAX_PATH is 260 characters, our path with the 20
91-
# directories is 160 characters long, leaving something for the
92-
# root (self.directory) as well.
93-
# Tests assume long_path contains at least 10 directories.
94-
if i < 2:
95-
raise ValueError(f'"Long path" is too short: {long_path}')
96-
97-
self.source_path_long = long_source
98-
self.bc_path_long = long_cache
99-
10049
def add_bad_source_file(self):
10150
self.bad_source_path = os.path.join(self.directory, '_test_bad.py')
10251
with open(self.bad_source_path, 'w') as file:
@@ -247,14 +196,21 @@ def test_compile_missing_multiprocessing(self, compile_file_mock):
247196
self.assertTrue(compile_file_mock.called)
248197

249198
def test_compile_dir_maxlevels(self):
250-
# Test the actual impact of maxlevels attr
251-
self.create_long_path()
252-
compileall.compile_dir(os.path.join(self.directory, "long"),
253-
maxlevels=10, quiet=True)
254-
self.assertFalse(os.path.isfile(self.bc_path_long))
255-
compileall.compile_dir(os.path.join(self.directory, "long"),
256-
quiet=True)
257-
self.assertTrue(os.path.isfile(self.bc_path_long))
199+
# Test the actual impact of maxlevels parameter
200+
depth = 3
201+
path = self.directory
202+
for i in range(1, depth + 1):
203+
path = os.path.join(path, f"dir_{i}")
204+
source = os.path.join(path, 'script.py')
205+
os.mkdir(path)
206+
shutil.copyfile(self.source_path, source)
207+
pyc_filename = importlib.util.cache_from_source(source)
208+
209+
compileall.compile_dir(self.directory, quiet=True, maxlevels=depth - 1)
210+
self.assertFalse(os.path.isfile(pyc_filename))
211+
212+
compileall.compile_dir(self.directory, quiet=True, maxlevels=depth)
213+
self.assertTrue(os.path.isfile(pyc_filename))
258214

259215
def test_strip_only(self):
260216
fullpath = ["test", "build", "real", "path"]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix ``test_compileall.test_compile_dir_maxlevels()`` on Windows without long
2+
path support: only create 3 subdirectories instead of between 20 and 100
3+
subdirectories.

0 commit comments

Comments
 (0)