Browse Source

showbase: Annotate basic `ShowBase` setup/shutdown methods (#1558)

WMOkiishi 1 year ago
parent
commit
f5b0b1e1d6

+ 3 - 0
direct/src/directbase/TestStart.py

@@ -8,6 +8,9 @@ base = ShowBase.ShowBase()
 # Put an axis in the world:
 # Put an axis in the world:
 base.loader.loadModel("models/misc/xyzAxis").reparentTo(base.render)
 base.loader.loadModel("models/misc/xyzAxis").reparentTo(base.render)
 
 
+assert base.camera is not None
+assert base.camLens is not None
+
 base.camera.setPosHpr(0, -10.0, 0, 0, 0, 0)
 base.camera.setPosHpr(0, -10.0, 0, 0, 0, 0)
 base.camLens.setFov(52.0)
 base.camLens.setFov(52.0)
 base.camLens.setNearFar(1.0, 10000.0)
 base.camLens.setNearFar(1.0, 10000.0)

+ 3 - 0
direct/src/directbase/ThreeUpStart.py

@@ -10,6 +10,9 @@ base = ThreeUpShow.ThreeUpShow()
 # Put an axis in the world:
 # Put an axis in the world:
 base.loader.loadModel("models/misc/xyzAxis").reparentTo(base.render)
 base.loader.loadModel("models/misc/xyzAxis").reparentTo(base.render)
 
 
+assert base.camera is not None
+assert base.camLens is not None
+
 base.camera.setPosHpr(0, -10.0, 0, 0, 0, 0)
 base.camera.setPosHpr(0, -10.0, 0, 0, 0, 0)
 base.camLens.setFov(52.0)
 base.camLens.setFov(52.0)
 base.camLens.setNearFar(1.0, 10000.0)
 base.camLens.setNearFar(1.0, 10000.0)

+ 82 - 74
direct/src/showbase/ShowBase.py

@@ -32,6 +32,8 @@ built-in scope.
 
 
 """
 """
 
 
+from __future__ import annotations
+
 __all__ = ['ShowBase', 'WindowControls']
 __all__ = ['ShowBase', 'WindowControls']
 
 
 # This module redefines the builtin import function with one
 # This module redefines the builtin import function with one
@@ -71,9 +73,11 @@ from panda3d.core import (
     GraphicsPipe,
     GraphicsPipe,
     GraphicsPipeSelection,
     GraphicsPipeSelection,
     GraphicsWindow,
     GraphicsWindow,
+    InputDevice,
     InputDeviceManager,
     InputDeviceManager,
     InputDeviceNode,
     InputDeviceNode,
     KeyboardButton,
     KeyboardButton,
+    Lens,
     LensNode,
     LensNode,
     Mat4,
     Mat4,
     ModelNode,
     ModelNode,
@@ -118,9 +122,11 @@ from . import DConfig
 from direct.extensions_native import NodePath_extensions # pylint: disable=unused-import
 from direct.extensions_native import NodePath_extensions # pylint: disable=unused-import
 
 
 # This needs to be available early for DirectGUI imports
 # This needs to be available early for DirectGUI imports
+from typing import Any
+builtins: Any  # Tell mypy not to worry about us setting attributes on builtins
 import sys
 import sys
 import builtins
 import builtins
-builtins.config = DConfig  # type: ignore[attr-defined]
+builtins.config = DConfig
 
 
 from direct.directnotify.DirectNotifyGlobal import directNotify, giveNotify
 from direct.directnotify.DirectNotifyGlobal import directNotify, giveNotify
 from direct.directnotify.Notifier import Notifier
 from direct.directnotify.Notifier import Notifier
@@ -141,7 +147,7 @@ import importlib
 from direct.showbase import ExceptionVarDump
 from direct.showbase import ExceptionVarDump
 from . import DirectObject
 from . import DirectObject
 from . import SfxPlayer
 from . import SfxPlayer
-from typing import ClassVar, Optional
+from typing import Callable, ClassVar, Literal, NoReturn
 if __debug__:
 if __debug__:
     from direct.showbase import GarbageReport
     from direct.showbase import GarbageReport
     from direct.directutil import DeltaProfiler
     from direct.directutil import DeltaProfiler
@@ -150,9 +156,10 @@ if __debug__:
 
 
 
 
 @atexit.register
 @atexit.register
-def exitfunc():
-    if getattr(builtins, 'base', None) is not None:
-        builtins.base.destroy()
+def exitfunc() -> None:
+    base = getattr(builtins, 'base', None)
+    if base is not None:
+        base.destroy()
 
 
 # Now ShowBase is a DirectObject.  We need this so ShowBase can hang
 # Now ShowBase is a DirectObject.  We need this so ShowBase can hang
 # hooks on messages, particularly on window-event.  This doesn't
 # hooks on messages, particularly on window-event.  This doesn't
@@ -170,7 +177,7 @@ class ShowBase(DirectObject.DirectObject):
     aspect2d: NodePath
     aspect2d: NodePath
     pixel2d: NodePath
     pixel2d: NodePath
 
 
-    def __init__(self, fStartDirect=True, windowType=None):
+    def __init__(self, fStartDirect: bool = True, windowType: str | None = None) -> None:
         """Opens a window, sets up a 3-D and several 2-D scene graphs, and
         """Opens a window, sets up a 3-D and several 2-D scene graphs, and
         everything else needed to render the scene graph to the window.
         everything else needed to render the scene graph to the window.
 
 
@@ -233,10 +240,10 @@ class ShowBase(DirectObject.DirectObject):
         self.wantRender2dp = ConfigVariableBool('want-render2dp', True).value
         self.wantRender2dp = ConfigVariableBool('want-render2dp', True).value
 
 
         self.screenshotExtension = ConfigVariableString('screenshot-extension', 'jpg').value
         self.screenshotExtension = ConfigVariableString('screenshot-extension', 'jpg').value
-        self.musicManager = None
-        self.musicManagerIsValid = None
-        self.sfxManagerList = []
-        self.sfxManagerIsValidList = []
+        self.musicManager: AudioManager | None = None
+        self.musicManagerIsValid: bool | None = None
+        self.sfxManagerList: list[AudioManager] = []
+        self.sfxManagerIsValidList: list[bool] = []
 
 
         self.wantStats = ConfigVariableBool('want-pstats', False).value
         self.wantStats = ConfigVariableBool('want-pstats', False).value
         self.wantTk = False
         self.wantTk = False
@@ -245,12 +252,12 @@ class ShowBase(DirectObject.DirectObject):
 
 
         #: Fill this in with a function to invoke when the user "exits"
         #: Fill this in with a function to invoke when the user "exits"
         #: the program by closing the main window.
         #: the program by closing the main window.
-        self.exitFunc = None
+        self.exitFunc: Callable[[], object] | None = None
 
 
         #: Add final-exit callbacks to this list.  These will be called
         #: Add final-exit callbacks to this list.  These will be called
         #: when sys.exit() is called, after Panda has unloaded, and
         #: when sys.exit() is called, after Panda has unloaded, and
         #: just before Python is about to shut down.
         #: just before Python is about to shut down.
-        self.finalExitCallbacks = []
+        self.finalExitCallbacks: list[Callable[[], object]] = []
 
 
         # Set up the TaskManager to reset the PStats clock back
         # Set up the TaskManager to reset the PStats clock back
         # whenever we resume from a pause.  This callback function is
         # whenever we resume from a pause.  This callback function is
@@ -268,7 +275,7 @@ class ShowBase(DirectObject.DirectObject):
         self.__configAspectRatio = ConfigVariableDouble('aspect-ratio', 0).value
         self.__configAspectRatio = ConfigVariableDouble('aspect-ratio', 0).value
         # This variable is used to see if the aspect ratio has changed when
         # This variable is used to see if the aspect ratio has changed when
         # we get a window-event.
         # we get a window-event.
-        self.__oldAspectRatio = None
+        self.__oldAspectRatio: float | None = None
 
 
         #: This is set to the value of the window-type config variable, but may
         #: This is set to the value of the window-type config variable, but may
         #: optionally be overridden in the Showbase constructor.  Should either
         #: optionally be overridden in the Showbase constructor.  Should either
@@ -279,68 +286,68 @@ class ShowBase(DirectObject.DirectObject):
         self.requireWindow = ConfigVariableBool('require-window', True).value
         self.requireWindow = ConfigVariableBool('require-window', True).value
 
 
         #: This is the main, or only window; see `winList` for a list of *all* windows.
         #: This is the main, or only window; see `winList` for a list of *all* windows.
-        self.win = None
-        self.frameRateMeter = None
-        self.sceneGraphAnalyzerMeter = None
+        self.win: GraphicsOutput | None = None
+        self.frameRateMeter: FrameRateMeter | None = None
+        self.sceneGraphAnalyzerMeter: SceneGraphAnalyzerMeter | None = None
         #: A list of all windows opened via `openWindow()`.
         #: A list of all windows opened via `openWindow()`.
-        self.winList = []
-        self.winControls = []
-        self.mainWinMinimized = 0
-        self.mainWinForeground = 0
+        self.winList: list[GraphicsEngine] = []
+        self.winControls: list[WindowControls] = []
+        self.mainWinMinimized = False
+        self.mainWinForeground = False
         #: Contains the :class:`~panda3d.core.GraphicsPipe` object created by
         #: Contains the :class:`~panda3d.core.GraphicsPipe` object created by
         #: `makeDefaultPipe()`.
         #: `makeDefaultPipe()`.
-        self.pipe = None
+        self.pipe: GraphicsPipe | None = None
         #: The full list of :class:`~panda3d.core.GraphicsPipe` objects,
         #: The full list of :class:`~panda3d.core.GraphicsPipe` objects,
         #: including any auxiliary pipes.  Filled by `makeAllPipes()`.
         #: including any auxiliary pipes.  Filled by `makeAllPipes()`.
-        self.pipeList = []
-        self.mouse2cam = None
-        self.buttonThrowers = None
-        self.mouseWatcher = None
+        self.pipeList: list[GraphicsPipe] = []
+        self.mouse2cam: NodePath | None = None
+        self.buttonThrowers: list[ButtonThrower] | None = None
+        self.mouseWatcher: NodePath | None = None
         #: The :class:`~panda3d.core.MouseWatcher` object, created by
         #: The :class:`~panda3d.core.MouseWatcher` object, created by
         #: `setupMouse()`.
         #: `setupMouse()`.
-        self.mouseWatcherNode = None
-        self.pointerWatcherNodes = None
-        self.mouseInterface = None
-        self.drive = None
-        self.trackball = None
-        self.texmem = None
-        self.showVertices = None
-        self.deviceButtonThrowers = []
+        self.mouseWatcherNode: MouseWatcher | None = None
+        self.pointerWatcherNodes: list[MouseWatcher] | None = None
+        self.mouseInterface: NodePath | None = None
+        self.drive: NodePath | None = None
+        self.trackball: NodePath | None = None
+        self.texmem: Any | None = None
+        self.showVertices: NodePath | None = None
+        self.deviceButtonThrowers: list[NodePath] = []
 
 
         #: This is a :class:`~panda3d.core.NodePath` pointing to the
         #: This is a :class:`~panda3d.core.NodePath` pointing to the
         #: :class:`~panda3d.core.Camera` object set up for the 3D scene.
         #: :class:`~panda3d.core.Camera` object set up for the 3D scene.
         #: Usually a child of `camera`.
         #: Usually a child of `camera`.
-        self.cam = None
+        self.cam: NodePath | None = None
         #: Same as `cam`, but for the 2D scene graph.
         #: Same as `cam`, but for the 2D scene graph.
-        self.cam2d = None
+        self.cam2d: NodePath | None = None
         #: Same as `cam2d`, but for the 2D overlay scene graph.
         #: Same as `cam2d`, but for the 2D overlay scene graph.
-        self.cam2dp = None
+        self.cam2dp: NodePath | None = None
 
 
         #: This is the :class:`~panda3d.core.NodePath` that should be used to
         #: This is the :class:`~panda3d.core.NodePath` that should be used to
         #: manipulate the camera.  It points at the node to which the default
         #: manipulate the camera.  It points at the node to which the default
         #: camera (`cam`, `camNode`) is attached.
         #: camera (`cam`, `camNode`) is attached.
-        self.camera = None
+        self.camera: NodePath | None = None
         #: Same as `camera`, but for the 2D scene graph.  Parent of `cam2d`.
         #: Same as `camera`, but for the 2D scene graph.  Parent of `cam2d`.
-        self.camera2d = None
+        self.camera2d: NodePath | None = None
         #: Same as `camera2d`, but for the 2D overlay scene graph.  Parent of
         #: Same as `camera2d`, but for the 2D overlay scene graph.  Parent of
         #: `cam2dp`.
         #: `cam2dp`.
-        self.camera2dp = None
+        self.camera2dp: NodePath | None = None
 
 
         #: A list of all cameras created with `makeCamera()`, including `cam`.
         #: A list of all cameras created with `makeCamera()`, including `cam`.
-        self.camList = []
+        self.camList: list[NodePath] = []
         #: Convenience accessor for base.cam.node(), containing a
         #: Convenience accessor for base.cam.node(), containing a
         #: :class:`~panda3d.core.Camera` object.
         #: :class:`~panda3d.core.Camera` object.
-        self.camNode = None
+        self.camNode: Camera | None = None
         #: Convenience accessor for base.camNode.get_lens(), containing a
         #: Convenience accessor for base.camNode.get_lens(), containing a
         #: :class:`~panda3d.core.Lens` object.
         #: :class:`~panda3d.core.Lens` object.
-        self.camLens = None
-        self.camFrustumVis = None
+        self.camLens: Lens | None = None
+        self.camFrustumVis: NodePath | None = None
         self.direct = None
         self.direct = None
         #: This is used to store the wx.Application object used when want-wx is
         #: This is used to store the wx.Application object used when want-wx is
         #: set or `startWx()` is called.
         #: set or `startWx()` is called.
-        self.wxApp = None
+        self.wxApp: Any | None = None
         self.wxAppCreated = False
         self.wxAppCreated = False
-        self.tkRoot = None
+        self.tkRoot: Any | None = None
         self.tkRootCreated = False
         self.tkRootCreated = False
 
 
         # This is used for syncing multiple PCs in a distributed cluster
         # This is used for syncing multiple PCs in a distributed cluster
@@ -371,11 +378,11 @@ class ShowBase(DirectObject.DirectObject):
         #: traverse it automatically in the collisionLoop task, so you won't
         #: traverse it automatically in the collisionLoop task, so you won't
         #: need to call :meth:`~panda3d.core.CollisionTraverser.traverse()`
         #: need to call :meth:`~panda3d.core.CollisionTraverser.traverse()`
         #: yourself every frame.
         #: yourself every frame.
-        self.cTrav = 0
-        self.shadowTrav = 0
+        self.cTrav: CollisionTraverser | Literal[0] = 0
+        self.shadowTrav: CollisionTraverser | Literal[0] = 0
         self.cTravStack = Stack()
         self.cTravStack = Stack()
         # Ditto for an AppTraverser.
         # Ditto for an AppTraverser.
-        self.appTrav = 0
+        self.appTrav: Any | Literal[0] = 0
 
 
         # This is the DataGraph traverser, which we might as well
         # This is the DataGraph traverser, which we might as well
         # create now.
         # create now.
@@ -383,7 +390,7 @@ class ShowBase(DirectObject.DirectObject):
 
 
         # Maybe create a RecorderController to record and/or play back
         # Maybe create a RecorderController to record and/or play back
         # the user session.
         # the user session.
-        self.recorder = None
+        self.recorder: RecorderController | None = None
         playbackSession = ConfigVariableFilename('playback-session', '')
         playbackSession = ConfigVariableFilename('playback-session', '')
         recordSession = ConfigVariableFilename('record-session', '')
         recordSession = ConfigVariableFilename('record-session', '')
         if not playbackSession.empty():
         if not playbackSession.empty():
@@ -448,22 +455,22 @@ class ShowBase(DirectObject.DirectObject):
         #: If `enableParticles()` has been called, this is the particle manager
         #: If `enableParticles()` has been called, this is the particle manager
         #: as imported from :mod:`direct.particles.ParticleManagerGlobal`.
         #: as imported from :mod:`direct.particles.ParticleManagerGlobal`.
         self.particleMgr = None
         self.particleMgr = None
-        self.particleMgrEnabled = 0
+        self.particleMgrEnabled = False
 
 
         #: If `enableParticles()` has been called, this is the physics manager
         #: If `enableParticles()` has been called, this is the physics manager
         #: as imported from :mod:`direct.showbase.PhysicsManagerGlobal`.
         #: as imported from :mod:`direct.showbase.PhysicsManagerGlobal`.
         self.physicsMgr = None
         self.physicsMgr = None
-        self.physicsMgrEnabled = 0
-        self.physicsMgrAngular = 0
+        self.physicsMgrEnabled = False
+        self.physicsMgrAngular = False
 
 
         #: This is the global :class:`~panda3d.core.InputDeviceManager`, which
         #: This is the global :class:`~panda3d.core.InputDeviceManager`, which
         #: keeps track of connected input devices.
         #: keeps track of connected input devices.
         self.devices = InputDeviceManager.getGlobalPtr()
         self.devices = InputDeviceManager.getGlobalPtr()
-        self.__inputDeviceNodes = {}
+        self.__inputDeviceNodes: dict[InputDevice, NodePath] = {}
 
 
         self.createStats()
         self.createStats()
 
 
-        self.AppHasAudioFocus = 1
+        self.AppHasAudioFocus = True
 
 
         # Get a pointer to Panda's global ClockObject, used for
         # Get a pointer to Panda's global ClockObject, used for
         # synchronizing events between Python and C.
         # synchronizing events between Python and C.
@@ -502,7 +509,7 @@ class ShowBase(DirectObject.DirectObject):
                 affinity = ConfigVariableInt('client-cpu-affinity', -1).value
                 affinity = ConfigVariableInt('client-cpu-affinity', -1).value
             if (affinity in (None, -1)) and autoAffinity:
             if (affinity in (None, -1)) and autoAffinity:
                 affinity = 0
                 affinity = 0
-            if affinity not in (None, -1):
+            if affinity is not None and affinity != -1:
                 # Windows XP supports a 32-bit affinity mask
                 # Windows XP supports a 32-bit affinity mask
                 TrueClock.getGlobalPtr().setCpuAffinity(1 << (affinity % 32))
                 TrueClock.getGlobalPtr().setCpuAffinity(1 << (affinity % 32))
 
 
@@ -575,7 +582,7 @@ class ShowBase(DirectObject.DirectObject):
         # Now hang a hook on the window-event from Panda.  This allows
         # Now hang a hook on the window-event from Panda.  This allows
         # us to detect when the user resizes, minimizes, or closes the
         # us to detect when the user resizes, minimizes, or closes the
         # main window.
         # main window.
-        self.__prevWindowProperties = None
+        self.__prevWindowProperties: WindowProperties | None = None
         self.__directObject.accept('window-event', self.windowEvent)
         self.__directObject.accept('window-event', self.windowEvent)
 
 
         # Transition effects (fade, iris, etc)
         # Transition effects (fade, iris, etc)
@@ -658,7 +665,7 @@ class ShowBase(DirectObject.DirectObject):
             #print getDnaPath()
             #print getDnaPath()
             print("}")
             print("}")
 
 
-    def destroy(self):
+    def destroy(self) -> None:
         """ Call this function to destroy the ShowBase and stop all
         """ Call this function to destroy the ShowBase and stop all
         its tasks, freeing all of the Panda resources.  Normally, you
         its tasks, freeing all of the Panda resources.  Normally, you
         should not need to call it explicitly, as it is bound to the
         should not need to call it explicitly, as it is bound to the
@@ -704,6 +711,7 @@ class ShowBase(DirectObject.DirectObject):
         self.shutdown()
         self.shutdown()
 
 
         if getattr(self, 'musicManager', None):
         if getattr(self, 'musicManager', None):
+            assert self.musicManager is not None
             self.musicManager.shutdown()
             self.musicManager.shutdown()
             self.musicManager = None
             self.musicManager = None
             for sfxManager in self.sfxManagerList:
             for sfxManager in self.sfxManagerList:
@@ -711,12 +719,12 @@ class ShowBase(DirectObject.DirectObject):
             self.sfxManagerList = []
             self.sfxManagerList = []
         if getattr(self, 'loader', None):
         if getattr(self, 'loader', None):
             self.loader.destroy()
             self.loader.destroy()
-            self.loader = None
+            del self.loader
         if getattr(self, 'graphicsEngine', None):
         if getattr(self, 'graphicsEngine', None):
             self.graphicsEngine.removeAllWindows()
             self.graphicsEngine.removeAllWindows()
 
 
         try:
         try:
-            self.direct.panel.destroy()
+            self.direct.panel.destroy()  # type: ignore[attr-defined]
         except Exception:
         except Exception:
             pass
             pass
 
 
@@ -1185,7 +1193,7 @@ class ShowBase(DirectObject.DirectObject):
             self.setSceneGraphAnalyzerMeter(flag.value)
             self.setSceneGraphAnalyzerMeter(flag.value)
         return success
         return success
 
 
-    def setSleep(self, amount):
+    def setSleep(self, amount: float) -> None:
         """
         """
         Sets up a task that calls python 'sleep' every frame.  This is a simple
         Sets up a task that calls python 'sleep' every frame.  This is a simple
         way to reduce the CPU usage (and frame rate) of a panda program.
         way to reduce the CPU usage (and frame rate) of a panda program.
@@ -1205,7 +1213,7 @@ class ShowBase(DirectObject.DirectObject):
         #time.sleep(self.clientSleep)
         #time.sleep(self.clientSleep)
         return Task.cont
         return Task.cont
 
 
-    def setFrameRateMeter(self, flag):
+    def setFrameRateMeter(self, flag: bool) -> None:
         """
         """
         Turns on or off (according to flag) a standard frame rate
         Turns on or off (according to flag) a standard frame rate
         meter in the upper-right corner of the main window.
         meter in the upper-right corner of the main window.
@@ -1219,7 +1227,7 @@ class ShowBase(DirectObject.DirectObject):
                 self.frameRateMeter.clearWindow()
                 self.frameRateMeter.clearWindow()
                 self.frameRateMeter = None
                 self.frameRateMeter = None
 
 
-    def setSceneGraphAnalyzerMeter(self, flag):
+    def setSceneGraphAnalyzerMeter(self, flag: bool) -> None:
         """
         """
         Turns on or off (according to flag) a standard frame rate
         Turns on or off (according to flag) a standard frame rate
         meter in the upper-right corner of the main window.
         meter in the upper-right corner of the main window.
@@ -1242,7 +1250,7 @@ class ShowBase(DirectObject.DirectObject):
                 mouseKeyboard = self.dataRoot.find("**/*"))
                 mouseKeyboard = self.dataRoot.find("**/*"))
         self.winControls.append(winCtrl)
         self.winControls.append(winCtrl)
 
 
-    def setupRender(self):
+    def setupRender(self) -> None:
         """
         """
         Creates the render scene graph, the primary scene graph for
         Creates the render scene graph, the primary scene graph for
         rendering 3-d geometry.
         rendering 3-d geometry.
@@ -1252,11 +1260,11 @@ class ShowBase(DirectObject.DirectObject):
         self.render.setAttrib(RescaleNormalAttrib.makeDefault())
         self.render.setAttrib(RescaleNormalAttrib.makeDefault())
 
 
         self.render.setTwoSided(0)
         self.render.setTwoSided(0)
-        self.backfaceCullingEnabled = 1
-        self.textureEnabled = 1
-        self.wireframeEnabled = 0
+        self.backfaceCullingEnabled = True
+        self.textureEnabled = True
+        self.wireframeEnabled = False
 
 
-    def setupRender2d(self):
+    def setupRender2d(self) -> None:
         """
         """
         Creates the render2d scene graph, the primary scene graph for
         Creates the render2d scene graph, the primary scene graph for
         2-d objects and gui elements that are superimposed over the
         2-d objects and gui elements that are superimposed over the
@@ -1355,7 +1363,7 @@ class ShowBase(DirectObject.DirectObject):
         if xsize > 0 and ysize > 0:
         if xsize > 0 and ysize > 0:
             self.pixel2d.setScale(2.0 / xsize, 1.0, 2.0 / ysize)
             self.pixel2d.setScale(2.0 / xsize, 1.0, 2.0 / ysize)
 
 
-    def setupRender2dp(self):
+    def setupRender2dp(self) -> None:
         """
         """
         Creates a render2d scene graph, the secondary scene graph for
         Creates a render2d scene graph, the secondary scene graph for
         2-d objects and gui elements that are superimposed over the
         2-d objects and gui elements that are superimposed over the
@@ -1677,7 +1685,7 @@ class ShowBase(DirectObject.DirectObject):
 
 
         return camera2dp
         return camera2dp
 
 
-    def setupDataGraph(self):
+    def setupDataGraph(self) -> None:
         """
         """
         Creates the data graph and populates it with the basic input
         Creates the data graph and populates it with the basic input
         devices.
         devices.
@@ -2006,7 +2014,7 @@ class ShowBase(DirectObject.DirectObject):
             self.physicsMgr.doPhysics(dt)
             self.physicsMgr.doPhysics(dt)
         return Task.cont
         return Task.cont
 
 
-    def createStats(self, hostname=None, port=None):
+    def createStats(self, hostname: str | None = None, port: int | None = None) -> bool:
         """
         """
         If want-pstats is set in Config.prc, or the `wantStats` member is
         If want-pstats is set in Config.prc, or the `wantStats` member is
         otherwise set to True, connects to the PStats server.
         otherwise set to True, connects to the PStats server.
@@ -2323,7 +2331,7 @@ class ShowBase(DirectObject.DirectObject):
         throw_new_frame()
         throw_new_frame()
         return Task.cont
         return Task.cont
 
 
-    def restart(self, clusterSync=False, cluster=None):
+    def restart(self, clusterSync: bool = False, cluster=None) -> None:
         self.shutdown()
         self.shutdown()
         # __resetPrevTransform goes at the very beginning of the frame.
         # __resetPrevTransform goes at the very beginning of the frame.
         self.taskMgr.add(
         self.taskMgr.add(
@@ -2354,7 +2362,7 @@ class ShowBase(DirectObject.DirectObject):
         self.taskMgr.add(self.__audioLoop, 'audioLoop', sort = 60)
         self.taskMgr.add(self.__audioLoop, 'audioLoop', sort = 60)
         self.eventMgr.restart()
         self.eventMgr.restart()
 
 
-    def shutdown(self):
+    def shutdown(self) -> None:
         self.taskMgr.remove('audioLoop')
         self.taskMgr.remove('audioLoop')
         self.taskMgr.remove('igLoop')
         self.taskMgr.remove('igLoop')
         self.taskMgr.remove('shadowCollisionLoop')
         self.taskMgr.remove('shadowCollisionLoop')
@@ -3195,14 +3203,14 @@ class ShowBase(DirectObject.DirectObject):
             # If anybody needs to update their GUI, put a callback on this event
             # If anybody needs to update their GUI, put a callback on this event
             messenger.send("aspectRatioChanged")
             messenger.send("aspectRatioChanged")
 
 
-    def userExit(self):
+    def userExit(self) -> NoReturn:
         # The user has requested we exit the program.  Deal with this.
         # The user has requested we exit the program.  Deal with this.
         if self.exitFunc:
         if self.exitFunc:
             self.exitFunc()
             self.exitFunc()
         self.notify.info("Exiting ShowBase.")
         self.notify.info("Exiting ShowBase.")
         self.finalizeExit()
         self.finalizeExit()
 
 
-    def finalizeExit(self):
+    def finalizeExit(self) -> NoReturn:
         """
         """
         Called by `userExit()` to quit the application.  The default
         Called by `userExit()` to quit the application.  The default
         implementation just calls `sys.exit()`.
         implementation just calls `sys.exit()`.