88
99
1010from dataclasses import dataclass
11- from typing import List , Optional
11+ from typing import Callable , Dict , List , Optional , Union
1212import comtypes
1313import sys
1414import winVersion
2424import addonHandler
2525import extensionPoints
2626import garbageHandler
27+ import wx
2728
2829
2930# inform those who want to know that NVDA has finished starting up.
@@ -72,7 +73,6 @@ def handleReplaceCLIArg(cliArgument: str) -> bool:
7273 if not isParamKnown :
7374 unknownCLIParams .append (param )
7475 if unknownCLIParams :
75- import wx
7676 gui .messageBox (
7777 # Translators: Shown when NVDA has been started with unknown command line parameters.
7878 _ ("The following command line parameters are unknown to NVDA: {params}" ).format (
@@ -84,7 +84,6 @@ def handleReplaceCLIArg(cliArgument: str) -> bool:
8484 wx .OK | wx .ICON_ERROR
8585 )
8686 if config .conf .baseConfigError :
87- import wx
8887 gui .messageBox (
8988 # Translators: A message informing the user that there are errors in the configuration file.
9089 _ ("Your configuration file contains errors. "
@@ -102,7 +101,6 @@ def handleReplaceCLIArg(cliArgument: str) -> bool:
102101 gui .mainFrame .onToggleSpeechViewerCommand (evt = None )
103102 import inputCore
104103 if inputCore .manager .userGestureMap .lastUpdateContainedError :
105- import wx
106104 gui .messageBox (_ ("Your gesture map file contains errors.\n "
107105 "More details about the errors can be found in the log file." ),
108106 _ ("gesture map File Error" ), wx .OK | wx .ICON_EXCLAMATION )
@@ -114,7 +112,6 @@ def handleReplaceCLIArg(cliArgument: str) -> bool:
114112 if updateCheck and not config .conf ['update' ]['askedAllowUsageStats' ]:
115113 # a callback to save config after the usage stats question dialog has been answered.
116114 def onResult (ID ):
117- import wx
118115 if ID in (wx .ID_YES ,wx .ID_NO ):
119116 try :
120117 config .conf .save ()
@@ -267,8 +264,7 @@ def _setInitialFocus():
267264 log .exception ("Error retrieving initial focus" )
268265
269266
270- def getWxLangOrNone () -> Optional ['wx.LanguageInfo' ]:
271- import wx
267+ def getWxLangOrNone () -> Optional [wx .LanguageInfo ]:
272268 lang = languageHandler .getLanguage ()
273269 wxLocaleObj = wx .Locale ()
274270 wxLang = wxLocaleObj .FindLanguageInfo (lang )
@@ -346,8 +342,6 @@ def _closeAllWindows():
346342 """
347343 import gui
348344 from gui .settingsDialogs import SettingsDialog
349- from typing import Dict
350- import wx
351345
352346 app = wx .GetApp ()
353347
@@ -483,7 +477,6 @@ def main():
483477 log .debugWarning ("Slow starting core (%.2f sec)" % (time .time ()- globalVars .startTime ))
484478 # Translators: This is spoken when NVDA is starting.
485479 speech .speakMessage (_ ("Loading NVDA. Please wait..." ))
486- import wx
487480 import six
488481 log .info ("Using wx version %s with six version %s" % (wx .version (), six .__version__ ))
489482 class App (wx .App ):
@@ -863,21 +856,34 @@ def requestPump():
863856 return
864857 # This isn't the main thread. wx timers cannot be run outside the main thread.
865858 # Therefore, Have wx start it in the main thread with a CallAfter.
866- import wx
867859 wx .CallAfter (_pump .Start ,PUMP_MAX_DELAY , True )
868860
869- def callLater (delay , callable , * args , ** kwargs ):
861+
862+ class NVDANotInitializedError (Exception ):
863+ pass
864+
865+
866+ def callLater (
867+ delay : float ,
868+ callable : Callable ,
869+ * args ,
870+ ** kwargs
871+ ) -> Union [wx .CallLater , None ]:
870872 """Call a callable once after the specified number of milliseconds.
871873 As the call is executed within NVDA's core queue, it is possible that execution will take place slightly after the requested time.
872874 This function should never be used to execute code that brings up a modal UI as it will cause NVDA's core to block.
873- This function can be safely called from any thread.
875+ This function can be safely called from any thread once NVDA has been initialized .
874876 """
875- import wx
877+ if wx .GetApp () is None :
878+ # If NVDA has not fully initialized yet, the wxApp may not be initialized.
879+ # wx.CallLater and wx.CallAfter requires the wxApp to be initialized.
880+ raise NVDANotInitializedError ("Cannot schedule callable, wx.App is not initialized" )
876881 if threading .get_ident () == mainThreadId :
877882 return wx .CallLater (delay , _callLaterExec , callable , args , kwargs )
878883 else :
879- return wx .CallAfter (wx .CallLater ,delay , _callLaterExec , callable , args , kwargs )
884+ return wx .CallAfter (wx .CallLater , delay , _callLaterExec , callable , args , kwargs )
885+
880886
881- def _callLaterExec (callable , args , kwargs ):
887+ def _callLaterExec (callable : Callable , args , kwargs ):
882888 import queueHandler
883- queueHandler .queueFunction (queueHandler .eventQueue ,callable ,* args , ** kwargs )
889+ queueHandler .queueFunction (queueHandler .eventQueue , callable , * args , ** kwargs )
0 commit comments