Repository: nvaccess/nvda

Issue:
Python Console: Additions to the initial namespace
<!--
Please thoroughly read NVDA's wiki article on how to fill in this template, including how to provide the required files.
Issues may be closed if the required information is not present.
https://github.com/nvaccess/nvda/wiki/Github-issue-template-explanation-and-examples
-->

### Is your feature request related to a problem? Please describe.

The initial namespace of the Python Console lacks a few common imports that would allow to take full advantage of the tab-completion capability:
 - appModules
 - controlTypes
 - globalPlugins
 - textInfos

Furthermore, one cannot customize it using a global plugin without first initializing the console.

### Describe the solution you'd like

 - Add the above-mentioned imports to the initial namespace.
 - Initialize the namespace in a dedicated method.

### Describe alternatives you've considered

Include in the initial namespace all root packages and modules found in `sys.modules`.
That would cause no new import to be performed while most empowering tab-completion.
Something like: `{key: value for key, value in sys.modules.items() if not "." in key}`
One might consider this a little too much, though…

### Additional context

Upcoming PR


Discussion:

Resolving patch:
diff --git a/source/pythonConsole.py b/source/pythonConsole.py
--- a/source/pythonConsole.py
+++ b/source/pythonConsole.py
@@ -76,25 +76,13 @@ class PythonConsole(code.InteractiveConsole, AutoPropertyObject):
 	def __init__(self, outputFunc, setPromptFunc, exitFunc, echoFunc=None, **kwargs):
 		self._output = outputFunc
 		self._echo = echoFunc
+		self._exit = exitFunc
 		self._setPrompt = setPromptFunc
 
 		#: The namespace available to the console. This can be updated externally.
 		#: @type: dict
-		# Populate with useful modules.
-		exitCmd = ExitConsoleCommand(exitFunc)
-		self.namespace = {
-			"help": HelpCommand(),
-			"exit": exitCmd,
-			"quit": exitCmd,
-			"sys": sys,
-			"os": os,
-			"wx": wx,
-			"log": log,
-			"api": api,
-			"queueHandler": queueHandler,
-			"speech": speech,
-			"braille": braille,
-		}
+		self.namespace = {}
+		self.initNamespace()
 		#: The variables last added to the namespace containing a snapshot of NVDA's state.
 		#: @type: dict
 		self._namespaceSnapshotVars = None
@@ -127,6 +115,35 @@ def push(self, line):
 		self.prompt = "..." if more else ">>>"
 		return more
 
+	def initNamespace(self):
+		"""(Re-)Initialize the console namespace with useful globals.
+		"""
+		exitCmd = ExitConsoleCommand(self._exit)
+		import appModules
+		import config
+		import controlTypes
+		import globalPlugins
+		import textInfos
+		self.namespace.clear()
+		self.namespace.update({
+			"help": HelpCommand(),
+			"exit": exitCmd,
+			"quit": exitCmd,
+			"os": os,
+			"sys": sys,
+			"wx": wx,
+			"api": api,
+			"appModules": appModules,
+			"braille": braille,
+			"config": config,
+			"controlTypes": controlTypes,
+			"globalPlugins": globalPlugins,
+			"log": log,
+			"queueHandler": queueHandler,
+			"speech": speech,
+			"textInfos": textInfos,
+		})
+
 	def updateNamespaceSnapshotVars(self):
 		"""Update the console namespace with a snapshot of NVDA's current state.
 		This creates/updates variables for the current focus, navigator object, etc.


Test patch: