Skip to content

Commit 4267c98

Browse files
authored
bpo-38112: compileall: Skip long path path on Windows if the path can't be created (GH-16414)
This avoids the buildbot failure on Windows: ``` FileNotFoundError: [WinError 206] The filename or extension is too long: 'd:\\temp\\tmp5r3z438t\\long\\1\\2\\3\\4\\5\\6\\7\\8\\9\\10\\11\\12\\13\\14\\15\\16\\17\\18\\19\\20\\21\\22\\23\\24\\25\\26\\27\\28\\29\\30\\31\\32\\33\\34\\35\\36\\37\\38\\39\\40\\41\\42\\43\\44\\45\\46\\47\\48\\49\\50\\51\\52\\53\\54\\55\\56\\57\\58\\59\\60\\61\\62\\63\\64\\65\\66\\67\\68\\69\\70\\71\\72\\73\\74\\75\\76\\77\\78' ``` Creates a path that's long but avoids OS restrictions. https://bugs.python.org/issue38112
1 parent a741457 commit 4267c98

File tree

1 file changed

+51
-12
lines changed

1 file changed

+51
-12
lines changed

Lib/test/test_compileall.py

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import time
1212
import unittest
1313
import io
14+
import errno
1415

1516
from unittest import mock, skipUnless
1617
try:
@@ -41,20 +42,57 @@ def setUp(self):
4142
os.mkdir(self.subdirectory)
4243
self.source_path3 = os.path.join(self.subdirectory, '_test3.py')
4344
shutil.copyfile(self.source_path, self.source_path3)
44-
many_directories = [str(number) for number in range(1, 100)]
45-
self.long_path = os.path.join(self.directory,
46-
"long",
47-
*many_directories)
48-
os.makedirs(self.long_path)
49-
self.source_path_long = os.path.join(self.long_path, '_test4.py')
50-
shutil.copyfile(self.source_path, self.source_path_long)
51-
self.bc_path_long = importlib.util.cache_from_source(
52-
self.source_path_long
53-
)
5445

5546
def tearDown(self):
5647
shutil.rmtree(self.directory)
5748

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"long_directory_{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+
if i < 2:
91+
raise ValueError('Path limit is too short')
92+
93+
self.source_path_long = long_source
94+
self.bc_path_long = long_cache
95+
5896
def add_bad_source_file(self):
5997
self.bad_source_path = os.path.join(self.directory, '_test_bad.py')
6098
with open(self.bad_source_path, 'w') as file:
@@ -204,13 +242,14 @@ def test_compile_missing_multiprocessing(self, compile_file_mock):
204242
compileall.compile_dir(self.directory, quiet=True, workers=5)
205243
self.assertTrue(compile_file_mock.called)
206244

207-
def text_compile_dir_maxlevels(self):
245+
def test_compile_dir_maxlevels(self):
208246
# Test the actual impact of maxlevels attr
247+
self.create_long_path()
209248
compileall.compile_dir(os.path.join(self.directory, "long"),
210249
maxlevels=10, quiet=True)
211250
self.assertFalse(os.path.isfile(self.bc_path_long))
212251
compileall.compile_dir(os.path.join(self.directory, "long"),
213-
maxlevels=110, quiet=True)
252+
quiet=True)
214253
self.assertTrue(os.path.isfile(self.bc_path_long))
215254

216255
def test_strip_only(self):

0 commit comments

Comments
 (0)