Skip to content

Commit 382970e

Browse files
jasonhildebrandCito
authored andcommitted
Servlet import fix (#2)
Fix inconsistencies in Servlet import and add tests.
1 parent 14bf78e commit 382970e

File tree

7 files changed

+86
-29
lines changed

7 files changed

+86
-29
lines changed

webware/ImportManager.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,10 @@ def getReloader(self):
6161
print()
6262
return reloader
6363

64-
def moduleFromSpec(self, spec, name=None):
64+
def moduleFromSpec(self, spec):
6565
"""Load the module with the given module spec."""
6666
if not spec or not isinstance(spec, ModuleSpec):
6767
raise TypeError(f'Invalid spec: {spec!r}')
68-
if name and not isinstance(name, str):
69-
raise TypeError(f'Invalid name: {name!r}')
7068
try:
7169
module = module_from_spec(spec)
7270
except Exception:
@@ -76,14 +74,11 @@ def moduleFromSpec(self, spec, name=None):
7674
if spec.origin:
7775
self.recordFile(spec.origin)
7876
raise
79-
if name:
80-
spec.name = name
81-
module.__package__ = spec.parent
8277
self.recordModule(module)
8378
spec.loader.exec_module(module)
8479
return module
8580

86-
def findSpec(self, name, path):
81+
def findSpec(self, name, path, fullModuleName=None):
8782
"""Find the module spec for the given name at the given path."""
8883
if not name or not isinstance(name, str):
8984
raise TypeError(f'Invalid name: {name!r}')
@@ -106,6 +101,8 @@ def findSpec(self, name, path):
106101
fileName = f'{name}.py'
107102
filePath = join(path, fileName)
108103
if isfile(filePath):
104+
if fullModuleName:
105+
name = fullModuleName
109106
loader = SourceFileLoader(name, filePath)
110107
return spec_from_file_location(name, filePath, loader=loader)
111108

webware/ServletFactory.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,10 @@ def _importModuleFromDirectory(
194194
'# Auto-generated by Webware' + os.linesep)
195195
except Exception:
196196
print("Error: __init__.py file could not be created.")
197-
spec = self._imp.findSpec(moduleName, directory)
198-
module = self._imp.moduleFromSpec(spec, fullModuleName)
197+
spec = self._imp.findSpec(moduleName, directory, fullModuleName)
198+
module = self._imp.moduleFromSpec(spec)
199199
module.__donotreload__ = self._reloadClasses
200-
sys.modules['fullModuleName'] = module
200+
sys.modules[fullModuleName] = module
201201
return module
202202

203203
def loadClass(self, transaction, path):

webware/Testing/ServletImport.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
from Page import Page
3+
import sys
4+
5+
mod_name = __name__ # we expect Testing.ServletImport
6+
7+
class ServletImport(Page):
8+
"""Test of import details."""
9+
10+
def title(self):
11+
return self.__doc__
12+
13+
def writeBody(self):
14+
self.writeln('<h2>Webware Servlet Import Test</h2>')
15+
self.writeln(f'<h3>{self.title()}</h3>')
16+
mod_name_from_class = ServletImport.__module__ # we expect Testing.ServletImport
17+
mod_name_consistent = mod_name == mod_name_from_class # we expect True
18+
servlet_in_sys_modules = mod_name in sys.modules # we expect True
19+
servlet_file_watched = __file__ in self.transaction().application()._imp.fileList(update=False) # we expect True
20+
self.writeln(
21+
f"<p>mod_name = <code>{mod_name}</code></p>"
22+
f"<p>mod_name_from_class = <code>{mod_name_from_class}</code></p>"
23+
f"<p>mod_name_consistent = <code>{mod_name_consistent}</code></p>"
24+
f"<p>servlet_in_sys_modules = <code>{servlet_in_sys_modules}</code></p>"
25+
f"<p>servlet_file_watched = <code>{servlet_file_watched}</code></p>"
26+
)

webware/Testing/TestCases.data

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,6 @@
6060

6161
# If-Modified-Since
6262
/Testing/TestIMS --> TestIMS passed
63+
64+
# ServletImport
65+
/Testing/ServletImport --> Servlet imported as part of package

webware/Tests/TestEndToEnd/AppTest.py

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ class AppTest:
1717
settings = dict(
1818
PrintConfigAtStartUp=False
1919
)
20+
bufferOutput = True # set to False if you want to run pdb inside a test to debug it.
2021

2122
@classmethod
2223
def setUpClass(cls):
2324
stdout, stderr = sys.stdout, sys.stderr
24-
sys.stdout = sys.stderr = StringIO()
25+
if cls.bufferOutput:
26+
sys.stdout = sys.stderr = StringIO()
2527
cls.currentDir = getcwd()
2628
import webware
2729
webwareDir = webware.__path__[0]
@@ -35,43 +37,55 @@ def setUpClass(cls):
3537
else:
3638
error = None
3739
finally:
38-
output = sys.stdout.getvalue().rstrip()
39-
sys.stdout, sys.stderr = stdout, stderr
40+
if cls.bufferOutput:
41+
output = sys.stdout.getvalue().rstrip()
42+
sys.stdout, sys.stderr = stdout, stderr
43+
else:
44+
output = ''
4045
if error:
4146
raise RuntimeError(
4247
'Error setting up application:\n' + error +
4348
'\nOutput was:\n' + output)
44-
if (not output.startswith('Webware for Python')
45-
or 'Running in development mode' not in output
46-
or 'Loading context' not in output):
47-
raise AssertionError(
48-
'Application was not properly started.'
49-
' Output was:\n' + output)
49+
if cls.bufferOutput:
50+
if (not output.startswith('Webware for Python')
51+
or 'Running in development mode' not in output
52+
or 'Loading context' not in output):
53+
raise AssertionError(
54+
'Application was not properly started.'
55+
' Output was:\n' + output)
5056

5157
@classmethod
5258
def tearDownClass(cls):
5359
stdout, stderr = sys.stdout, sys.stderr
54-
sys.stdout = sys.stderr = StringIO()
60+
if cls.bufferOutput:
61+
sys.stdout = sys.stderr = StringIO()
5562
cls.app.shutDown()
56-
output = sys.stdout.getvalue().rstrip()
57-
sys.stdout, sys.stderr = stdout, stderr
63+
if cls.bufferOutput:
64+
output = sys.stdout.getvalue().rstrip()
65+
sys.stdout, sys.stderr = stdout, stderr
66+
else:
67+
output = ''
5868
chdir(cls.currentDir)
59-
if output != ('Application is shutting down...\n'
60-
'Application has been successfully shutdown.'):
69+
if cls.bufferOutput and output != ('Application is shutting down...\n'
70+
'Application has been successfully shutdown.'):
6171
raise AssertionError(
6272
'Application was not properly shut down. Output was:\n'
6373
+ output)
6474

6575
def setUp(self):
6676
self.stdout, self.stderr = sys.stdout, sys.stderr
67-
sys.stdout = sys.stderr = StringIO()
77+
if self.bufferOutput:
78+
sys.stdout = sys.stderr = StringIO()
6879

6980
def tearDown(self):
70-
self.output = sys.stdout.getvalue().rstrip()
71-
sys.stdout, sys.stderr = self.stdout, self.stderr
81+
if self.bufferOutput:
82+
self.output = sys.stdout.getvalue().rstrip()
83+
sys.stdout, sys.stderr = self.stdout, self.stderr
84+
else:
85+
self.output = ''
7286

7387
def run(self, result=None):
7488
result = super().run(result) # pylint: disable=no-member
75-
if not result.wasSuccessful() and self.output:
89+
if not result.wasSuccessful() and self.bufferOutput and self.output:
7690
print("Application output was:")
7791
print(self.output)

webware/Tests/TestEndToEnd/TestAdmin.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,14 @@ def testAppControl(self):
232232
'Reload the selected Python modules. Be careful!',
233233
'<input type="checkbox" name="reloads"'
234234
' value="Admin.AdminPage"> Admin.AdminPage<br>')
235-
r.form.get('reloads', index=0).checked = True
235+
236+
# things change, so don't hardcode the index of this checkbox.
237+
for i, checkbox in enumerate(r.html.find_all('input', attrs={'name': 'reloads'})):
238+
if checkbox.attrs['value'] == 'Admin.AdminPage':
239+
break
240+
else:
241+
assert False, 'Did not find expected checkbox for Admin.AdminPage'
242+
r.form.get('reloads', index=i).checked = True
236243
r = r.form.submit('action', index=1)
237244
self.assertEqual(r.status, '200 OK')
238245
r.mustcontain(

webware/Tests/TestEndToEnd/TestTesting.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,16 @@ def testCase17(self):
258258
self.assertEqual(r.headers.get('Last-Modified'), lastMod)
259259
self.assertEqual(len(r.body), size)
260260

261+
def testCase18(self):
262+
url = self.getTestCaseUrl(18, 'Servlet imported as part of package')
263+
r = self.testApp.get(url)
264+
self.assertEqual(r.status, '200 OK')
265+
r.mustcontain(
266+
'<title>Test of import details.</title>',
267+
'<p>mod_name = <code>Testing.ServletImport</code></p>',
268+
'<p>mod_name_from_class = <code>Testing.ServletImport</code></p>',
269+
f"<p>servlet_in_sys_modules = <code>True</code></p>",
270+
)
261271

262272
class TestTestingWithExtraPathInfo(TestTesting):
263273

0 commit comments

Comments
 (0)