HierarchicalEmitter that lazily initializes plugins from a registry. The registry maps event patterns to lists of (module, fn_name) tuples. Before emitting any event, this emitter checks whether there are uninitialised plugins whose event patterns match the event being emitted. If s
| 32 | |
| 33 | |
| 34 | class LazyInitEmitter(HierarchicalEmitter): |
| 35 | """HierarchicalEmitter that lazily initializes plugins from a registry. |
| 36 | |
| 37 | The registry maps event patterns to lists of (module, fn_name) tuples. |
| 38 | Before emitting any event, this emitter checks whether there are |
| 39 | uninitialised plugins whose event patterns match the event being emitted. |
| 40 | If so, it imports and calls them, then proceeds with normal dispatch. |
| 41 | """ |
| 42 | |
| 43 | def __init__(self, plugin_registry=None, main_command_table_ops=None): |
| 44 | super().__init__() |
| 45 | self._init_trie = PrefixTrie() |
| 46 | # set of (module, fn_name) |
| 47 | self._initialized = set() |
| 48 | # number of entries not yet initialized |
| 49 | self._pending_count = 0 |
| 50 | # event_name -> list of entries from init trie |
| 51 | self._init_cache: dict[str, list] = {} |
| 52 | self._registry = plugin_registry or {} |
| 53 | self._main_ops = main_command_table_ops |
| 54 | self._main_ops_applied = False |
| 55 | if self._registry: |
| 56 | self.load_registry(self._registry) |
| 57 | |
| 58 | def load_registry(self, registry): |
| 59 | self._registry = registry |
| 60 | unique = set() |
| 61 | for event_pattern, entries in registry.items(): |
| 62 | for entry in entries: |
| 63 | self._init_trie.append_item(event_pattern, entry) |
| 64 | if entry not in unique: |
| 65 | unique.add(entry) |
| 66 | self._pending_count += 1 |
| 67 | self._init_cache = {} |
| 68 | |
| 69 | @property |
| 70 | def initialized_count(self): |
| 71 | return len(self._initialized) |
| 72 | |
| 73 | def _apply_main_command_table_ops(self, kwargs): |
| 74 | """Apply pre-computed renames and LazyCommand additions. |
| 75 | |
| 76 | This replaces the normal lazy-init path for |
| 77 | building-command-table.main entries, avoiding the import of |
| 78 | heavy plugin modules until the command is actually invoked. |
| 79 | """ |
| 80 | command_table = kwargs.get('command_table') |
| 81 | session = kwargs.get('session') |
| 82 | if command_table is None or session is None: |
| 83 | return |
| 84 | |
| 85 | super()._emit('before-load-plugins.building-command-table.main', {}) |
| 86 | for op in self._main_ops: |
| 87 | if op[0] == CommandTableOp.RENAME: |
| 88 | _, old_name, new_name = op |
| 89 | if old_name in command_table: |
| 90 | current = command_table[old_name] |
| 91 | command_table[new_name] = current |
no outgoing calls