diff --git a/webware/ImportManager.py b/webware/ImportManager.py index 107a15b..ee936a6 100644 --- a/webware/ImportManager.py +++ b/webware/ImportManager.py @@ -61,12 +61,10 @@ def getReloader(self): print() return reloader - def moduleFromSpec(self, spec, name=None): + def moduleFromSpec(self, spec): """Load the module with the given module spec.""" if not spec or not isinstance(spec, ModuleSpec): raise TypeError(f'Invalid spec: {spec!r}') - if name and not isinstance(name, str): - raise TypeError(f'Invalid name: {name!r}') try: module = module_from_spec(spec) except Exception: @@ -76,14 +74,11 @@ def moduleFromSpec(self, spec, name=None): if spec.origin: self.recordFile(spec.origin) raise - if name: - spec.name = name - module.__package__ = spec.parent self.recordModule(module) spec.loader.exec_module(module) return module - def findSpec(self, name, path): + def findSpec(self, name, path, fullModuleName=None): """Find the module spec for the given name at the given path.""" if not name or not isinstance(name, str): raise TypeError(f'Invalid name: {name!r}') @@ -106,6 +101,8 @@ def findSpec(self, name, path): fileName = f'{name}.py' filePath = join(path, fileName) if isfile(filePath): + if fullModuleName: + name = fullModuleName loader = SourceFileLoader(name, filePath) return spec_from_file_location(name, filePath, loader=loader) diff --git a/webware/ServletFactory.py b/webware/ServletFactory.py index ade00dd..921766c 100644 --- a/webware/ServletFactory.py +++ b/webware/ServletFactory.py @@ -194,10 +194,10 @@ def _importModuleFromDirectory( '# Auto-generated by Webware' + os.linesep) except Exception: print("Error: __init__.py file could not be created.") - spec = self._imp.findSpec(moduleName, directory) - module = self._imp.moduleFromSpec(spec, fullModuleName) + spec = self._imp.findSpec(moduleName, directory, fullModuleName) + module = self._imp.moduleFromSpec(spec) module.__donotreload__ = self._reloadClasses - sys.modules['fullModuleName'] = module + sys.modules[fullModuleName] = module return module def loadClass(self, transaction, path): diff --git a/webware/Testing/ServletImport.py b/webware/Testing/ServletImport.py new file mode 100644 index 0000000..b384360 --- /dev/null +++ b/webware/Testing/ServletImport.py @@ -0,0 +1,26 @@ + +from Page import Page +import sys + +mod_name = __name__ # we expect Testing.ServletImport + +class ServletImport(Page): + """Test of import details.""" + + def title(self): + return self.__doc__ + + def writeBody(self): + self.writeln('

Webware Servlet Import Test

') + self.writeln(f'

{self.title()}

') + mod_name_from_class = ServletImport.__module__ # we expect Testing.ServletImport + mod_name_consistent = mod_name == mod_name_from_class # we expect True + servlet_in_sys_modules = mod_name in sys.modules # we expect True + servlet_file_watched = __file__ in self.transaction().application()._imp.fileList(update=False) # we expect True + self.writeln( + f"

mod_name = {mod_name}

" + f"

mod_name_from_class = {mod_name_from_class}

" + f"

mod_name_consistent = {mod_name_consistent}

" + f"

servlet_in_sys_modules = {servlet_in_sys_modules}

" + f"

servlet_file_watched = {servlet_file_watched}

