Asynchronously import and instantiate all scan modules, including internal and output modules. This method is automatically invoked by `setup_modules()`. It performs several key tasks in the following sequence: 1. Install dependencies for each module via `self.helpers.depsinstaller
(self)
| 528 | return succeeded, hard_failed, soft_failed |
| 529 | |
| 530 | async def load_modules(self): |
| 531 | """Asynchronously import and instantiate all scan modules, including internal and output modules. |
| 532 | |
| 533 | This method is automatically invoked by `setup_modules()`. It performs several key tasks in the following sequence: |
| 534 | |
| 535 | 1. Install dependencies for each module via `self.helpers.depsinstaller.install()`. |
| 536 | 2. Load scan modules and updates the `modules` dictionary. |
| 537 | 3. Load internal modules and updates the `modules` dictionary. |
| 538 | 4. Load output modules and updates the `modules` dictionary. |
| 539 | 5. Sorts modules based on their `_priority` attribute. |
| 540 | |
| 541 | If any modules fail to load or their dependencies fail to install, a ScanError will be raised (unless `self.force_start` is True). |
| 542 | |
| 543 | Attributes: |
| 544 | succeeded, failed (tuple): A tuple containing lists of modules that succeeded or failed during the dependency installation. |
| 545 | loaded_modules, loaded_internal_modules, loaded_output_modules (dict): Dictionaries of successfully loaded modules. |
| 546 | failed, failed_internal, failed_output (list): Lists of module names that failed to load. |
| 547 | |
| 548 | Raises: |
| 549 | ScanError: If any module dependencies fail to install or modules fail to load, and if `self.force_start` is False. |
| 550 | |
| 551 | Returns: |
| 552 | None |
| 553 | |
| 554 | Note: |
| 555 | After all modules are loaded, they are sorted by `_priority` and stored in the `modules` dictionary. |
| 556 | """ |
| 557 | if not self._modules_loaded: |
| 558 | if not self.preset.modules: |
| 559 | self.warning("No modules to load") |
| 560 | return |
| 561 | |
| 562 | if not self.preset.scan_modules: |
| 563 | self.warning("No scan modules to load") |
| 564 | |
| 565 | # install module dependencies |
| 566 | succeeded, failed = await self.helpers.depsinstaller.install(*self.preset.modules) |
| 567 | if failed: |
| 568 | msg = f"Failed to install dependencies for {len(failed):,} modules: {','.join(failed)}" |
| 569 | self._fail_setup(msg) |
| 570 | modules = sorted([m for m in self.preset.scan_modules if m in succeeded]) |
| 571 | output_modules = sorted([m for m in self.preset.output_modules if m in succeeded]) |
| 572 | internal_modules = sorted([m for m in self.preset.internal_modules if m in succeeded]) |
| 573 | |
| 574 | # Load scan modules |
| 575 | self.verbose(f"Loading {len(modules):,} scan modules: {','.join(modules)}") |
| 576 | loaded_modules, failed = self._load_modules(modules) |
| 577 | self.modules.update(loaded_modules) |
| 578 | if len(failed) > 0: |
| 579 | msg = f"Failed to load {len(failed):,} scan modules: {','.join(failed)}" |
| 580 | self._fail_setup(msg) |
| 581 | if loaded_modules: |
| 582 | self.info( |
| 583 | f"Loaded {len(loaded_modules):,}/{len(self.preset.scan_modules):,} scan modules ({','.join(loaded_modules)})" |
| 584 | ) |
| 585 | |
| 586 | # Load internal modules |
| 587 | self.verbose(f"Loading {len(internal_modules):,} internal modules: {','.join(internal_modules)}") |