diff --git a/evennia/utils/containers.py b/evennia/utils/containers.py index ae3236a2b3..a94a92454b 100644 --- a/evennia/utils/containers.py +++ b/evennia/utils/containers.py @@ -106,6 +106,7 @@ class GlobalScriptContainer(Container): callables from settings but a custom dict of tuples. """ + __BASE_SCRIPT_TYPECLASS = class_from_module(settings.BASE_SCRIPT_TYPECLASS) def __init__(self): """ @@ -202,14 +203,19 @@ class GlobalScriptContainer(Container): """ if self.typeclass_storage is None: self.typeclass_storage = {} - for key, data in self.loaded_data.items(): + for key, data in list(self.loaded_data.items()): try: typeclass = data.get("typeclass", settings.BASE_SCRIPT_TYPECLASS) - self.typeclass_storage[key] = class_from_module(typeclass) + script_typeclass = class_from_module(typeclass) + assert issubclass(script_typeclass, self.__BASE_SCRIPT_TYPECLASS) + self.typeclass_storage[key] = script_typeclass except Exception: logger.log_trace( - f"GlobalScriptContainer could not start import global script {key}." + f"GlobalScriptContainer could not start import global script {key}. " + "It will be removed (skipped)." ) + # Let's remove this key/value. We want to let other scripts load. + self.loaded_data.pop(key) def get(self, key, default=None): """ diff --git a/evennia/utils/tests/test_containers.py b/evennia/utils/tests/test_containers.py new file mode 100644 index 0000000000..0f46ec1bca --- /dev/null +++ b/evennia/utils/tests/test_containers.py @@ -0,0 +1,81 @@ +import unittest + +from evennia.utils import containers +from django.conf import settings +from django.test import override_settings +from evennia.utils.utils import class_from_module + +_BASE_SCRIPT_TYPECLASS = class_from_module(settings.BASE_SCRIPT_TYPECLASS) + +class GoodScript(_BASE_SCRIPT_TYPECLASS): + pass + +class BadScript: + """Not subclass of _BASE_SCRIPT_TYPECLASS,""" + pass + +class WorseScript(_BASE_SCRIPT_TYPECLASS): + """objects will fail upon call""" + @property + def objects(self): + from evennia import module_that_doesnt_exist + +class TestGlobalScriptContainer(unittest.TestCase): + + def test_init_with_no_scripts(self): + gsc = containers.GlobalScriptContainer() + + self.assertEqual(len(gsc.loaded_data), 0) + + @override_settings(GLOBAL_SCRIPTS={'script_name': {}}) + def test_init_with_typeclassless_script(self): + + gsc = containers.GlobalScriptContainer() + + self.assertEqual(len(gsc.loaded_data), 1) + self.assertIn('script_name', gsc.loaded_data) + + def test_start_with_no_scripts(self): + gsc = containers.GlobalScriptContainer() + + gsc.start() + + self.assertEqual(len(gsc.typeclass_storage), 0) + + @override_settings(GLOBAL_SCRIPTS={'script_name': {}}) + def test_start_with_typeclassless_script_defaults_to_base(self): + gsc = containers.GlobalScriptContainer() + + gsc.start() + + self.assertEqual(len(gsc.typeclass_storage), 1) + self.assertIn('script_name', gsc.typeclass_storage) + self.assertEqual(gsc.typeclass_storage['script_name'], _BASE_SCRIPT_TYPECLASS) + + @override_settings(GLOBAL_SCRIPTS={'script_name': {'typeclass': 'evennia.utils.tests.test_containers.GoodScript'}}) + def test_start_with_typeclassed_script_loads_it(self): + gsc = containers.GlobalScriptContainer() + + gsc.start() + + self.assertEqual(len(gsc.typeclass_storage), 1) + self.assertIn('script_name', gsc.typeclass_storage) + self.assertEqual(gsc.typeclass_storage['script_name'], GoodScript) + + @override_settings(GLOBAL_SCRIPTS={'script_name': {'typeclass': 'evennia.utils.tests.test_containers.BadScript'}}) + def test_start_with_bad_typeclassed_script_skips_it(self): + gsc = containers.GlobalScriptContainer() + + gsc.start() + + self.assertEqual(len(gsc.typeclass_storage), 0) + self.assertNotIn('script_name', gsc.typeclass_storage) + + @override_settings(GLOBAL_SCRIPTS={'script_name': {'typeclass': 'evennia.utils.tests.test_containers.WorstScript'}}) + def test_start_with_worst_typeclassed_script_skips_it(self): + gsc = containers.GlobalScriptContainer() + + gsc.start() + + self.assertEqual(len(gsc.typeclass_storage), 0) + self.assertNotIn('script_name', gsc.typeclass_storage)