Skip to content

Commit 7e5c107

Browse files
bpo-45020: Add more test cases for frozen modules. (gh-28664)
I've added a number of test-only modules. Some of those cases are covered by the recently frozen stdlib modules (and some will be once we add encodings back in). However, I figured we'd play it safe by having a set of modules guaranteed to be there during tests. https://bugs.python.org/issue45020
1 parent ec4d917 commit 7e5c107

13 files changed

+205
-24
lines changed

Lib/__phello__.foo.py

-1
This file was deleted.

Lib/__phello__/__init__.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
initialized = True
2+
3+
def main():
4+
print("Hello world!")
5+
6+
if __name__ == '__main__':
7+
main()

Lib/__phello__/ham/__init__.py

Whitespace-only changes.

Lib/__phello__/ham/eggs.py

Whitespace-only changes.

Lib/__phello__/spam.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
initialized = True
2+
3+
def main():
4+
print("Hello world!")
5+
6+
if __name__ == '__main__':
7+
main()

Lib/test/test_frozen.py

+28
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
# Invalid marshalled data in frozen.c could case the interpreter to
1111
# crash when __hello__ is imported.
1212

13+
import importlib.machinery
1314
import sys
1415
import unittest
1516
from test.support import captured_stdout, import_helper
@@ -26,6 +27,33 @@ def test_frozen(self):
2627
__hello__.main()
2728
self.assertEqual(out.getvalue(), 'Hello world!\n')
2829

30+
def test_frozen_submodule_in_unfrozen_package(self):
31+
with import_helper.CleanImport('__phello__', '__phello__.spam'):
32+
with import_helper.frozen_modules(enabled=False):
33+
import __phello__
34+
with import_helper.frozen_modules(enabled=True):
35+
import __phello__.spam as spam
36+
self.assertIs(spam, __phello__.spam)
37+
self.assertIsNot(__phello__.__spec__.loader,
38+
importlib.machinery.FrozenImporter)
39+
self.assertIs(spam.__spec__.loader,
40+
importlib.machinery.FrozenImporter)
41+
42+
# This is not possible until frozen packages have __path__ set properly.
43+
# See https://bugs.python.org/issue21736.
44+
@unittest.expectedFailure
45+
def test_unfrozen_submodule_in_frozen_package(self):
46+
with import_helper.CleanImport('__phello__', '__phello__.spam'):
47+
with import_helper.frozen_modules(enabled=True):
48+
import __phello__
49+
with import_helper.frozen_modules(enabled=False):
50+
import __phello__.spam as spam
51+
self.assertIs(spam, __phello__.spam)
52+
self.assertIs(__phello__.__spec__.loader,
53+
importlib.machinery.FrozenImporter)
54+
self.assertIsNot(spam.__spec__.loader,
55+
importlib.machinery.FrozenImporter)
56+
2957

3058
if __name__ == '__main__':
3159
unittest.main()

Lib/test/test_importlib/frozen/test_finder.py

+66-13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from .. import abc
2+
import os.path
23
from .. import util
34

45
machinery = util.import_importlib('importlib.machinery')
@@ -13,34 +14,86 @@ class FindSpecTests(abc.FinderTests):
1314

1415
"""Test finding frozen modules."""
1516

16-
def find(self, name, path=None):
17+
def find(self, name, **kwargs):
1718
finder = self.machinery.FrozenImporter
1819
with import_helper.frozen_modules():
19-
return finder.find_spec(name, path)
20+
return finder.find_spec(name, **kwargs)
2021

21-
def test_module(self):
22-
name = '__hello__'
23-
spec = self.find(name)
22+
def check(self, spec, name):
23+
self.assertEqual(spec.name, name)
24+
self.assertIs(spec.loader, self.machinery.FrozenImporter)
2425
self.assertEqual(spec.origin, 'frozen')
26+
self.assertFalse(spec.has_location)
2527

26-
def test_package(self):
27-
spec = self.find('__phello__')
28-
self.assertIsNotNone(spec)
29-
30-
def test_module_in_package(self):
31-
spec = self.find('__phello__.spam', ['__phello__'])
32-
self.assertIsNotNone(spec)
28+
def test_module(self):
29+
names = [
30+
'__hello__',
31+
'__hello_alias__',
32+
'__hello_only__',
33+
'__phello__.__init__',
34+
'__phello__.spam',
35+
'__phello__.ham.__init__',
36+
'__phello__.ham.eggs',
37+
]
38+
for name in names:
39+
with self.subTest(name):
40+
spec = self.find(name)
41+
self.check(spec, name)
42+
self.assertEqual(spec.submodule_search_locations, None)
3343

34-
# No frozen package within another package to test with.
44+
def test_package(self):
45+
names = [
46+
'__phello__',
47+
'__phello__.ham',
48+
'__phello_alias__',
49+
]
50+
for name in names:
51+
with self.subTest(name):
52+
spec = self.find(name)
53+
self.check(spec, name)
54+
self.assertEqual(spec.submodule_search_locations, [])
55+
56+
# These are covered by test_module() and test_package().
57+
test_module_in_package = None
3558
test_package_in_package = None
3659

3760
# No easy way to test.
3861
test_package_over_module = None
3962

63+
def test_path_ignored(self):
64+
for name in ('__hello__', '__phello__', '__phello__.spam'):
65+
actual = self.find(name)
66+
for path in (None, object(), '', 'eggs', [], [''], ['eggs']):
67+
with self.subTest((name, path)):
68+
spec = self.find(name, path=path)
69+
self.assertEqual(spec, actual)
70+
71+
def test_target_ignored(self):
72+
imported = ('__hello__', '__phello__')
73+
with import_helper.CleanImport(*imported, usefrozen=True):
74+
import __hello__ as match
75+
import __phello__ as nonmatch
76+
name = '__hello__'
77+
actual = self.find(name)
78+
for target in (None, match, nonmatch, object(), 'not-a-module-object'):
79+
with self.subTest(target):
80+
spec = self.find(name, target=target)
81+
self.assertEqual(spec, actual)
82+
4083
def test_failure(self):
4184
spec = self.find('<not real>')
4285
self.assertIsNone(spec)
4386

87+
def test_not_using_frozen(self):
88+
finder = self.machinery.FrozenImporter
89+
with import_helper.frozen_modules(enabled=False):
90+
# both frozen and not frozen
91+
spec1 = finder.find_spec('__hello__')
92+
# only frozen
93+
spec2 = finder.find_spec('__hello_only__')
94+
self.assertIsNone(spec1)
95+
self.assertIsNone(spec2)
96+
4497

4598
(Frozen_FindSpecTests,
4699
Source_FindSpecTests

Makefile.pre.in

+27-2
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,12 @@ FROZEN_FILES_IN = \
752752
Lib/os.py \
753753
Lib/site.py \
754754
Lib/stat.py \
755-
Lib/__hello__.py
755+
Lib/__hello__.py \
756+
Lib/__phello__/__init__.py \
757+
Lib/__phello__/ham/__init__.py \
758+
Lib/__phello__/ham/eggs.py \
759+
Lib/__phello__/spam.py \
760+
Tools/freeze/flag.py
756761
# End FROZEN_FILES_IN
757762
FROZEN_FILES_OUT = \
758763
Python/frozen_modules/importlib._bootstrap.h \
@@ -769,7 +774,12 @@ FROZEN_FILES_OUT = \
769774
Python/frozen_modules/os.h \
770775
Python/frozen_modules/site.h \
771776
Python/frozen_modules/stat.h \
772-
Python/frozen_modules/__hello__.h
777+
Python/frozen_modules/__hello__.h \
778+
Python/frozen_modules/__phello__.h \
779+
Python/frozen_modules/__phello__.ham.h \
780+
Python/frozen_modules/__phello__.ham.eggs.h \
781+
Python/frozen_modules/__phello__.spam.h \
782+
Python/frozen_modules/frozen_only.h
773783
# End FROZEN_FILES_OUT
774784

775785
Programs/_freeze_module.o: Programs/_freeze_module.c Makefile
@@ -824,6 +834,21 @@ Python/frozen_modules/stat.h: Programs/_freeze_module Lib/stat.py
824834
Python/frozen_modules/__hello__.h: Programs/_freeze_module Lib/__hello__.py
825835
Programs/_freeze_module __hello__ $(srcdir)/Lib/__hello__.py $(srcdir)/Python/frozen_modules/__hello__.h
826836

837+
Python/frozen_modules/__phello__.h: Programs/_freeze_module Lib/__phello__/__init__.py
838+
Programs/_freeze_module __phello__ $(srcdir)/Lib/__phello__/__init__.py $(srcdir)/Python/frozen_modules/__phello__.h
839+
840+
Python/frozen_modules/__phello__.ham.h: Programs/_freeze_module Lib/__phello__/ham/__init__.py
841+
Programs/_freeze_module __phello__.ham $(srcdir)/Lib/__phello__/ham/__init__.py $(srcdir)/Python/frozen_modules/__phello__.ham.h
842+
843+
Python/frozen_modules/__phello__.ham.eggs.h: Programs/_freeze_module Lib/__phello__/ham/eggs.py
844+
Programs/_freeze_module __phello__.ham.eggs $(srcdir)/Lib/__phello__/ham/eggs.py $(srcdir)/Python/frozen_modules/__phello__.ham.eggs.h
845+
846+
Python/frozen_modules/__phello__.spam.h: Programs/_freeze_module Lib/__phello__/spam.py
847+
Programs/_freeze_module __phello__.spam $(srcdir)/Lib/__phello__/spam.py $(srcdir)/Python/frozen_modules/__phello__.spam.h
848+
849+
Python/frozen_modules/frozen_only.h: Programs/_freeze_module Tools/freeze/flag.py
850+
Programs/_freeze_module frozen_only $(srcdir)/Tools/freeze/flag.py $(srcdir)/Python/frozen_modules/frozen_only.h
851+
827852
# END: freezing modules
828853

829854
Tools/scripts/freeze_modules.py: Programs/_freeze_module

PCbuild/_freeze_module.vcxproj

+25
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,31 @@
305305
<IntFile>$(IntDir)__hello__.g.h</IntFile>
306306
<OutFile>$(PySourcePath)Python\frozen_modules\__hello__.h</OutFile>
307307
</None>
308+
<None Include="..\Lib\__phello__\__init__.py">
309+
<ModName>__phello__</ModName>
310+
<IntFile>$(IntDir)__phello__.g.h</IntFile>
311+
<OutFile>$(PySourcePath)Python\frozen_modules\__phello__.h</OutFile>
312+
</None>
313+
<None Include="..\Lib\__phello__\ham\__init__.py">
314+
<ModName>__phello__.ham</ModName>
315+
<IntFile>$(IntDir)__phello__.ham.g.h</IntFile>
316+
<OutFile>$(PySourcePath)Python\frozen_modules\__phello__.ham.h</OutFile>
317+
</None>
318+
<None Include="..\Lib\__phello__\ham\eggs.py">
319+
<ModName>__phello__.ham.eggs</ModName>
320+
<IntFile>$(IntDir)__phello__.ham.eggs.g.h</IntFile>
321+
<OutFile>$(PySourcePath)Python\frozen_modules\__phello__.ham.eggs.h</OutFile>
322+
</None>
323+
<None Include="..\Lib\__phello__\spam.py">
324+
<ModName>__phello__.spam</ModName>
325+
<IntFile>$(IntDir)__phello__.spam.g.h</IntFile>
326+
<OutFile>$(PySourcePath)Python\frozen_modules\__phello__.spam.h</OutFile>
327+
</None>
328+
<None Include="..\Tools\freeze\flag.py">
329+
<ModName>frozen_only</ModName>
330+
<IntFile>$(IntDir)frozen_only.g.h</IntFile>
331+
<OutFile>$(PySourcePath)Python\frozen_modules\frozen_only.h</OutFile>
332+
</None>
308333
<!-- END frozen modules -->
309334
</ItemGroup>
310335
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

PCbuild/_freeze_module.vcxproj.filters

+15
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,21 @@
6161
<None Include="..\Lib\__hello__.py">
6262
<Filter>Python Files</Filter>
6363
</None>
64+
<None Include="..\Lib\__phello__\__init__.py">
65+
<Filter>Python Files</Filter>
66+
</None>
67+
<None Include="..\Lib\__phello__\ham\__init__.py">
68+
<Filter>Python Files</Filter>
69+
</None>
70+
<None Include="..\Lib\__phello__\ham\eggs.py">
71+
<Filter>Python Files</Filter>
72+
</None>
73+
<None Include="..\Lib\__phello__\spam.py">
74+
<Filter>Python Files</Filter>
75+
</None>
76+
<None Include="..\Tools\freeze\flag.py">
77+
<Filter>Python Files</Filter>
78+
</None>
6479
<!-- END frozen modules -->
6580
</ItemGroup>
6681
</Project>

Python/frozen.c

+18-2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@
5353
#include "frozen_modules/site.h"
5454
#include "frozen_modules/stat.h"
5555
#include "frozen_modules/__hello__.h"
56+
#include "frozen_modules/__phello__.h"
57+
#include "frozen_modules/__phello__.ham.h"
58+
#include "frozen_modules/__phello__.ham.eggs.h"
59+
#include "frozen_modules/__phello__.spam.h"
60+
#include "frozen_modules/frozen_only.h"
5661
/* End includes */
5762

5863
/* Note that a negative size indicates a package. */
@@ -84,8 +89,19 @@ static const struct _frozen _PyImport_FrozenModules[] = {
8489

8590
/* Test module */
8691
{"__hello__", _Py_M____hello__, (int)sizeof(_Py_M____hello__)},
87-
{"__phello__", _Py_M____hello__, -(int)sizeof(_Py_M____hello__)},
88-
{"__phello__.spam", _Py_M____hello__, (int)sizeof(_Py_M____hello__)},
92+
{"__hello_alias__", _Py_M____hello__, (int)sizeof(_Py_M____hello__)},
93+
{"__phello_alias__", _Py_M____hello__, -(int)sizeof(_Py_M____hello__)},
94+
{"__phello_alias__.spam", _Py_M____hello__, (int)sizeof(_Py_M____hello__)},
95+
{"__phello__", _Py_M____phello__, -(int)sizeof(_Py_M____phello__)},
96+
{"__phello__.__init__", _Py_M____phello__, (int)sizeof(_Py_M____phello__)},
97+
{"__phello__.ham", _Py_M____phello___ham, -(int)sizeof(_Py_M____phello___ham)},
98+
{"__phello__.ham.__init__", _Py_M____phello___ham,
99+
(int)sizeof(_Py_M____phello___ham)},
100+
{"__phello__.ham.eggs", _Py_M____phello___ham_eggs,
101+
(int)sizeof(_Py_M____phello___ham_eggs)},
102+
{"__phello__.spam", _Py_M____phello___spam,
103+
(int)sizeof(_Py_M____phello___spam)},
104+
{"__hello_only__", _Py_M__frozen_only, (int)sizeof(_Py_M__frozen_only)},
89105
{0, 0, 0} /* sentinel */
90106
};
91107

Tools/scripts/freeze_modules.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
2121
ROOT_DIR = os.path.abspath(ROOT_DIR)
22+
FROZEN_ONLY = os.path.join(ROOT_DIR, 'Tools', 'freeze', 'flag.py')
2223

2324
STDLIB_DIR = os.path.join(ROOT_DIR, 'Lib')
2425
# If MODULES_DIR is changed then the .gitattributes and .gitignore files
@@ -53,7 +54,6 @@ def find_tool():
5354
MAKEFILE = os.path.join(ROOT_DIR, 'Makefile.pre.in')
5455
PCBUILD_PROJECT = os.path.join(ROOT_DIR, 'PCbuild', '_freeze_module.vcxproj')
5556
PCBUILD_FILTERS = os.path.join(ROOT_DIR, 'PCbuild', '_freeze_module.vcxproj.filters')
56-
TEST_CTYPES = os.path.join(STDLIB_DIR, 'ctypes', 'test', 'test_values.py')
5757

5858

5959
OS_PATH = 'ntpath' if os.name == 'nt' else 'posixpath'
@@ -95,8 +95,11 @@ def find_tool():
9595
]),
9696
('Test module', [
9797
'__hello__',
98-
'__hello__ : <__phello__>',
99-
'__hello__ : __phello__.spam',
98+
'__hello__ : __hello_alias__',
99+
'__hello__ : <__phello_alias__>',
100+
'__hello__ : __phello_alias__.spam',
101+
'<__phello__.**.*>',
102+
f'frozen_only : __hello_only__ = {FROZEN_ONLY}',
100103
]),
101104
]
102105
ESSENTIAL = {
@@ -135,14 +138,15 @@ def parse_frozen_specs(sectionalspecs=FROZEN, destdir=None):
135138
seen = {}
136139
for section, specs in sectionalspecs:
137140
parsed = _parse_specs(specs, section, seen)
138-
for frozenid, pyfile, modname, ispkg, section in parsed:
141+
for item in parsed:
142+
frozenid, pyfile, modname, ispkg, section = item
139143
try:
140144
source = seen[frozenid]
141145
except KeyError:
142146
source = FrozenSource.from_id(frozenid, pyfile, destdir)
143147
seen[frozenid] = source
144148
else:
145-
assert not pyfile
149+
assert not pyfile or pyfile == source.pyfile, item
146150
yield FrozenModule(modname, ispkg, section, source)
147151

148152

@@ -224,7 +228,6 @@ def _parse_spec(spec, knownids=None, section=None):
224228
pkgfiles = {pyfile: pkgid}
225229
def iter_subs():
226230
for frozenid, pyfile, ispkg in resolved:
227-
assert not knownids or frozenid not in knownids, (frozenid, spec)
228231
if pkgname:
229232
modname = frozenid.replace(pkgid, pkgname, 1)
230233
else:

Tools/scripts/generate_stdlib_module_names.py

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
# Test modules and packages
2222
'__hello__',
2323
'__phello__',
24+
'__hello_alias__',
25+
'__phello_alias__',
26+
'__hello_only__',
2427
'_ctypes_test',
2528
'_testbuffer',
2629
'_testcapi',

0 commit comments

Comments
 (0)