direct: Get direct to pass a mypy check

Closes #1476
This commit is contained in:
WMOkiishi 2023-08-04 14:31:11 +02:00 committed by rdb
parent ab93d88f1b
commit 32edfa43fd
44 changed files with 352 additions and 244 deletions

23
.github/workflows/mypy.yml vendored Normal file
View File

@ -0,0 +1,23 @@
name: Run Mypy
on: [push, pull_request]
jobs:
mypy:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.8', '3.11']
fail-fast: false
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install mypy==1.4.0
- name: Run mypy on direct
run: python tests/run_mypy.py

View File

@ -15,7 +15,7 @@ to and may be replaced by the following code:
base = ShowBase()
"""
__all__ = []
__all__ = ()
if __debug__:
print('Using deprecated DirectStart interface.')

View File

@ -6,7 +6,7 @@ from direct.showbase import ShowBase
base = ShowBase.ShowBase()
# Put an axis in the world:
base.loader.loadModel("models/misc/xyzAxis").reparentTo(render)
base.loader.loadModel("models/misc/xyzAxis").reparentTo(base.render)
base.camera.setPosHpr(0, -10.0, 0, 0, 0, 0)
base.camLens.setFov(52.0)

View File

@ -8,7 +8,7 @@ from direct.showbase import ThreeUpShow
base = ThreeUpShow.ThreeUpShow()
# Put an axis in the world:
base.loader.loadModel("models/misc/xyzAxis").reparentTo(render)
base.loader.loadModel("models/misc/xyzAxis").reparentTo(base.render)
base.camera.setPosHpr(0, -10.0, 0, 0, 0, 0)
base.camLens.setFov(52.0)

View File

@ -41,8 +41,12 @@ class DirectJoybox(DirectObject):
xyzMultiplier = 1.0
hprMultiplier = 1.0
def __init__(self, device = 'CerealBox', nodePath = base.direct.camera,
headingNP = base.direct.camera):
def __init__(self, device = 'CerealBox', nodePath = None, headingNP = None):
from direct.showbase.ShowBaseGlobal import base
if nodePath is None:
nodePath = base.direct.camera
if headingNP is None:
headingNP = base.direct.camera
# See if device manager has been initialized
if base.direct.deviceManager is None:
base.direct.deviceManager = DirectDeviceManager()

View File

@ -1,3 +1,5 @@
from __future__ import annotations
#from otp.ai.AIBaseGlobal import *
from direct.directnotify import DirectNotifyGlobal
from direct.showbase.DirectObject import DirectObject
@ -39,7 +41,7 @@ class AsyncRequest(DirectObject):
will be called again when the new self.neededObjects is complete. You
may repeat this as necessary.
"""
_asyncRequests = {}
_asyncRequests: dict[int, AsyncRequest] = {}
notify = DirectNotifyGlobal.directNotify.newCategory('AsyncRequest')

View File

@ -20,3 +20,10 @@ class CachedDOData:
# override and destroy the cached data
# cached data is typically created by the DistributedObject and destroyed here
pass
# These next two methods tell mypy to allow arbitrary attributes.
def __getattribute__(self, name: str):
return object.__getattribute__(self, name)
def __setattr__(self, name: str, value) -> None:
object.__setattr__(self, name, value)

View File

@ -299,7 +299,7 @@ class DistributedObjectAI(DistributedObjectBase):
# setLocation destroys self._zoneData if we move away to
# a different zone
if self._zoneData is None:
from otp.ai.AIZoneData import AIZoneData
from otp.ai.AIZoneData import AIZoneData # type: ignore[import]
self._zoneData = AIZoneData(self.air, self.parentId, self.zoneId)
return self._zoneData
@ -489,7 +489,7 @@ class DistributedObjectAI(DistributedObjectBase):
# simultaneously on different lists of avatars, although they
# should have different names.
from otp.ai import Barrier
from otp.ai import Barrier # type: ignore[import]
context = self.__nextBarrierContext
# We assume the context number is passed as a uint16.
self.__nextBarrierContext = (self.__nextBarrierContext + 1) & 0xffff

View File

@ -424,7 +424,7 @@ class DistributedObjectUD(DistributedObjectBase):
# simultaneously on different lists of avatars, although they
# should have different names.
from otp.ai import Barrier
from otp.ai import Barrier # type: ignore[import]
context = self.__nextBarrierContext
# We assume the context number is passed as a uint16.
self.__nextBarrierContext = (self.__nextBarrierContext + 1) & 0xffff

View File

@ -7,6 +7,8 @@ zone, remove interest in that zone.
p.s. A great deal of this code is just code moved from ClientRepository.py.
"""
from __future__ import annotations
from panda3d.core import ConfigVariableBool
from .MsgTypes import CLIENT_ADD_INTEREST, CLIENT_ADD_INTEREST_MULTIPLE, CLIENT_REMOVE_INTEREST
from direct.showbase import DirectObject
@ -98,9 +100,9 @@ class DoInterestManager(DirectObject.DirectObject):
_ContextIdSerialNum = 100
_ContextIdMask = 0x3FFFFFFF # avoid making Python create a long
_interests = {}
_interests: dict[int, InterestState] = {}
if __debug__:
_debug_interestHistory = []
_debug_interestHistory: list[tuple] = []
_debug_maxDescriptionLen = 40
_SerialGen = SerialNumGen()

View File

@ -1,3 +1,5 @@
from __future__ import annotations
from panda3d.core import NodePath
#
@ -13,8 +15,8 @@ from panda3d.core import NodePath
class GridParent:
# this lets GridParents share CellOrigins
GridZone2CellOrigin = {}
GridZone2count = {}
GridZone2CellOrigin: dict[tuple, NodePath] = {}
GridZone2count: dict[tuple, int] = {}
@staticmethod
def getCellOrigin(grid, zoneId):
tup = (grid, zoneId)

View File

@ -1,143 +1,145 @@
"""MsgTypes module: contains distributed object message types"""
from __future__ import annotations
from direct.showbase.PythonUtil import invertDictLossless
MsgName2Id = {
'CLIENT_HELLO': 1,
'CLIENT_HELLO_RESP': 2,
CLIENT_HELLO = 1
CLIENT_HELLO_RESP = 2
# Sent by the client when it's leaving.
'CLIENT_DISCONNECT': 3,
# Sent by the client when it's leaving.
CLIENT_DISCONNECT = 3
# Sent by the server when it is dropping the connection deliberately.
'CLIENT_EJECT': 4,
# Sent by the server when it is dropping the connection deliberately.
CLIENT_EJECT = 4
'CLIENT_HEARTBEAT': 5,
CLIENT_HEARTBEAT = 5
'CLIENT_OBJECT_SET_FIELD': 120,
'CLIENT_OBJECT_SET_FIELDS': 121,
'CLIENT_OBJECT_LEAVING': 132,
'CLIENT_OBJECT_LEAVING_OWNER': 161,
'CLIENT_ENTER_OBJECT_REQUIRED': 142,
'CLIENT_ENTER_OBJECT_REQUIRED_OTHER': 143,
'CLIENT_ENTER_OBJECT_REQUIRED_OWNER': 172,
'CLIENT_ENTER_OBJECT_REQUIRED_OTHER_OWNER': 173,
CLIENT_OBJECT_SET_FIELD = 120
CLIENT_OBJECT_SET_FIELDS = 121
CLIENT_OBJECT_LEAVING = 132
CLIENT_OBJECT_LEAVING_OWNER = 161
CLIENT_ENTER_OBJECT_REQUIRED = 142
CLIENT_ENTER_OBJECT_REQUIRED_OTHER = 143
CLIENT_ENTER_OBJECT_REQUIRED_OWNER = 172
CLIENT_ENTER_OBJECT_REQUIRED_OTHER_OWNER = 173
'CLIENT_DONE_INTEREST_RESP': 204,
CLIENT_DONE_INTEREST_RESP = 204
'CLIENT_ADD_INTEREST': 200,
'CLIENT_ADD_INTEREST_MULTIPLE': 201,
'CLIENT_REMOVE_INTEREST': 203,
'CLIENT_OBJECT_LOCATION': 140,
CLIENT_ADD_INTEREST = 200
CLIENT_ADD_INTEREST_MULTIPLE = 201
CLIENT_REMOVE_INTEREST = 203
CLIENT_OBJECT_LOCATION = 140
# These are sent internally inside the Astron cluster.
# These are sent internally inside the Astron cluster.
# Message Director control messages:
'CONTROL_CHANNEL': 1,
'CONTROL_ADD_CHANNEL': 9000,
'CONTROL_REMOVE_CHANNEL': 9001,
'CONTROL_ADD_RANGE': 9002,
'CONTROL_REMOVE_RANGE': 9003,
'CONTROL_ADD_POST_REMOVE': 9010,
'CONTROL_CLEAR_POST_REMOVES': 9011,
# Message Director control messages:
CONTROL_CHANNEL = 1
CONTROL_ADD_CHANNEL = 9000
CONTROL_REMOVE_CHANNEL = 9001
CONTROL_ADD_RANGE = 9002
CONTROL_REMOVE_RANGE = 9003
CONTROL_ADD_POST_REMOVE = 9010
CONTROL_CLEAR_POST_REMOVES = 9011
# State Server control messages:
'STATESERVER_CREATE_OBJECT_WITH_REQUIRED': 2000,
'STATESERVER_CREATE_OBJECT_WITH_REQUIRED_OTHER': 2001,
'STATESERVER_DELETE_AI_OBJECTS': 2009,
'STATESERVER_OBJECT_GET_FIELD': 2010,
'STATESERVER_OBJECT_GET_FIELD_RESP': 2011,
'STATESERVER_OBJECT_GET_FIELDS': 2012,
'STATESERVER_OBJECT_GET_FIELDS_RESP': 2013,
'STATESERVER_OBJECT_GET_ALL': 2014,
'STATESERVER_OBJECT_GET_ALL_RESP': 2015,
'STATESERVER_OBJECT_SET_FIELD': 2020,
'STATESERVER_OBJECT_SET_FIELDS': 2021,
'STATESERVER_OBJECT_DELETE_FIELD_RAM': 2030,
'STATESERVER_OBJECT_DELETE_FIELDS_RAM': 2031,
'STATESERVER_OBJECT_DELETE_RAM': 2032,
'STATESERVER_OBJECT_SET_LOCATION': 2040,
'STATESERVER_OBJECT_CHANGING_LOCATION': 2041,
'STATESERVER_OBJECT_ENTER_LOCATION_WITH_REQUIRED': 2042,
'STATESERVER_OBJECT_ENTER_LOCATION_WITH_REQUIRED_OTHER': 2043,
'STATESERVER_OBJECT_GET_LOCATION': 2044,
'STATESERVER_OBJECT_GET_LOCATION_RESP': 2045,
'STATESERVER_OBJECT_SET_AI': 2050,
'STATESERVER_OBJECT_CHANGING_AI': 2051,
'STATESERVER_OBJECT_ENTER_AI_WITH_REQUIRED': 2052,
'STATESERVER_OBJECT_ENTER_AI_WITH_REQUIRED_OTHER': 2053,
'STATESERVER_OBJECT_GET_AI': 2054,
'STATESERVER_OBJECT_GET_AI_RESP': 2055,
'STATESERVER_OBJECT_SET_OWNER': 2060,
'STATESERVER_OBJECT_CHANGING_OWNER': 2061,
'STATESERVER_OBJECT_ENTER_OWNER_WITH_REQUIRED': 2062,
'STATESERVER_OBJECT_ENTER_OWNER_WITH_REQUIRED_OTHER': 2063,
'STATESERVER_OBJECT_GET_OWNER': 2064,
'STATESERVER_OBJECT_GET_OWNER_RESP': 2065,
'STATESERVER_OBJECT_GET_ZONE_OBJECTS': 2100,
'STATESERVER_OBJECT_GET_ZONES_OBJECTS': 2102,
'STATESERVER_OBJECT_GET_CHILDREN': 2104,
'STATESERVER_OBJECT_GET_ZONE_COUNT': 2110,
'STATESERVER_OBJECT_GET_ZONE_COUNT_RESP': 2111,
'STATESERVER_OBJECT_GET_ZONES_COUNT': 2112,
'STATESERVER_OBJECT_GET_ZONES_COUNT_RESP': 2113,
'STATESERVER_OBJECT_GET_CHILD_COUNT': 2114,
'STATESERVER_OBJECT_GET_CHILD_COUNT_RESP': 2115,
'STATESERVER_OBJECT_DELETE_ZONE': 2120,
'STATESERVER_OBJECT_DELETE_ZONES': 2122,
'STATESERVER_OBJECT_DELETE_CHILDREN': 2124,
# DBSS-backed-object messages:
'DBSS_OBJECT_ACTIVATE_WITH_DEFAULTS': 2200,
'DBSS_OBJECT_ACTIVATE_WITH_DEFAULTS_OTHER': 2201,
'DBSS_OBJECT_GET_ACTIVATED': 2207,
'DBSS_OBJECT_GET_ACTIVATED_RESP': 2208,
'DBSS_OBJECT_DELETE_FIELD_DISK': 2230,
'DBSS_OBJECT_DELETE_FIELDS_DISK': 2231,
'DBSS_OBJECT_DELETE_DISK': 2232,
# State Server control messages:
STATESERVER_CREATE_OBJECT_WITH_REQUIRED = 2000
STATESERVER_CREATE_OBJECT_WITH_REQUIRED_OTHER = 2001
STATESERVER_DELETE_AI_OBJECTS = 2009
STATESERVER_OBJECT_GET_FIELD = 2010
STATESERVER_OBJECT_GET_FIELD_RESP = 2011
STATESERVER_OBJECT_GET_FIELDS = 2012
STATESERVER_OBJECT_GET_FIELDS_RESP = 2013
STATESERVER_OBJECT_GET_ALL = 2014
STATESERVER_OBJECT_GET_ALL_RESP = 2015
STATESERVER_OBJECT_SET_FIELD = 2020
STATESERVER_OBJECT_SET_FIELDS = 2021
STATESERVER_OBJECT_DELETE_FIELD_RAM = 2030
STATESERVER_OBJECT_DELETE_FIELDS_RAM = 2031
STATESERVER_OBJECT_DELETE_RAM = 2032
STATESERVER_OBJECT_SET_LOCATION = 2040
STATESERVER_OBJECT_CHANGING_LOCATION = 2041
STATESERVER_OBJECT_ENTER_LOCATION_WITH_REQUIRED = 2042
STATESERVER_OBJECT_ENTER_LOCATION_WITH_REQUIRED_OTHER = 2043
STATESERVER_OBJECT_GET_LOCATION = 2044
STATESERVER_OBJECT_GET_LOCATION_RESP = 2045
STATESERVER_OBJECT_SET_AI = 2050
STATESERVER_OBJECT_CHANGING_AI = 2051
STATESERVER_OBJECT_ENTER_AI_WITH_REQUIRED = 2052
STATESERVER_OBJECT_ENTER_AI_WITH_REQUIRED_OTHER = 2053
STATESERVER_OBJECT_GET_AI = 2054
STATESERVER_OBJECT_GET_AI_RESP = 2055
STATESERVER_OBJECT_SET_OWNER = 2060
STATESERVER_OBJECT_CHANGING_OWNER = 2061
STATESERVER_OBJECT_ENTER_OWNER_WITH_REQUIRED = 2062
STATESERVER_OBJECT_ENTER_OWNER_WITH_REQUIRED_OTHER = 2063
STATESERVER_OBJECT_GET_OWNER = 2064
STATESERVER_OBJECT_GET_OWNER_RESP = 2065
STATESERVER_OBJECT_GET_ZONE_OBJECTS = 2100
STATESERVER_OBJECT_GET_ZONES_OBJECTS = 2102
STATESERVER_OBJECT_GET_CHILDREN = 2104
STATESERVER_OBJECT_GET_ZONE_COUNT = 2110
STATESERVER_OBJECT_GET_ZONE_COUNT_RESP = 2111
STATESERVER_OBJECT_GET_ZONES_COUNT = 2112
STATESERVER_OBJECT_GET_ZONES_COUNT_RESP = 2113
STATESERVER_OBJECT_GET_CHILD_COUNT = 2114
STATESERVER_OBJECT_GET_CHILD_COUNT_RESP = 2115
STATESERVER_OBJECT_DELETE_ZONE = 2120
STATESERVER_OBJECT_DELETE_ZONES = 2122
STATESERVER_OBJECT_DELETE_CHILDREN = 2124
# DBSS-backed-object messages:
DBSS_OBJECT_ACTIVATE_WITH_DEFAULTS = 2200
DBSS_OBJECT_ACTIVATE_WITH_DEFAULTS_OTHER = 2201
DBSS_OBJECT_GET_ACTIVATED = 2207
DBSS_OBJECT_GET_ACTIVATED_RESP = 2208
DBSS_OBJECT_DELETE_FIELD_DISK = 2230
DBSS_OBJECT_DELETE_FIELDS_DISK = 2231
DBSS_OBJECT_DELETE_DISK = 2232
# Database Server control messages:
'DBSERVER_CREATE_OBJECT': 3000,
'DBSERVER_CREATE_OBJECT_RESP': 3001,
'DBSERVER_OBJECT_GET_FIELD': 3010,
'DBSERVER_OBJECT_GET_FIELD_RESP': 3011,
'DBSERVER_OBJECT_GET_FIELDS': 3012,
'DBSERVER_OBJECT_GET_FIELDS_RESP': 3013,
'DBSERVER_OBJECT_GET_ALL': 3014,
'DBSERVER_OBJECT_GET_ALL_RESP': 3015,
'DBSERVER_OBJECT_SET_FIELD': 3020,
'DBSERVER_OBJECT_SET_FIELDS': 3021,
'DBSERVER_OBJECT_SET_FIELD_IF_EQUALS': 3022,
'DBSERVER_OBJECT_SET_FIELD_IF_EQUALS_RESP': 3023,
'DBSERVER_OBJECT_SET_FIELDS_IF_EQUALS': 3024,
'DBSERVER_OBJECT_SET_FIELDS_IF_EQUALS_RESP': 3025,
'DBSERVER_OBJECT_SET_FIELD_IF_EMPTY': 3026,
'DBSERVER_OBJECT_SET_FIELD_IF_EMPTY_RESP': 3027,
'DBSERVER_OBJECT_DELETE_FIELD': 3030,
'DBSERVER_OBJECT_DELETE_FIELDS': 3031,
'DBSERVER_OBJECT_DELETE': 3032,
# Database Server control messages:
DBSERVER_CREATE_OBJECT = 3000
DBSERVER_CREATE_OBJECT_RESP = 3001
DBSERVER_OBJECT_GET_FIELD = 3010
DBSERVER_OBJECT_GET_FIELD_RESP = 3011
DBSERVER_OBJECT_GET_FIELDS = 3012
DBSERVER_OBJECT_GET_FIELDS_RESP = 3013
DBSERVER_OBJECT_GET_ALL = 3014
DBSERVER_OBJECT_GET_ALL_RESP = 3015
DBSERVER_OBJECT_SET_FIELD = 3020
DBSERVER_OBJECT_SET_FIELDS = 3021
DBSERVER_OBJECT_SET_FIELD_IF_EQUALS = 3022
DBSERVER_OBJECT_SET_FIELD_IF_EQUALS_RESP = 3023
DBSERVER_OBJECT_SET_FIELDS_IF_EQUALS = 3024
DBSERVER_OBJECT_SET_FIELDS_IF_EQUALS_RESP = 3025
DBSERVER_OBJECT_SET_FIELD_IF_EMPTY = 3026
DBSERVER_OBJECT_SET_FIELD_IF_EMPTY_RESP = 3027
DBSERVER_OBJECT_DELETE_FIELD = 3030
DBSERVER_OBJECT_DELETE_FIELDS = 3031
DBSERVER_OBJECT_DELETE = 3032
# Client Agent control messages:
'CLIENTAGENT_SET_STATE': 1000,
'CLIENTAGENT_SET_CLIENT_ID': 1001,
'CLIENTAGENT_SEND_DATAGRAM': 1002,
'CLIENTAGENT_EJECT': 1004,
'CLIENTAGENT_DROP': 1005,
'CLIENTAGENT_GET_NETWORK_ADDRESS': 1006,
'CLIENTAGENT_GET_NETWORK_ADDRESS_RESP': 1007,
'CLIENTAGENT_DECLARE_OBJECT': 1010,
'CLIENTAGENT_UNDECLARE_OBJECT': 1011,
'CLIENTAGENT_ADD_SESSION_OBJECT': 1012,
'CLIENTAGENT_REMOVE_SESSION_OBJECT': 1013,
'CLIENTAGENT_SET_FIELDS_SENDABLE': 1014,
'CLIENTAGENT_OPEN_CHANNEL': 1100,
'CLIENTAGENT_CLOSE_CHANNEL': 1101,
'CLIENTAGENT_ADD_POST_REMOVE': 1110,
'CLIENTAGENT_CLEAR_POST_REMOVES': 1111,
'CLIENTAGENT_ADD_INTEREST': 1200,
'CLIENTAGENT_ADD_INTEREST_MULTIPLE': 1201,
'CLIENTAGENT_REMOVE_INTEREST': 1203,
}
# Client Agent control messages:
CLIENTAGENT_SET_STATE = 1000
CLIENTAGENT_SET_CLIENT_ID = 1001
CLIENTAGENT_SEND_DATAGRAM = 1002
CLIENTAGENT_EJECT = 1004
CLIENTAGENT_DROP = 1005
CLIENTAGENT_GET_NETWORK_ADDRESS = 1006
CLIENTAGENT_GET_NETWORK_ADDRESS_RESP = 1007
CLIENTAGENT_DECLARE_OBJECT = 1010
CLIENTAGENT_UNDECLARE_OBJECT = 1011
CLIENTAGENT_ADD_SESSION_OBJECT = 1012
CLIENTAGENT_REMOVE_SESSION_OBJECT = 1013
CLIENTAGENT_SET_FIELDS_SENDABLE = 1014
CLIENTAGENT_OPEN_CHANNEL = 1100
CLIENTAGENT_CLOSE_CHANNEL = 1101
CLIENTAGENT_ADD_POST_REMOVE = 1110
CLIENTAGENT_CLEAR_POST_REMOVES = 1111
CLIENTAGENT_ADD_INTEREST = 1200
CLIENTAGENT_ADD_INTEREST_MULTIPLE = 1201
CLIENTAGENT_REMOVE_INTEREST = 1203
MsgName2Id = {name: value for name, value in globals().items() if isinstance(value, int)}
# create id->name table for debugging
MsgId2Names = invertDictLossless(MsgName2Id)
@ -146,7 +148,7 @@ MsgId2Names = invertDictLossless(MsgName2Id)
globals().update(MsgName2Id)
# These messages are ignored when the client is headed to the quiet zone
QUIET_ZONE_IGNORED_LIST = [
QUIET_ZONE_IGNORED_LIST: list[int] = [
# We mustn't ignore updates, because some updates for localToon
# are always important.

View File

@ -5,25 +5,22 @@ implementation. """
from direct.showbase.PythonUtil import invertDictLossless
MsgName2Id = {
'SET_DOID_RANGE_CMU' : 9001,
'CLIENT_OBJECT_GENERATE_CMU' : 9002,
'OBJECT_GENERATE_CMU' : 9003,
'OBJECT_UPDATE_FIELD_CMU' : 9004,
'OBJECT_DISABLE_CMU' : 9005,
'OBJECT_DELETE_CMU' : 9006,
'REQUEST_GENERATES_CMU' : 9007,
'CLIENT_DISCONNECT_CMU' : 9008,
'CLIENT_SET_INTEREST_CMU' : 9009,
'OBJECT_SET_ZONE_CMU' : 9010,
'CLIENT_HEARTBEAT_CMU' : 9011,
'CLIENT_OBJECT_UPDATE_FIELD_TARGETED_CMU' : 9011,
SET_DOID_RANGE_CMU = 9001
CLIENT_OBJECT_GENERATE_CMU = 9002
OBJECT_GENERATE_CMU = 9003
OBJECT_UPDATE_FIELD_CMU = 9004
OBJECT_DISABLE_CMU = 9005
OBJECT_DELETE_CMU = 9006
REQUEST_GENERATES_CMU = 9007
CLIENT_DISCONNECT_CMU = 9008
CLIENT_SET_INTEREST_CMU = 9009
OBJECT_SET_ZONE_CMU = 9010
CLIENT_HEARTBEAT_CMU = 9011
CLIENT_OBJECT_UPDATE_FIELD_TARGETED_CMU = 9011
'CLIENT_OBJECT_UPDATE_FIELD' : 120, # Matches MsgTypes.CLIENT_OBJECT_SET_FIELD
}
CLIENT_OBJECT_UPDATE_FIELD = 120 # Matches MsgTypes.CLIENT_OBJECT_SET_FIELD
MsgName2Id = {name: value for name, value in globals().items() if isinstance(value, int)}
# create id->name table for debugging
MsgId2Names = invertDictLossless(MsgName2Id)
# put msg names in module scope, assigned to msg value
globals().update(MsgName2Id)

View File

@ -5,6 +5,8 @@ Note:
existing code. New code should use the :mod:`.FSM` module instead.
"""
from __future__ import annotations
__all__ = ['ClassicFSM']
from direct.directnotify.DirectNotifyGlobal import directNotify
@ -13,7 +15,7 @@ from direct.showbase.MessengerGlobal import messenger
import weakref
if __debug__:
_debugFsms = {}
_debugFsms: dict[str, weakref.ref] = {}
def printDebugFsmList():
for k in sorted(_debugFsms.keys()):

View File

@ -1,5 +1,7 @@
"""State module: contains State class"""
from __future__ import annotations
__all__ = ['State']
from direct.directnotify.DirectNotifyGlobal import directNotify
@ -18,7 +20,7 @@ class State(DirectObject):
# should not cause any leaks.
if __debug__:
import weakref
States = weakref.WeakKeyDictionary()
States: weakref.WeakKeyDictionary[State, int] = weakref.WeakKeyDictionary()
@classmethod
def replaceMethod(cls, oldFunction, newFunction):

View File

@ -1,6 +1,8 @@
# classes for event-driven programming
# http://en.wikipedia.org/wiki/Event-driven_programming
from __future__ import annotations
__all__ = ['StateVar', 'FunctionCall', 'EnterExit', 'Pulse', 'EventPulse',
'EventArgument', ]

View File

@ -4,6 +4,8 @@ See the :ref:`directdialog` page in the programming manual for a more
in-depth explanation and an example of how to use this class.
"""
from __future__ import annotations
__all__ = [
'findDialog', 'cleanupDialog', 'DirectDialog', 'OkDialog',
'OkCancelDialog', 'YesNoDialog', 'YesNoCancelDialog', 'RetryCancelDialog',
@ -45,7 +47,7 @@ def cleanupDialog(uniqueName):
class DirectDialog(DirectFrame):
AllDialogs = {}
AllDialogs: dict[str, DirectDialog] = {}
PanelIndex = 0
def __init__(self, parent=None, **kw):

View File

@ -84,6 +84,8 @@ Code overview:
see if any keywords are left unused. If so, an error is raised.
"""
from __future__ import annotations
__all__ = ['DirectGuiBase', 'DirectGuiWidget']
@ -680,7 +682,7 @@ class DirectGuiWidget(DirectGuiBase, NodePath):
else:
inactiveInitState = DGG.DISABLED
guiDict = {}
guiDict: dict[str, DirectGuiWidget] = {}
def __init__(self, parent = None, **kw):
# Direct gui widgets are node paths

View File

@ -3,7 +3,7 @@ Global definitions used by Direct Gui Classes and handy constants
that can be used during widget construction
"""
__all__ = []
__all__ = ()
from panda3d.core import (
KeyboardButton,

View File

@ -1,5 +1,7 @@
"""FunctionInterval module: contains the FunctionInterval class"""
from __future__ import annotations
__all__ = ['FunctionInterval', 'EventInterval', 'AcceptInterval', 'IgnoreInterval', 'ParentInterval', 'WrtParentInterval', 'PosInterval', 'HprInterval', 'ScaleInterval', 'PosHprInterval', 'HprScaleInterval', 'PosHprScaleInterval', 'Func', 'Wait']
from panda3d.direct import WaitInterval
@ -23,7 +25,7 @@ class FunctionInterval(Interval.Interval):
# should not cause any leaks.
if __debug__:
import weakref
FunctionIntervals = weakref.WeakKeyDictionary()
FunctionIntervals: weakref.WeakKeyDictionary[FunctionInterval, int] = weakref.WeakKeyDictionary()
@classmethod
def replaceMethod(cls, oldFunction, newFunction):

View File

@ -1,6 +1,6 @@
"""Undocumented Module"""
__all__ = []
__all__ = ()
if __name__ == "__main__":
@ -26,7 +26,7 @@ if __name__ == "__main__":
base = ShowBase()
boat = base.loader.loadModel('models/misc/smiley')
boat.reparentTo(render)
boat.reparentTo(base.render)
donald = Actor()
donald.loadModel("phase_6/models/char/donald-wheel-1000")
@ -34,7 +34,7 @@ if __name__ == "__main__":
donald.reparentTo(boat)
dock = base.loader.loadModel('models/misc/smiley')
dock.reparentTo(render)
dock.reparentTo(base.render)
sound = base.loader.loadSfx('phase_6/audio/sfx/SZ_DD_waterlap.mp3')
foghorn = base.loader.loadSfx('phase_6/audio/sfx/SZ_DD_foghorn.mp3')
@ -93,7 +93,7 @@ if __name__ == "__main__":
foghornSound = SoundInterval(foghorn, name='foghorn')
soundTrack2 = Track([(foghornStartTime, foghornSound)], 'soundtrack2')
mtrack = MultiTrack([boatTrack, dockTrack, soundTrack, soundTrack2, waterEventTrack,
mtrack = MultiTrack([boatTrack, dockTrack, soundTrack, soundTrack2, waterEventTrack, # type: ignore[name-defined]
donaldSteerTrack])
# Print out MultiTrack parameters
print(mtrack)
@ -175,11 +175,11 @@ if __name__ == "__main__":
# Just to take time
i2 = LerpPosInterval(base.camera, 2.0, Point3(0, 10, 5))
# This will be relative to end of camera move
i3 = FunctionInterval(printPreviousEnd)
i3 = FunctionInterval(printPreviousEnd) # type: ignore[assignment]
# Just to take time
i4 = LerpPosInterval(base.camera, 2.0, Point3(0, 0, 5))
# This will be relative to the start of the camera move
i5 = FunctionInterval(printPreviousStart)
i5 = FunctionInterval(printPreviousStart) # type: ignore[assignment]
# This will be relative to track start
i6 = FunctionInterval(printTrackStart)
# This will print some arguments

View File

@ -4,7 +4,7 @@ if __name__ == '__main__':
from direct.showbase.ShowBase import ShowBase
base = ShowBase()
base.le = LevelEditor.LevelEditor()
base.le = LevelEditor.LevelEditor() # type: ignore[attr-defined]
# You should define LevelEditor instance as
# base.le so it can be reached in global scope

View File

@ -1,4 +1,5 @@
from panda3d.core import Point3, VBase3
from direct.showbase.ShowBaseGlobal import base
if hasattr(base, 'le'):
objectMgr = base.le.objectMgr
@ -6,7 +7,7 @@ if hasattr(base, 'le'):
ui.sceneGraphUI.reset()
else:
objectMgr = base.objectMgr
objectMgr = base.objectMgr # type: ignore[attr-defined]
# temporary place holder for nodepath
objects = {}

View File

@ -1,3 +1,5 @@
from __future__ import annotations
from panda3d.core import (
BoundingVolume,
ColorBlendAttrib,
@ -92,7 +94,7 @@ class MotionTrail(NodePath, DirectObject):
notify = directNotify.newCategory("MotionTrail")
task_added = False
motion_trail_list = []
motion_trail_list: list[MotionTrail] = []
motion_trail_task_name = "motion_trail_task"
global_enable = True

View File

@ -1,3 +1,5 @@
from __future__ import annotations
from direct.directnotify.DirectNotifyGlobal import directNotify
import direct.showbase.DConfig as config
from direct.showbase.PythonUtil import makeFlywheelGen, flywheel
@ -982,7 +984,7 @@ class ContainerLeakDetector(Job):
"""
notify = directNotify.newCategory("ContainerLeakDetector")
# set of containers that should not be examined
PrivateIds = set()
PrivateIds: set[int] = set()
def __init__(self, name, firstCheckDelay = None):
Job.__init__(self, name)

View File

@ -1,3 +1,5 @@
from __future__ import annotations
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.showbase.PythonUtil import Queue, invertDictLossless
from direct.showbase.PythonUtil import safeRepr
@ -11,7 +13,7 @@ import io
class ContainerReport(Job):
notify = directNotify.newCategory("ContainerReport")
# set of containers that should not be included in the report
PrivateIds = set()
PrivateIds: set[int] = set()
def __init__(self, name, log=False, limit=None, threaded=False):
Job.__init__(self, name)

View File

@ -1,6 +1,6 @@
"This module contains a deprecated shim emulating the old DConfig API."
__all__ = []
__all__ = ()
from panda3d.core import (ConfigFlags, ConfigVariableBool, ConfigVariableInt,
ConfigVariableDouble, ConfigVariableString)

View File

@ -1,3 +1,5 @@
from __future__ import annotations
from direct.showbase.DirectObject import DirectObject
from direct.directnotify.DirectNotifyGlobal import directNotify
from panda3d.core import (
@ -62,7 +64,7 @@ class DistancePhasedNode(PhasedObject, DirectObject, NodePath):
notify = directNotify.newCategory("DistancePhasedObject")
__InstanceSequence = 0
__InstanceDeque = []
__InstanceDeque: list[int] = []
@staticmethod
def __allocateId():

View File

@ -69,7 +69,7 @@ oldExcepthook = None
# from its main exception handler
wantStackDumpLog = False
wantStackDumpUpload = False
variableDumpReasons = []
variableDumpReasons: list = []
dumpOnExceptionInit = False

View File

@ -11,6 +11,8 @@
>>> o.diff(o2)
"""
from __future__ import annotations
__all__ = ['ExclusiveObjectPool', 'ObjectReport']
from direct.directnotify.DirectNotifyGlobal import directNotify
@ -26,8 +28,8 @@ import builtins
class ExclusiveObjectPool(DirectObject):
# ObjectPool specialization that excludes particular objects
# IDs of objects to globally exclude from reporting
_ExclObjs = []
_ExclObjIds = {}
_ExclObjs: list[object] = []
_ExclObjIds: dict[int, int] = {}
_SyncMaster = Sync('ExclusiveObjectPool.ExcludedObjectList')
_SerialNumGen = SerialNumGen()

View File

@ -1,5 +1,7 @@
"""Contains miscellaneous utility functions and classes."""
from __future__ import annotations
__all__ = [
'indent', 'doc', 'adjust', 'difference', 'intersection', 'union',
@ -39,6 +41,7 @@ import time
import builtins
import importlib
import functools
from typing import Callable
__report_indent = 3
@ -699,9 +702,9 @@ if __debug__:
return profileDecorator
# intercept profile-related file operations to avoid disk access
movedOpenFuncs = []
movedDumpFuncs = []
movedLoadFuncs = []
movedOpenFuncs: list[Callable] = []
movedDumpFuncs: list[Callable] = []
movedLoadFuncs: list[Callable] = []
profileFilenames = set()
profileFilenameList = Stack()
profileFilename2file = {}
@ -1899,7 +1902,7 @@ class SubframeCall:
class PStatScope:
collectors = {}
collectors: dict = {}
def __init__(self, level = None):
self.levels = []
@ -2618,52 +2621,52 @@ class PriorityCallbacks:
callback()
builtins.Functor = Functor
builtins.Stack = Stack
builtins.Queue = Queue
builtins.SerialNumGen = SerialNumGen
builtins.SerialMaskedGen = SerialMaskedGen
builtins.ScratchPad = ScratchPad
builtins.uniqueName = uniqueName
builtins.serialNum = serialNum
builtins.Functor = Functor # type: ignore[attr-defined]
builtins.Stack = Stack # type: ignore[attr-defined]
builtins.Queue = Queue # type: ignore[attr-defined]
builtins.SerialNumGen = SerialNumGen # type: ignore[attr-defined]
builtins.SerialMaskedGen = SerialMaskedGen # type: ignore[attr-defined]
builtins.ScratchPad = ScratchPad # type: ignore[attr-defined]
builtins.uniqueName = uniqueName # type: ignore[attr-defined]
builtins.serialNum = serialNum # type: ignore[attr-defined]
if __debug__:
builtins.profiled = profiled
builtins.exceptionLogged = exceptionLogged
builtins.itype = itype
builtins.appendStr = appendStr
builtins.bound = bound
builtins.clamp = clamp
builtins.lerp = lerp
builtins.makeList = makeList
builtins.makeTuple = makeTuple
builtins.profiled = profiled # type: ignore[attr-defined]
builtins.exceptionLogged = exceptionLogged # type: ignore[attr-defined]
builtins.itype = itype # type: ignore[attr-defined]
builtins.appendStr = appendStr # type: ignore[attr-defined]
builtins.bound = bound # type: ignore[attr-defined]
builtins.clamp = clamp # type: ignore[attr-defined]
builtins.lerp = lerp # type: ignore[attr-defined]
builtins.makeList = makeList # type: ignore[attr-defined]
builtins.makeTuple = makeTuple # type: ignore[attr-defined]
if __debug__:
builtins.printStack = printStack
builtins.printReverseStack = printReverseStack
builtins.printVerboseStack = printVerboseStack
builtins.DelayedCall = DelayedCall
builtins.DelayedFunctor = DelayedFunctor
builtins.FrameDelayedCall = FrameDelayedCall
builtins.SubframeCall = SubframeCall
builtins.invertDict = invertDict
builtins.invertDictLossless = invertDictLossless
builtins.getBase = getBase
builtins.getRepository = getRepository
builtins.safeRepr = safeRepr
builtins.fastRepr = fastRepr
builtins.nullGen = nullGen
builtins.flywheel = flywheel
builtins.loopGen = loopGen
builtins.printStack = printStack # type: ignore[attr-defined]
builtins.printReverseStack = printReverseStack # type: ignore[attr-defined]
builtins.printVerboseStack = printVerboseStack # type: ignore[attr-defined]
builtins.DelayedCall = DelayedCall # type: ignore[attr-defined]
builtins.DelayedFunctor = DelayedFunctor # type: ignore[attr-defined]
builtins.FrameDelayedCall = FrameDelayedCall # type: ignore[attr-defined]
builtins.SubframeCall = SubframeCall # type: ignore[attr-defined]
builtins.invertDict = invertDict # type: ignore[attr-defined]
builtins.invertDictLossless = invertDictLossless # type: ignore[attr-defined]
builtins.getBase = getBase # type: ignore[attr-defined]
builtins.getRepository = getRepository # type: ignore[attr-defined]
builtins.safeRepr = safeRepr # type: ignore[attr-defined]
builtins.fastRepr = fastRepr # type: ignore[attr-defined]
builtins.nullGen = nullGen # type: ignore[attr-defined]
builtins.flywheel = flywheel # type: ignore[attr-defined]
builtins.loopGen = loopGen # type: ignore[attr-defined]
if __debug__:
builtins.StackTrace = StackTrace
builtins.report = report
builtins.pstatcollect = pstatcollect
builtins.MiniLog = MiniLog
builtins.MiniLogSentry = MiniLogSentry
builtins.logBlock = logBlock
builtins.HierarchyException = HierarchyException
builtins.deeptype = deeptype
builtins.Default = Default
builtins.configIsToday = configIsToday
builtins.typeName = typeName
builtins.safeTypeName = safeTypeName
builtins.histogramDict = histogramDict
builtins.StackTrace = StackTrace # type: ignore[attr-defined]
builtins.report = report # type: ignore[attr-defined]
builtins.pstatcollect = pstatcollect # type: ignore[attr-defined]
builtins.MiniLog = MiniLog # type: ignore[attr-defined]
builtins.MiniLogSentry = MiniLogSentry # type: ignore[attr-defined]
builtins.logBlock = logBlock # type: ignore[attr-defined]
builtins.HierarchyException = HierarchyException # type: ignore[attr-defined]
builtins.deeptype = deeptype # type: ignore[attr-defined]
builtins.Default = Default # type: ignore[attr-defined]
builtins.configIsToday = configIsToday # type: ignore[attr-defined]
builtins.typeName = typeName # type: ignore[attr-defined]
builtins.safeTypeName = safeTypeName # type: ignore[attr-defined]
builtins.histogramDict = histogramDict # type: ignore[attr-defined]

View File

@ -120,7 +120,7 @@ from direct.extensions_native import NodePath_extensions # pylint: disable=unuse
# This needs to be available early for DirectGUI imports
import sys
import builtins
builtins.config = DConfig
builtins.config = DConfig # type: ignore[attr-defined]
from direct.directnotify.DirectNotifyGlobal import directNotify, giveNotify
from .MessengerGlobal import messenger

View File

@ -11,7 +11,7 @@ Note that you cannot directly import :data:`~builtins.base` from this module
since ShowBase may not have been created yet; instead, ShowBase dynamically
adds itself to this module's scope when instantiated."""
__all__ = []
__all__ = ()
from .ShowBase import ShowBase, WindowControls # pylint: disable=unused-import
from direct.directnotify.DirectNotifyGlobal import directNotify, giveNotify # pylint: disable=unused-import
@ -23,6 +23,8 @@ import warnings
__dev__ = ConfigVariableBool('want-dev', __debug__).value
base: ShowBase
#: The global instance of the :ref:`virtual-file-system`, as obtained using
#: :meth:`panda3d.core.VirtualFileSystem.getGlobalPtr()`.
vfs = VirtualFileSystem.getGlobalPtr()
@ -81,7 +83,7 @@ def inspect(anObject):
import builtins
builtins.inspect = inspect
builtins.inspect = inspect # type: ignore[attr-defined]
# this also appears in AIBaseGlobal
if (not __debug__) and __dev__:

View File

@ -3,7 +3,7 @@ This module hooks into Python's import mechanism to print out all imports to
the standard output as they happen.
"""
__all__ = []
__all__ = ()
import sys

View File

@ -45,7 +45,7 @@ BasePickler = pickle._Pickler
BaseUnpickler = pickle._Unpickler
class Pickler(BasePickler):
class Pickler(BasePickler): # type: ignore[misc, valid-type]
def __init__(self, *args, **kw):
self.bamWriter = BamWriter()
@ -148,7 +148,7 @@ class Pickler(BasePickler):
self.save_reduce(obj=obj, *rv)
class Unpickler(BaseUnpickler):
class Unpickler(BaseUnpickler): # type: ignore[misc, valid-type]
def __init__(self, *args, **kw):
self.bamReader = BamReader()

View File

@ -83,8 +83,8 @@ class ThreadBase:
# Copy these static methods from Panda's Thread object. These are
# useful if you may be running in Panda's SIMPLE_THREADS compilation
# mode.
ThreadBase.forceYield = core.Thread.forceYield
ThreadBase.considerYield = core.Thread.considerYield
ThreadBase.forceYield = core.Thread.forceYield # type: ignore[attr-defined]
ThreadBase.considerYield = core.Thread.considerYield # type: ignore[attr-defined]
class Thread(ThreadBase):

View File

@ -65,7 +65,7 @@ if __debug__:
else:
# Disable this when using "python -O"
class _Verbose(object):
class _Verbose(object): # type: ignore[no-redef]
def __init__(self, verbose=None):
pass
def _note(self, *args):

View File

@ -24,7 +24,7 @@ if hasattr(sys, 'getandroidapilevel'):
signal = None
else:
try:
import _signal as signal
import _signal as signal # type: ignore[import, no-redef]
except ImportError:
signal = None

View File

@ -21,11 +21,11 @@ import builtins
# Create toplevel widget dictionary
if not hasattr(builtins, "widgetDict"):
builtins.widgetDict = {}
builtins.widgetDict = {} # type: ignore[attr-defined]
# Create toplevel variable dictionary
if not hasattr(builtins, "variableDict"):
builtins.variableDict = {}
builtins.variableDict = {} # type: ignore[attr-defined]
def resetWidgetDict():

View File

@ -6,6 +6,8 @@ Modified by gjeon.
Modified by Summer 2010 Carnegie Mellon University ETC PandaLE team: fixed a bug in Viewport.Close
"""
from __future__ import annotations
__all__ = ["Viewport", "ViewportManager"]
from panda3d.core import (
@ -36,7 +38,7 @@ VPPERSPECTIVE = 13
class ViewportManager:
"""Manages the global viewport stuff."""
viewports = []
viewports: list[Viewport] = []
gsg = None
@staticmethod
@ -58,7 +60,7 @@ class ViewportManager:
v.Layout(*args, **kwargs)
class Viewport(WxPandaWindow, DirectObject):
class Viewport(WxPandaWindow, DirectObject): # type: ignore[misc, valid-type]
"""Class representing a 3D Viewport."""
CREATENEW = CREATENEW
VPLEFT = VPLEFT

View File

@ -1,2 +1,3 @@
from direct.showbase.ShowBaseGlobal import base
from .WxPandaShell import WxPandaShell
base.app = WxPandaShell()
base.app = WxPandaShell() # type: ignore[attr-defined]

View File

@ -81,7 +81,7 @@ class EmbeddedPandaWindow(wx.Window):
if not hasattr(wxgl, 'GLCanvas'):
OpenGLPandaWindow = None
else:
class OpenGLPandaWindow(wxgl.GLCanvas):
class OpenGLPandaWindow(wxgl.GLCanvas): # type: ignore[no-redef]
""" This class implements a Panda3D "window" that actually draws
within the wx GLCanvas object. It is supported whenever OpenGL is
Panda's rendering engine, and GLCanvas is available in wx. """

13
mypy.ini Normal file
View File

@ -0,0 +1,13 @@
[mypy]
explicit_package_bases = True
exclude = /(dist|directscripts)/
warn_unused_ignores = True
[mypy-panda3d.*]
ignore_missing_imports = True
[mypy-wx.*]
ignore_missing_imports = True
[mypy-Pmw.*]
ignore_missing_imports = True

25
tests/run_mypy.py Normal file
View File

@ -0,0 +1,25 @@
import os
import pathlib
import shutil
import subprocess
import tempfile
def main():
root = pathlib.Path(__file__).parent.parent
direct_src = root / 'direct' / 'src'
mypy_config = root / 'mypy.ini'
with tempfile.TemporaryDirectory() as temp_dir:
os.environ['MYPYPATH'] = temp_dir
direct_copy = pathlib.Path(temp_dir, 'direct')
shutil.copytree(direct_src, direct_copy)
subprocess.run([
'mypy',
str(direct_copy),
'--config-file',
str(mypy_config),
])
if __name__ == '__main__':
main()