" + ) diff --git a/webware/Testing/TestCases.data b/webware/Testing/TestCases.data index c952182..8af0d46 100644 --- a/webware/Testing/TestCases.data +++ b/webware/Testing/TestCases.data @@ -60,3 +60,6 @@ # If-Modified-Since /Testing/TestIMS --> TestIMS passed + +# ServletImport +/Testing/ServletImport --> Servlet imported as part of package diff --git a/webware/Tests/TestEndToEnd/AppTest.py b/webware/Tests/TestEndToEnd/AppTest.py index 489e357..ae13cb6 100644 --- a/webware/Tests/TestEndToEnd/AppTest.py +++ b/webware/Tests/TestEndToEnd/AppTest.py @@ -17,11 +17,13 @@ class AppTest: settings = dict( PrintConfigAtStartUp=False ) + bufferOutput = True # set to False if you want to run pdb inside a test to debug it. @classmethod def setUpClass(cls): stdout, stderr = sys.stdout, sys.stderr - sys.stdout = sys.stderr = StringIO() + if cls.bufferOutput: + sys.stdout = sys.stderr = StringIO() cls.currentDir = getcwd() import webware webwareDir = webware.__path__[0] @@ -35,43 +37,55 @@ def setUpClass(cls): else: error = None finally: - output = sys.stdout.getvalue().rstrip() - sys.stdout, sys.stderr = stdout, stderr + if cls.bufferOutput: + output = sys.stdout.getvalue().rstrip() + sys.stdout, sys.stderr = stdout, stderr + else: + output = '' if error: raise RuntimeError( 'Error setting up application:\n' + error + '\nOutput was:\n' + output) - if (not output.startswith('Webware for Python') - or 'Running in development mode' not in output - or 'Loading context' not in output): - raise AssertionError( - 'Application was not properly started.' - ' Output was:\n' + output) + if cls.bufferOutput: + if (not output.startswith('Webware for Python') + or 'Running in development mode' not in output + or 'Loading context' not in output): + raise AssertionError( + 'Application was not properly started.' + ' Output was:\n' + output) @classmethod def tearDownClass(cls): stdout, stderr = sys.stdout, sys.stderr - sys.stdout = sys.stderr = StringIO() + if cls.bufferOutput: + sys.stdout = sys.stderr = StringIO() cls.app.shutDown() - output = sys.stdout.getvalue().rstrip() - sys.stdout, sys.stderr = stdout, stderr + if cls.bufferOutput: + output = sys.stdout.getvalue().rstrip() + sys.stdout, sys.stderr = stdout, stderr + else: + output = '' chdir(cls.currentDir) - if output != ('Application is shutting down...\n' - 'Application has been successfully shutdown.'): + if cls.bufferOutput and output != ('Application is shutting down...\n' + 'Application has been successfully shutdown.'): raise AssertionError( 'Application was not properly shut down. Output was:\n' + output) def setUp(self): self.stdout, self.stderr = sys.stdout, sys.stderr - sys.stdout = sys.stderr = StringIO() + if self.bufferOutput: + sys.stdout = sys.stderr = StringIO() def tearDown(self): - self.output = sys.stdout.getvalue().rstrip() - sys.stdout, sys.stderr = self.stdout, self.stderr + if self.bufferOutput: + self.output = sys.stdout.getvalue().rstrip() + sys.stdout, sys.stderr = self.stdout, self.stderr + else: + self.output = '' def run(self, result=None): result = super().run(result) # pylint: disable=no-member - if not result.wasSuccessful() and self.output: + if not result.wasSuccessful() and self.bufferOutput and self.output: print("Application output was:") print(self.output) diff --git a/webware/Tests/TestEndToEnd/TestAdmin.py b/webware/Tests/TestEndToEnd/TestAdmin.py index 9bdbeac..42b526f 100644 --- a/webware/Tests/TestEndToEnd/TestAdmin.py +++ b/webware/Tests/TestEndToEnd/TestAdmin.py @@ -232,7 +232,14 @@ def testAppControl(self): 'Reload the selected Python modules. Be careful!', ' Admin.AdminPage
') - r.form.get('reloads', index=0).checked = True + + # things change, so don't hardcode the index of this checkbox. + for i, checkbox in enumerate(r.html.find_all('input', attrs={'name': 'reloads'})): + if checkbox.attrs['value'] == 'Admin.AdminPage': + break + else: + assert False, 'Did not find expected checkbox for Admin.AdminPage' + r.form.get('reloads', index=i).checked = True r = r.form.submit('action', index=1) self.assertEqual(r.status, '200 OK') r.mustcontain( diff --git a/webware/Tests/TestEndToEnd/TestTesting.py b/webware/Tests/TestEndToEnd/TestTesting.py index e673722..8550f1f 100644 --- a/webware/Tests/TestEndToEnd/TestTesting.py +++ b/webware/Tests/TestEndToEnd/TestTesting.py @@ -258,6 +258,16 @@ def testCase17(self): self.assertEqual(r.headers.get('Last-Modified'), lastMod) self.assertEqual(len(r.body), size) + def testCase18(self): + url = self.getTestCaseUrl(18, 'Servlet imported as part of package') + r = self.testApp.get(url) + self.assertEqual(r.status, '200 OK') + r.mustcontain( + 'Test of import details.', + '

mod_name = Testing.ServletImport

', + '

mod_name_from_class = Testing.ServletImport

', + f"

servlet_in_sys_modules = True

", + ) class TestTestingWithExtraPathInfo(TestTesting):