@@ -168,6 +168,7 @@ def initialize():
168168 getAvailableAddons (refresh = True , isFirstLoad = True )
169169 state .cleanupRemovedDisabledAddons ()
170170 state .save ()
171+ initializeModulePackagePaths ()
171172
172173
173174def terminate ():
@@ -602,6 +603,54 @@ def _translatedManifestPaths(lang=None, forBundle=False):
602603 return [sep .join (("locale" , lang , MANIFEST_FILENAME )) for lang in langs ]
603604
604605
606+ def initializeModulePackagePaths ():
607+ """Initializes the module package paths for drivers and plugins.
608+ This ensures that drivers (such as braille display drivers) or plugins (such as app modules)
609+ can be discovered by NVDA.
610+ """
611+ import appModules
612+ import brailleDisplayDrivers
613+ import globalPlugins
614+ import synthDrivers
615+ import visionEnhancementProviders
616+ modules = [
617+ appModules ,
618+ brailleDisplayDrivers ,
619+ globalPlugins ,
620+ synthDrivers ,
621+ visionEnhancementProviders ,
622+ ]
623+ for module in modules :
624+ addDirsToPythonPackagePath (module )
625+
626+
627+ def addDirsToPythonPackagePath (module : ModuleType , subdir : typing .Optional [str ] = None ):
628+ """Add add-on and scratchpath directories for a module to the search path (__path__) of a Python package.
629+ C{subdir} is added to each directory. It defaults to the name of the Python package.
630+ @param module: The root module of the package.
631+ @param subdir: The subdirectory to be used, C{None} for the name of C{module}.
632+ """
633+ if config .isAppX or globalVars .appArgs .disableAddons :
634+ return
635+ for addon in getRunningAddons ():
636+ addon .addToPackagePath (module )
637+ if globalVars .appArgs .secure or not config .conf ['development' ]['enableScratchpadDir' ]:
638+ return
639+ if not subdir :
640+ subdir = module .__name__
641+ fullPath = os .path .join (config .getScratchpadDir (), subdir )
642+ if fullPath in module .__path__ :
643+ return
644+ # Ensure this directory exists otherwise pkgutil.iter_importers may emit None for missing paths.
645+ if not os .path .isdir (fullPath ):
646+ os .makedirs (fullPath )
647+ # Insert this path at the beginning of the module's search paths.
648+ # The module's search paths may not be a mutable list, so replace it with a new one
649+ pathList = [fullPath ]
650+ pathList .extend (module .__path__ )
651+ module .__path__ = pathList
652+
653+
605654class AddonBundle (AddonBase ):
606655 """ Represents the contents of an NVDA addon suitable for distribution.
607656 The bundle is compressed using the zip file format. Manifest information
0 commit comments