def setUp(self): super(ExtensionTestCaseMixin, self).setUp() self.extension_mgr = self.get_extension_manager() # We want to override all the information, even if a previous test # already set it. The metadata may be different, and the registration # definitely needs to be replaced (as it contains extension settings). extension_id = '%s.%s' % (self.extension_class.__module__, self.extension_class.__name__) self.extension_class.id = extension_id self.extension_class.info = ExtensionInfo( ext_class=self.extension_class, package_name=self.extension_package_name, metadata=self.extension_metadata) self.extension_class.registration = RegisteredExtension.objects.create( class_name=extension_id, name=self.extension_class.info.name, enabled=True, installed=True) # We're going to manually inject the extension, instead of calling # load(), since it might not be found otherwise. self.extension_mgr._extension_classes[extension_id] = \ self.extension_class self.extension = self.extension_mgr.enable_extension(extension_id) assert self.extension
def test_create_from_entrypoint_with_custom_metadata(self): """Testing ExtensionInfo.create_from_entrypoint with custom Extension.metadata """ package_name = 'DummyExtension' module_name = 'test_extension.dummy.submodule' extension_id = '%s:DummyExtension' % module_name class TestExtension(Extension): __module__ = module_name id = extension_id metadata = { 'Name': 'OverrideName', 'Version': '3.14159', 'Summary': 'Lorem ipsum dolor sit amet.', 'Description': 'Tempus fugit.', 'License': 'None', 'Home-page': 'http://127.0.0.1/', } entrypoint = FakeEntryPoint(TestExtension, project_name=package_name) extension_info = ExtensionInfo.create_from_entrypoint(entrypoint, TestExtension) expected_metadata = entrypoint.dist.metadata.copy() expected_metadata.update(TestExtension.metadata) self._check_extension_info(extension_info=extension_info, app_name='test_extension.dummy', package_name=package_name, extension_id=extension_id, metadata=expected_metadata)
def test_custom_metadata(self): """Testing ExtensionInfo metadata from Extension.metadata""" entrypoint = Mock() entrypoint.dist = Mock() test_author = 'Test author lorem ipsum' test_description = 'Test description lorem ipsum' test_email = 'Test [email protected]' test_home_page = 'http://www.example.com' test_license = 'Test License MIT GPL Apache Drivers' test_module_name = 'testextension.dummy.dummy' test_module_to_app = 'testextension.dummy' test_project_name = 'TestProjectName' test_summary = 'Test summary lorem ipsum' test_version = '1.0' test_htdocs_path = os.path.join(settings.EXTENSIONS_STATIC_ROOT, 'Dummy') test_metadata = { 'Name': test_project_name, 'Version': test_version, 'Summary': test_summary, 'Description': test_description, 'Author': test_author, 'Author-email': test_email, 'License': test_license, 'Home-page': test_home_page, } entrypoint.dist.get_metadata_lines = Mock( return_value=[ "%s: %s" % (key, 'Dummy') for key, value in six.iteritems(test_metadata) ]) entrypoint.dist.project_name = 'Dummy' entrypoint.dist.version = 'Dummy' ext_class = Mock() ext_class.__module__ = test_module_name ext_class.metadata = test_metadata extension_info = ExtensionInfo(entrypoint, ext_class) self.assertEqual(extension_info.app_name, test_module_to_app) self.assertEqual(extension_info.author, test_author) self.assertEqual(extension_info.author_email, test_email) self.assertEqual(extension_info.description, test_description) self.assertFalse(extension_info.enabled) self.assertEqual(extension_info.installed_htdocs_path, test_htdocs_path) self.assertFalse(extension_info.installed) self.assertEqual(extension_info.license, test_license) self.assertEqual(extension_info.metadata, test_metadata) self.assertEqual(extension_info.name, test_project_name) self.assertEqual(extension_info.summary, test_summary) self.assertEqual(extension_info.url, test_home_page) self.assertEqual(extension_info.version, test_version)
def test_create_from_entrypoint(self): """Testing ExtensionInfo.create_from_entrypoint""" module_name = 'test_extension.dummy.submodule' package_name = 'DummyExtension' extension_id = '%s:DummyExtension' % module_name class TestExtension(Extension): __module__ = module_name id = extension_id entrypoint = FakeEntryPoint(TestExtension, project_name=package_name) extension_info = ExtensionInfo.create_from_entrypoint(entrypoint, TestExtension) self._check_extension_info(extension_info=extension_info, app_name='test_extension.dummy', package_name=package_name, extension_id=extension_id, metadata=entrypoint.dist.metadata)
def _load_extensions(self, full_reload=False): if full_reload: # We're reloading everything, so nuke all the cached copies. self._clear_extensions() self._clear_template_cache() self._load_errors = {} # Preload all the RegisteredExtension objects registered_extensions = {} for registered_ext in RegisteredExtension.objects.all(): registered_extensions[registered_ext.class_name] = registered_ext found_extensions = {} found_registrations = {} registrations_to_fetch = [] find_registrations = False extensions_changed = False for entrypoint in self._entrypoint_iterator(): registered_ext = None try: ext_class = entrypoint.load() except Exception as e: logging.exception("Error loading extension %s: %s" % (entrypoint.name, e)) extension_id = '%s.%s' % (entrypoint.module_name, '.'.join( entrypoint.attrs)) self._store_load_error(extension_id, e) continue # A class's extension ID is its class name. We want to # make this easier for users to access by giving it an 'id' # variable, which will be accessible both on the class and on # instances. class_name = ext_class.id = "%s.%s" % (ext_class.__module__, ext_class.__name__) self._extension_classes[class_name] = ext_class found_extensions[class_name] = ext_class # Don't override the info if we've previously loaded this # class. if not getattr(ext_class, 'info', None): ext_class.info = ExtensionInfo.create_from_entrypoint( entrypoint, ext_class) registered_ext = registered_extensions.get(class_name) if registered_ext: found_registrations[class_name] = registered_ext if not hasattr(ext_class, 'registration'): find_registrations = True else: registrations_to_fetch.append( (class_name, entrypoint.dist.project_name)) find_registrations = True if find_registrations: if registrations_to_fetch: stored_registrations = list( RegisteredExtension.objects.filter( class_name__in=registrations_to_fetch)) # Go through the list of registrations found in the database # and mark them as found for later processing. for registered_ext in stored_registrations: class_name = registered_ext.class_name found_registrations[class_name] = registered_ext # Go through each registration we still need and couldn't find, # and create an entry in the database. These are going to be # newly discovered extensions. for class_name, ext_name in registrations_to_fetch: if class_name not in found_registrations: try: registered_ext = RegisteredExtension.objects.create( class_name=class_name, name=ext_name) except IntegrityError: # An entry was created since we last looked up # anything. Fetch it from the database. registered_ext = RegisteredExtension.objects.get( class_name=class_name) found_registrations[class_name] = registered_ext # Now we have all the RegisteredExtension instances. Go through # and initialize each of them. for class_name, registered_ext in six.iteritems(found_registrations): ext_class = found_extensions[class_name] ext_class.registration = registered_ext if (ext_class.registration.enabled and ext_class.id not in self._extension_instances): try: self._init_extension(ext_class) except EnablingExtensionError: # When in debug mode, we want this error to be noticed. # However, in production, it shouldn't break the whole # server, so continue on. if not settings.DEBUG: continue extensions_changed = True # At this point, if we're reloading, it's possible that the user # has removed some extensions. Go through and remove any that we # can no longer find. # # While we're at it, since we're at a point where we've seen all # extensions, we can set the ExtensionInfo.requirements for # each extension for class_name, ext_class in six.iteritems(self._extension_classes): if class_name not in found_extensions: if class_name in self._extension_instances: self.disable_extension(class_name) del self._extension_classes[class_name] extensions_changed = True else: ext_class.info.requirements = \ [self.get_installed_extension(requirement_id) for requirement_id in ext_class.requirements] # Add the sync generation if it doesn't already exist. self._gen_sync.refresh() settings.AJAX_SERIAL = self._gen_sync.sync_gen if extensions_changed: self._recalculate_middleware()
def load(self, full_reload=False): """ Loads all known extensions, initializing any that are recorded as being enabled. If this is called a second time, it will refresh the list of extensions, adding new ones and removing deleted ones. If full_reload is passed, all state is cleared and we reload all extensions and state from scratch. """ if full_reload: # We're reloading everything, so nuke all the cached copies. self._clear_extensions() self._clear_template_cache() self._load_errors = {} # Preload all the RegisteredExtension objects registered_extensions = {} for registered_ext in RegisteredExtension.objects.all(): registered_extensions[registered_ext.class_name] = registered_ext found_extensions = {} extensions_changed = False for entrypoint in self._entrypoint_iterator(): registered_ext = None try: ext_class = entrypoint.load() except Exception as e: logging.error("Error loading extension %s: %s" % (entrypoint.name, e)) extension_id = '%s.%s' % (entrypoint.module_name, '.'.join( entrypoint.attrs)) self._store_load_error(extension_id, e) continue # A class's extension ID is its class name. We want to # make this easier for users to access by giving it an 'id' # variable, which will be accessible both on the class and on # instances. class_name = ext_class.id = "%s.%s" % (ext_class.__module__, ext_class.__name__) self._extension_classes[class_name] = ext_class found_extensions[class_name] = ext_class # Don't override the info if we've previously loaded this # class. if not getattr(ext_class, "info", None): ext_class.info = ExtensionInfo(entrypoint, ext_class) # If the ext_class has a registration variable that's set, then # it's already been loaded. We don't want to bother creating a # new one. if not hasattr(ext_class, "registration"): if class_name in registered_extensions: registered_ext = registered_extensions[class_name] else: registered_ext, is_new = \ RegisteredExtension.objects.get_or_create( class_name=class_name, defaults={ 'name': entrypoint.dist.project_name }) ext_class.registration = registered_ext if (ext_class.registration.enabled and ext_class.id not in self._extension_instances): try: self._init_extension(ext_class) except EnablingExtensionError: # When in debug mode, we want this error to be noticed. # However, in production, it shouldn't break the whole # server, so continue on. if not settings.DEBUG: continue extensions_changed = True # At this point, if we're reloading, it's possible that the user # has removed some extensions. Go through and remove any that we # can no longer find. # # While we're at it, since we're at a point where we've seen all # extensions, we can set the ExtensionInfo.requirements for # each extension for class_name, ext_class in six.iteritems(self._extension_classes): if class_name not in found_extensions: if class_name in self._extension_instances: self.disable_extension(class_name) del self._extension_classes[class_name] extensions_changed = True else: ext_class.info.requirements = \ [self.get_installed_extension(requirement_id) for requirement_id in ext_class.requirements] # Add the sync generation if it doesn't already exist. self._add_new_sync_gen() self._last_sync_gen = cache.get(self._sync_key) settings.AJAX_SERIAL = self._last_sync_gen if extensions_changed: self._recalculate_middleware()
def _load_extensions(self, full_reload=False): if full_reload: # We're reloading everything, so nuke all the cached copies. self._clear_extensions() clear_template_caches() self._load_errors = {} # Preload all the RegisteredExtension objects registered_extensions = {} for registered_ext in RegisteredExtension.objects.all(): registered_extensions[registered_ext.class_name] = registered_ext found_extensions = {} found_registrations = {} registrations_to_fetch = [] find_registrations = False extensions_changed = False for entrypoint in self._entrypoint_iterator(): registered_ext = None try: ext_class = entrypoint.load() except Exception as e: logger.exception('Error loading extension %s: %s', entrypoint.name, e) extension_id = '%s.%s' % (entrypoint.module_name, '.'.join(entrypoint.attrs)) self._store_load_error(extension_id, e) continue # A class's extension ID is its class name. We want to # make this easier for users to access by giving it an 'id' # variable, which will be accessible both on the class and on # instances. class_name = ext_class.id = "%s.%s" % (ext_class.__module__, ext_class.__name__) self._extension_classes[class_name] = ext_class found_extensions[class_name] = ext_class # Don't override the info if we've previously loaded this # class. if not getattr(ext_class, 'info', None): ext_class.info = ExtensionInfo.create_from_entrypoint( entrypoint, ext_class) registered_ext = registered_extensions.get(class_name) if registered_ext: found_registrations[class_name] = registered_ext if not hasattr(ext_class, 'registration'): find_registrations = True else: registrations_to_fetch.append( (class_name, entrypoint.dist.project_name)) find_registrations = True if find_registrations: if registrations_to_fetch: stored_registrations = list( RegisteredExtension.objects.filter( class_name__in=registrations_to_fetch)) # Go through the list of registrations found in the database # and mark them as found for later processing. for registered_ext in stored_registrations: class_name = registered_ext.class_name found_registrations[class_name] = registered_ext # Go through each registration we still need and couldn't find, # and create an entry in the database. These are going to be # newly discovered extensions. for class_name, ext_name in registrations_to_fetch: if class_name not in found_registrations: try: registered_ext = RegisteredExtension.objects.create( class_name=class_name, name=ext_name) except IntegrityError: # An entry was created since we last looked up # anything. Fetch it from the database. registered_ext = RegisteredExtension.objects.get( class_name=class_name) found_registrations[class_name] = registered_ext # Now we have all the RegisteredExtension instances. Go through # and initialize each of them. for class_name, registered_ext in six.iteritems(found_registrations): ext_class = found_extensions[class_name] ext_class.registration = registered_ext if (ext_class.registration.enabled and ext_class.id not in self._extension_instances): try: self._init_extension(ext_class) except EnablingExtensionError: # When in debug mode, we want this error to be noticed. # However, in production, it shouldn't break the whole # server, so continue on. if not settings.DEBUG: continue extensions_changed = True # At this point, if we're reloading, it's possible that the user # has removed some extensions. Go through and remove any that we # can no longer find. # # While we're at it, since we're at a point where we've seen all # extensions, we can set the ExtensionInfo.requirements for # each extension for class_name, ext_class in six.iteritems(self._extension_classes): if class_name not in found_extensions: if class_name in self._extension_instances: self.disable_extension(class_name) del self._extension_classes[class_name] extensions_changed = True else: ext_class.info.requirements = \ [self.get_installed_extension(requirement_id) for requirement_id in ext_class.requirements] # Add the sync generation if it doesn't already exist. self._gen_sync.refresh() settings.AJAX_SERIAL = self._gen_sync.sync_gen if extensions_changed: self._recalculate_middleware()