Improve module imports
Import modules only on demand instead all on first module import
This commit is contained in:
		
							parent
							
								
									e999b74a5b
								
							
						
					
					
						commit
						731aaab633
					
				
					 4 changed files with 66 additions and 29 deletions
				
			
		| 
						 | 
				
			
			@ -492,7 +492,7 @@ class Connection(CommonConnection, ConnectionHandlers):
 | 
			
		|||
        self._sm_resume_data = {}
 | 
			
		||||
 | 
			
		||||
        # Register all modules
 | 
			
		||||
        modules.register(self)
 | 
			
		||||
        modules.register_modules(self)
 | 
			
		||||
 | 
			
		||||
        app.ged.register_event_handler('message-outgoing', ged.OUT_CORE,
 | 
			
		||||
            self._nec_message_outgoing)
 | 
			
		||||
| 
						 | 
				
			
			@ -505,7 +505,7 @@ class Connection(CommonConnection, ConnectionHandlers):
 | 
			
		|||
    # END __init__
 | 
			
		||||
 | 
			
		||||
    def cleanup(self):
 | 
			
		||||
        modules.unregister(self)
 | 
			
		||||
        modules.unregister_modules(self)
 | 
			
		||||
        app.ged.remove_event_handler('message-outgoing', ged.OUT_CORE,
 | 
			
		||||
            self._nec_message_outgoing)
 | 
			
		||||
        app.ged.remove_event_handler('gc-message-outgoing', ged.OUT_CORE,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,9 +17,9 @@ from typing import Dict  # pylint: disable=unused-import
 | 
			
		|||
from typing import List
 | 
			
		||||
from typing import Tuple
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
import logging
 | 
			
		||||
from importlib import import_module
 | 
			
		||||
from pathlib import Path
 | 
			
		||||
from unittest.mock import MagicMock
 | 
			
		||||
 | 
			
		||||
from gajim.common.types import ConnectionT
 | 
			
		||||
| 
						 | 
				
			
			@ -32,6 +32,49 @@ ZEROCONF_MODULES = ['iq',
 | 
			
		|||
                    'discovery',
 | 
			
		||||
                    'chatstates']
 | 
			
		||||
 | 
			
		||||
MODULES = [
 | 
			
		||||
    'adhoc_commands',
 | 
			
		||||
    'annotations',
 | 
			
		||||
    'bits_of_binary',
 | 
			
		||||
    'blocking',
 | 
			
		||||
    'bookmarks',
 | 
			
		||||
    'caps',
 | 
			
		||||
    'carbons',
 | 
			
		||||
    'chatstates',
 | 
			
		||||
    'delimiter',
 | 
			
		||||
    'discovery',
 | 
			
		||||
    'entity_time',
 | 
			
		||||
    'gateway',
 | 
			
		||||
    'httpupload',
 | 
			
		||||
    'http_auth',
 | 
			
		||||
    'iq',
 | 
			
		||||
    'last_activity',
 | 
			
		||||
    'mam',
 | 
			
		||||
    'message',
 | 
			
		||||
    'metacontacts',
 | 
			
		||||
    'muc',
 | 
			
		||||
    'pep',
 | 
			
		||||
    'ping',
 | 
			
		||||
    'presence',
 | 
			
		||||
    'privacylists',
 | 
			
		||||
    'pubsub',
 | 
			
		||||
    'receipts',
 | 
			
		||||
    'register',
 | 
			
		||||
    'roster',
 | 
			
		||||
    'roster_item_exchange',
 | 
			
		||||
    'search',
 | 
			
		||||
    'security_labels',
 | 
			
		||||
    'software_version',
 | 
			
		||||
    'user_activity',
 | 
			
		||||
    'user_avatar',
 | 
			
		||||
    'user_location',
 | 
			
		||||
    'user_mood',
 | 
			
		||||
    'user_nickname',
 | 
			
		||||
    'user_tune',
 | 
			
		||||
    'vcard_avatars',
 | 
			
		||||
    'vcard_temp',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
_imported_modules = []  # type: List[tuple]
 | 
			
		||||
_modules = {}  # type: Dict[str, Dict[str, Any]]
 | 
			
		||||
_store_publish_modules = [
 | 
			
		||||
| 
						 | 
				
			
			@ -41,20 +84,6 @@ _store_publish_modules = [
 | 
			
		|||
    'UserTune',
 | 
			
		||||
]  # type: List[str]
 | 
			
		||||
 | 
			
		||||
for file in Path(__file__).parent.iterdir():
 | 
			
		||||
    if file.stem == '__init__':
 | 
			
		||||
        continue
 | 
			
		||||
 | 
			
		||||
    _module = import_module('.%s' % file.stem, package='gajim.common.modules')
 | 
			
		||||
    if hasattr(_module, 'get_instance'):
 | 
			
		||||
        log.info('Load module: %s', file.stem)
 | 
			
		||||
        if file.stem == 'pep':
 | 
			
		||||
            # Register the PEP module first, because other modules
 | 
			
		||||
            # depend on it
 | 
			
		||||
            _imported_modules.insert(0, (_module, file.stem))
 | 
			
		||||
        else:
 | 
			
		||||
            _imported_modules.append((_module, file.stem))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ModuleMock:
 | 
			
		||||
    def __init__(self, name: str) -> None:
 | 
			
		||||
| 
						 | 
				
			
			@ -84,33 +113,32 @@ class ModuleMock:
 | 
			
		|||
        return MagicMock()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def register(con: ConnectionT, *args: Any, **kwargs: Any) -> None:
 | 
			
		||||
def register_modules(con: ConnectionT, *args: Any, **kwargs: Any) -> None:
 | 
			
		||||
    if con in _modules:
 | 
			
		||||
        return
 | 
			
		||||
    _modules[con.name] = {}
 | 
			
		||||
    for module in _imported_modules:
 | 
			
		||||
        mod, name = module
 | 
			
		||||
    for module_name in MODULES:
 | 
			
		||||
        if con.name == 'Local':
 | 
			
		||||
            if name not in ZEROCONF_MODULES:
 | 
			
		||||
            if module_name not in ZEROCONF_MODULES:
 | 
			
		||||
                continue
 | 
			
		||||
        instance, name = mod.get_instance(con, *args, **kwargs)
 | 
			
		||||
        instance, name = _load_module(module_name, con, *args, **kwargs)
 | 
			
		||||
        _modules[con.name][name] = instance
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def register_single(con: ConnectionT, instance: Any, name: str) -> None:
 | 
			
		||||
def register_single_module(con: ConnectionT, instance: Any, name: str) -> None:
 | 
			
		||||
    if con.name not in _modules:
 | 
			
		||||
        raise ValueError('Unknown account name: %s' % con.name)
 | 
			
		||||
    _modules[con.name][name] = instance
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def unregister(con: ConnectionT) -> None:
 | 
			
		||||
def unregister_modules(con: ConnectionT) -> None:
 | 
			
		||||
    for instance in _modules[con.name].values():
 | 
			
		||||
        if hasattr(instance, 'cleanup'):
 | 
			
		||||
            instance.cleanup()
 | 
			
		||||
    del _modules[con.name]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def unregister_single(con: ConnectionT, name: str) -> None:
 | 
			
		||||
def unregister_single_module(con: ConnectionT, name: str) -> None:
 | 
			
		||||
    if con.name not in _modules:
 | 
			
		||||
        return
 | 
			
		||||
    if name not in _modules[con.name]:
 | 
			
		||||
| 
						 | 
				
			
			@ -130,6 +158,15 @@ def get(account: str, name: str) -> Any:
 | 
			
		|||
        return ModuleMock(name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _load_module(name: str, con: ConnectionT, *args: Any, **kwargs: Any) -> Any:
 | 
			
		||||
    if name not in MODULES:
 | 
			
		||||
        raise ValueError('Module %s does not exist' % name)
 | 
			
		||||
    module = sys.modules.get(name)
 | 
			
		||||
    if module is None:
 | 
			
		||||
        module = import_module('.%s' % name, package='gajim.common.modules')
 | 
			
		||||
    return module.get_instance(con, *args, **kwargs)  # type: ignore
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_handlers(con: ConnectionT) -> List[Tuple[Any, ...]]:
 | 
			
		||||
    handlers = []  # type: List[Tuple[Any, ...]]
 | 
			
		||||
    for module in _modules[con.name].values():
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,7 +70,7 @@ class ConnectionZeroconf(CommonConnection, ConnectionHandlersZeroconf):
 | 
			
		|||
        self.is_zeroconf = True
 | 
			
		||||
 | 
			
		||||
        # Register all modules
 | 
			
		||||
        modules.register(self)
 | 
			
		||||
        modules.register_modules(self)
 | 
			
		||||
 | 
			
		||||
        app.ged.register_event_handler('message-outgoing', ged.OUT_CORE,
 | 
			
		||||
            self._nec_message_outgoing)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -408,7 +408,7 @@ class PluginManager(metaclass=Singleton):
 | 
			
		|||
                if not module.zeroconf and con.name == 'Local':
 | 
			
		||||
                    continue
 | 
			
		||||
                instance, name = module.get_instance(con)
 | 
			
		||||
                modules.register_single(con, instance, name)
 | 
			
		||||
                modules.register_single_module(con, instance, name)
 | 
			
		||||
 | 
			
		||||
                # If handlers have been registered, register the
 | 
			
		||||
                # plugin handlers. Otherwise this will be done
 | 
			
		||||
| 
						 | 
				
			
			@ -424,7 +424,7 @@ class PluginManager(metaclass=Singleton):
 | 
			
		|||
        for con in app.connections.values():
 | 
			
		||||
            for module in plugin.modules:
 | 
			
		||||
                instance = con.get_module(module.name)
 | 
			
		||||
                modules.unregister_single(con, module.name)
 | 
			
		||||
                modules.unregister_single_module(con, module.name)
 | 
			
		||||
 | 
			
		||||
                # Account is still connected and handlers are registered
 | 
			
		||||
                # So just unregister the plugin handlers
 | 
			
		||||
| 
						 | 
				
			
			@ -562,7 +562,7 @@ class PluginManager(metaclass=Singleton):
 | 
			
		|||
                instance, name = module.get_instance(con)
 | 
			
		||||
                if not module.zeroconf and con.name == 'Local':
 | 
			
		||||
                    continue
 | 
			
		||||
                modules.register_single(con, instance, name)
 | 
			
		||||
                modules.register_single_module(con, instance, name)
 | 
			
		||||
 | 
			
		||||
    def _plugin_is_active_in_global_config(self, plugin):
 | 
			
		||||
        return app.config.get_per('plugins', plugin.short_name, 'active')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue