From f149fb4ab0f5259d027eef32145111c7e4e120fe Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 29 Oct 2019 20:43:15 +0100 Subject: [PATCH] direct: big formatting changes for the benefit of API reference Part of the effort to move the API reference to Sphinx, see panda3d/panda3d-docs#21 --- direct/src/actor/Actor.py | 54 +++-- direct/src/cluster/ClusterClient.py | 3 +- direct/src/cluster/ClusterConfig.py | 37 ++-- direct/src/controls/ControlManager.py | 31 +-- direct/src/controls/DevWalker.py | 14 +- direct/src/controls/GhostWalker.py | 14 +- direct/src/controls/GravityWalker.py | 14 +- direct/src/controls/InputState.py | 33 +-- direct/src/controls/NonPhysicsWalker.py | 14 +- direct/src/controls/ObserverWalker.py | 14 +- direct/src/controls/PhysicsWalker.py | 14 +- direct/src/controls/TwoDWalker.py | 2 +- .../src/directdevices/DirectDeviceManager.py | 2 +- direct/src/directnotify/DirectNotifyGlobal.py | 6 +- direct/src/directnotify/LoggerGlobal.py | 3 +- direct/src/directnotify/Notifier.py | 12 +- direct/src/directnotify/RotatingLog.py | 30 +-- direct/src/directutil/Verify.py | 68 +++--- direct/src/dist/__init__.py | 4 + direct/src/dist/commands.py | 6 + direct/src/distributed/AsyncRequest.py | 2 +- direct/src/distributed/DistributedObject.py | 3 +- .../src/distributed/DistributedObjectBase.py | 3 +- direct/src/distributed/DoCollectionManager.py | 17 +- direct/src/distributed/DoHierarchy.py | 17 +- direct/src/distributed/PyDatagram.py | 5 +- direct/src/distributed/PyDatagramIterator.py | 1 + direct/src/fsm/ClassicFSM.py | 23 +- direct/src/fsm/FSM.py | 58 ++--- direct/src/fsm/FourState.py | 9 +- direct/src/fsm/FourStateAI.py | 26 +-- direct/src/fsm/__init__.py | 3 + direct/src/gui/DirectDialog.py | 84 +++---- direct/src/gui/DirectGui.py | 2 +- direct/src/gui/DirectGuiBase.py | 76 ++++--- direct/src/gui/DirectGuiGlobals.py | 9 +- direct/src/gui/OnscreenImage.py | 17 +- direct/src/gui/OnscreenText.py | 8 +- direct/src/gui/__init__.py | 2 +- direct/src/interval/ActorInterval.py | 6 +- direct/src/interval/ParticleInterval.py | 36 ++- direct/src/interval/__init__.py | 2 + direct/src/p3d/AppRunner.py | 4 + direct/src/p3d/DeploymentTools.py | 7 +- direct/src/p3d/JavaScript.py | 6 +- direct/src/p3d/Packager.py | 16 +- direct/src/p3d/__init__.py | 4 + direct/src/particles/Particles.py | 8 +- direct/src/particles/__init__.py | 3 + direct/src/showbase/AppRunnerGlobal.py | 11 +- direct/src/showbase/BufferViewer.py | 37 +++- direct/src/showbase/BulletinBoardGlobal.py | 3 +- direct/src/showbase/DistancePhasedNode.py | 44 ++-- direct/src/showbase/ExceptionVarDump.py | 1 + direct/src/showbase/GarbageReportScheduler.py | 5 +- direct/src/showbase/InputStateGlobal.py | 3 +- direct/src/showbase/Job.py | 64 +++--- direct/src/showbase/JobManagerGlobal.py | 1 + direct/src/showbase/LeakDetectors.py | 4 +- direct/src/showbase/Loader.py | 4 +- direct/src/showbase/Messenger.py | 46 ++-- direct/src/showbase/MessengerGlobal.py | 3 +- direct/src/showbase/MirrorDemo.py | 2 +- direct/src/showbase/PhysicsManagerGlobal.py | 3 +- direct/src/showbase/Pool.py | 11 +- direct/src/showbase/PythonUtil.py | 144 ++++++------ direct/src/showbase/ShowBase.py | 79 ++++--- direct/src/showbase/ShowBaseGlobal.py | 12 +- direct/src/showbase/TkGlobal.py | 1 + direct/src/showbase/VFSImporter.py | 39 ++-- direct/src/showbase/WxGlobal.py | 2 + direct/src/stdpy/file.py | 5 + direct/src/stdpy/pickle.py | 6 +- direct/src/task/Task.py | 98 +++++---- direct/src/task/TaskManagerGlobal.py | 2 +- direct/src/task/__init__.py | 3 + direct/src/tkpanels/FSMInspector.py | 206 +++++++++--------- direct/src/tkpanels/__init__.py | 3 + direct/src/tkwidgets/__init__.py | 1 + 79 files changed, 939 insertions(+), 736 deletions(-) diff --git a/direct/src/actor/Actor.py b/direct/src/actor/Actor.py index 902c6830d7..f99a18bbdf 100644 --- a/direct/src/actor/Actor.py +++ b/direct/src/actor/Actor.py @@ -104,45 +104,43 @@ class Actor(DirectObject, NodePath): lodNode = None, flattenable = True, setFinal = False, mergeLODBundles = None, allowAsyncBind = None, okMissing = None): - """__init__(self, string | string:string{}, string:string{} | - string:(string:string{}){}, Actor=None) - Actor constructor: can be used to create single or multipart + """Actor constructor: can be used to create single or multipart actors. If another Actor is supplied as an argument this method acts like a copy constructor. Single part actors are created by calling with a model and animation dictionary - (animName:animPath{}) as follows: + ``(animName:animPath{})`` as follows:: - a = Actor("panda-3k.egg", {"walk":"panda-walk.egg" \ + a = Actor("panda-3k.egg", {"walk":"panda-walk.egg", "run":"panda-run.egg"}) - This could be displayed and animated as such: + This could be displayed and animated as such:: a.reparentTo(render) a.loop("walk") a.stop() Multipart actors expect a dictionary of parts and a dictionary - of animation dictionaries (partName:(animName:animPath{}){}) as - below: + of animation dictionaries ``(partName:(animName:animPath{}){})`` + as below:: a = Actor( # part dictionary - {"head":"char/dogMM/dogMM_Shorts-head-mod", \ - "torso":"char/dogMM/dogMM_Shorts-torso-mod", \ - "legs":"char/dogMM/dogMM_Shorts-legs-mod"}, \ + {"head": "char/dogMM/dogMM_Shorts-head-mod", + "torso": "char/dogMM/dogMM_Shorts-torso-mod", + "legs": "char/dogMM/dogMM_Shorts-legs-mod"}, # dictionary of anim dictionaries - {"head":{"walk":"char/dogMM/dogMM_Shorts-head-walk", \ - "run":"char/dogMM/dogMM_Shorts-head-run"}, \ - "torso":{"walk":"char/dogMM/dogMM_Shorts-torso-walk", \ - "run":"char/dogMM/dogMM_Shorts-torso-run"}, \ - "legs":{"walk":"char/dogMM/dogMM_Shorts-legs-walk", \ - "run":"char/dogMM/dogMM_Shorts-legs-run"} \ + {"head":{"walk": "char/dogMM/dogMM_Shorts-head-walk", + "run": "char/dogMM/dogMM_Shorts-head-run"}, + "torso":{"walk": "char/dogMM/dogMM_Shorts-torso-walk", + "run": "char/dogMM/dogMM_Shorts-torso-run"}, + "legs":{"walk": "char/dogMM/dogMM_Shorts-legs-walk", + "run": "char/dogMM/dogMM_Shorts-legs-run"} }) In addition multipart actor parts need to be connected together - in a meaningful fashion: + in a meaningful fashion:: a.attach("head", "torso", "joint-head") a.attach("torso", "legs", "joint-hips") @@ -151,7 +149,7 @@ class Actor(DirectObject, NodePath): # ADD LOD COMMENT HERE! # - Other useful Actor class functions: + Other useful Actor class functions:: #fix actor eye rendering a.drawInFront("joint-pupil?", "eyes*") @@ -1135,7 +1133,7 @@ class Actor(DirectObject, NodePath): def getJoints(self, partName = None, jointName = '*', lodName = None): """ Returns the list of all joints, from the named part or from all parts, that match the indicated jointName. The - jointName may include pattern characters like *. """ + jointName may include pattern characters like \\*. """ joints=[] pattern = GlobPattern(jointName) @@ -2439,15 +2437,15 @@ class Actor(DirectObject, NodePath): return ActorInterval.ActorInterval(self, *args, **kw) def getAnimBlends(self, animName=None, partName=None, lodName=None): - """ Returns a list of the form: + """Returns a list of the form:: - [ (lodName, [(animName, [(partName, effect), (partName, effect), ...]), - (animName, [(partName, effect), (partName, effect), ...]), - ...]), - (lodName, [(animName, [(partName, effect), (partName, effect), ...]), - (animName, [(partName, effect), (partName, effect), ...]), - ...]), - ... ] + [ (lodName, [(animName, [(partName, effect), (partName, effect), ...]), + (animName, [(partName, effect), (partName, effect), ...]), + ...]), + (lodName, [(animName, [(partName, effect), (partName, effect), ...]), + (animName, [(partName, effect), (partName, effect), ...]), + ...]), + ... ] This list reports the non-zero control effects for each partName within a particular animation and LOD. """ diff --git a/direct/src/cluster/ClusterClient.py b/direct/src/cluster/ClusterClient.py index 873b03d4ea..969ba9e860 100644 --- a/direct/src/cluster/ClusterClient.py +++ b/direct/src/cluster/ClusterClient.py @@ -1,4 +1,4 @@ -"""ClusterClient: Master for mutli-piping or PC clusters. """ +"""ClusterClient: Master for multi-piping or PC clusters.""" from panda3d.core import * from .ClusterMsgs import * @@ -8,6 +8,7 @@ from direct.showbase import DirectObject from direct.task import Task import os + class ClusterClient(DirectObject.DirectObject): notify = DirectNotifyGlobal.directNotify.newCategory("ClusterClient") MGR_NUM = 1000000 diff --git a/direct/src/cluster/ClusterConfig.py b/direct/src/cluster/ClusterConfig.py index 73e4ebf2b6..a22e98b7db 100644 --- a/direct/src/cluster/ClusterConfig.py +++ b/direct/src/cluster/ClusterConfig.py @@ -1,23 +1,26 @@ from .ClusterClient import * -# A dictionary of information for various cluster configurations. -# Dictionary is keyed on cluster-config string -# Each dictionary contains a list of display configurations, one for -# each display in the cluster -# Information that can be specified for each display: -# display name: Name of display (used in Configrc to specify server) -# display type: Used to flag client vs. server -# pos: positional offset of display's camera from main cluster group -# hpr: orientation offset of display's camera from main cluster group -# focal length: display's focal length (in mm) -# film size: display's film size (in inches) -# film offset: offset of film back (in inches) -# Note: Note, this overrides offsets specified in DirectCamConfig.py -# For now we only specify frustum for first display region of configuration -# TODO: Need to handle multiple display regions per cluster node and to -# generalize to non cluster situations - +#: A dictionary of information for various cluster configurations. +#: Dictionary is keyed on cluster-config string +#: Each dictionary contains a list of display configurations, one for +#: each display in the cluster +#: +#: Information that can be specified for each display: +#: +#: - display name: Name of display (used in Configrc to specify server) +#: - display type: Used to flag client vs. server +#: - pos: positional offset of display's camera from main cluster group +#: - hpr: orientation offset of display's camera from main cluster group +#: - focal length: display's focal length (in mm) +#: - film size: display's film size (in inches) +#: - film offset: offset of film back (in inches) +#: +#: Note: this overrides offsets specified in DirectCamConfig.py +#: For now we only specify frustum for first display region of configuration +#: +#: TODO: Need to handle multiple display regions per cluster node and to +#: generalize to non cluster situations ClientConfigs = { 'single-server': [{'display name': 'display0', 'display mode': 'client', diff --git a/direct/src/controls/ControlManager.py b/direct/src/controls/ControlManager.py index bc3aad3ff2..6c11f619f6 100755 --- a/direct/src/controls/ControlManager.py +++ b/direct/src/controls/ControlManager.py @@ -15,7 +15,9 @@ from direct.directnotify import DirectNotifyGlobal from direct.task import Task from panda3d.core import ConfigVariableBool -CollisionHandlerRayStart = 4000.0 # This is a hack, it may be better to use a line instead of a ray. +# This is a hack, it may be better to use a line instead of a ray. +CollisionHandlerRayStart = 4000.0 + class ControlManager: notify = DirectNotifyGlobal.directNotify.newCategory("ControlManager") @@ -52,14 +54,14 @@ class ControlManager: return 'ControlManager: using \'%s\'' % self.currentControlsName def add(self, controls, name="basic"): - """ - controls is an avatar control system. - name is any key that you want to use to refer to the - the controls later (e.g. using the use() call). + """Add a control instance to the list of available control systems. - Add a control instance to the list of available control systems. + Args: + controls: an avatar control system. + name (str): any key that you want to use to refer to the controls + later (e.g. using the use() call). - See also: use(). + See also: :meth:`use()`. """ assert self.notify.debugCall(id(self)) assert controls is not None @@ -77,15 +79,14 @@ class ControlManager: return self.controls.get(name) def remove(self, name): - """ - name is any key that was used to refer to the - the controls when they were added (e.g. - using the add(, ) call). + """Remove a control instance from the list of available control + systems. - Remove a control instance from the list of - available control systems. + Args: + name: any key that was used to refer to the controls when they were + added (e.g. using the add(, ) call). - See also: add(). + See also: :meth:`add()`. """ assert self.notify.debugCall(id(self)) oldControls = self.controls.pop(name,None) @@ -108,7 +109,7 @@ class ControlManager: Use a previously added control system. - See also: add(). + See also: :meth:`add()`. """ assert self.notify.debugCall(id(self)) if __debug__ and hasattr(self, "ignoreUse"): diff --git a/direct/src/controls/DevWalker.py b/direct/src/controls/DevWalker.py index 03f2f0b0ff..460b6c83f6 100755 --- a/direct/src/controls/DevWalker.py +++ b/direct/src/controls/DevWalker.py @@ -2,15 +2,17 @@ DevWalker.py is for avatars. A walker control such as this one provides: - - creation of the collision nodes - - handling the keyboard and mouse input for avatar movement - - moving the avatar + +- creation of the collision nodes +- handling the keyboard and mouse input for avatar movement +- moving the avatar it does not: - - play sounds - - play animations -although it does send messeges that allow a listener to play sounds or +- play sounds +- play animations + +although it does send messages that allow a listener to play sounds or animations based on walker events. """ diff --git a/direct/src/controls/GhostWalker.py b/direct/src/controls/GhostWalker.py index 4badbf7258..26f4ad8a9f 100755 --- a/direct/src/controls/GhostWalker.py +++ b/direct/src/controls/GhostWalker.py @@ -2,15 +2,17 @@ GhostWalker.py is for avatars. A walker control such as this one provides: - - creation of the collision nodes - - handling the keyboard and mouse input for avatar movement - - moving the avatar + +- creation of the collision nodes +- handling the keyboard and mouse input for avatar movement +- moving the avatar it does not: - - play sounds - - play animations -although it does send messeges that allow a listener to play sounds or +- play sounds +- play animations + +although it does send messages that allow a listener to play sounds or animations based on walker events. """ diff --git a/direct/src/controls/GravityWalker.py b/direct/src/controls/GravityWalker.py index bf3ea8a9bd..28d047d6f0 100755 --- a/direct/src/controls/GravityWalker.py +++ b/direct/src/controls/GravityWalker.py @@ -2,15 +2,17 @@ GravityWalker.py is for avatars. A walker control such as this one provides: - - creation of the collision nodes - - handling the keyboard and mouse input for avatar movement - - moving the avatar + +- creation of the collision nodes +- handling the keyboard and mouse input for avatar movement +- moving the avatar it does not: - - play sounds - - play animations -although it does send messeges that allow a listener to play sounds or +- play sounds +- play animations + +although it does send messages that allow a listener to play sounds or animations based on walker events. """ from direct.directnotify.DirectNotifyGlobal import directNotify diff --git a/direct/src/controls/InputState.py b/direct/src/controls/InputState.py index 2fe21fc80f..1be5d6fbfe 100755 --- a/direct/src/controls/InputState.py +++ b/direct/src/controls/InputState.py @@ -135,14 +135,16 @@ class InputState(DirectObject.DirectObject): def watch(self, name, eventOn, eventOff, startState=False, inputSource=None): """ - This returns a token; hold onto the token and call token.release() when you - no longer want to watch for these events. + This returns a token; hold onto the token and call token.release() when + you no longer want to watch for these events. - # set up - token = inputState.watch('forward', 'w', 'w-up', inputSource=inputState.WASD) - ... - # tear down - token.release() + Example:: + + # set up + token = inputState.watch('forward', 'w', 'w-up', inputSource=inputState.WASD) + ... + # tear down + token.release() """ assert self.debugPrint( "watch(name=%s, eventOn=%s, eventOff=%s, startState=%s)"%( @@ -191,15 +193,16 @@ class InputState(DirectObject.DirectObject): """ Force isSet(name) to return 'value'. - This returns a token; hold onto the token and call token.release() when you - no longer want to force the state. + This returns a token; hold onto the token and call token.release() when + you no longer want to force the state. - example: - # set up - token=inputState.force('forward', True, inputSource='myForwardForcer') - ... - # tear down - token.release() + Example:: + + # set up + token = inputState.force('forward', True, inputSource='myForwardForcer') + ... + # tear down + token.release() """ token = InputStateForceToken(self) self._token2forceInfo[token] = (name, inputSource) diff --git a/direct/src/controls/NonPhysicsWalker.py b/direct/src/controls/NonPhysicsWalker.py index de5a6bfb00..0b9c67f5e6 100755 --- a/direct/src/controls/NonPhysicsWalker.py +++ b/direct/src/controls/NonPhysicsWalker.py @@ -2,15 +2,17 @@ NonPhysicsWalker.py is for avatars. A walker control such as this one provides: - - creation of the collision nodes - - handling the keyboard and mouse input for avatar movement - - moving the avatar + +- creation of the collision nodes +- handling the keyboard and mouse input for avatar movement +- moving the avatar it does not: - - play sounds - - play animations -although it does send messeges that allow a listener to play sounds or +- play sounds +- play animations + +although it does send messages that allow a listener to play sounds or animations based on walker events. """ diff --git a/direct/src/controls/ObserverWalker.py b/direct/src/controls/ObserverWalker.py index f93e0e3325..3fbdaeaed6 100755 --- a/direct/src/controls/ObserverWalker.py +++ b/direct/src/controls/ObserverWalker.py @@ -2,15 +2,17 @@ ObserverWalker.py is for avatars. A walker control such as this one provides: - - creation of the collision nodes - - handling the keyboard and mouse input for avatar movement - - moving the avatar + +- creation of the collision nodes +- handling the keyboard and mouse input for avatar movement +- moving the avatar it does not: - - play sounds - - play animations -although it does send messeges that allow a listener to play sounds or +- play sounds +- play animations + +although it does send messages that allow a listener to play sounds or animations based on walker events. """ diff --git a/direct/src/controls/PhysicsWalker.py b/direct/src/controls/PhysicsWalker.py index de6ebcefa8..3743f25ac9 100755 --- a/direct/src/controls/PhysicsWalker.py +++ b/direct/src/controls/PhysicsWalker.py @@ -2,15 +2,17 @@ PhysicsWalker.py is for avatars. A walker control such as this one provides: - - creation of the collision nodes - - handling the keyboard and mouse input for avatar movement - - moving the avatar + +- creation of the collision nodes +- handling the keyboard and mouse input for avatar movement +- moving the avatar it does not: - - play sounds - - play animations -although it does send messeges that allow a listener to play sounds or +- play sounds +- play animations + +although it does send messages that allow a listener to play sounds or animations based on walker events. """ diff --git a/direct/src/controls/TwoDWalker.py b/direct/src/controls/TwoDWalker.py index b99f6db11b..58fa913959 100644 --- a/direct/src/controls/TwoDWalker.py +++ b/direct/src/controls/TwoDWalker.py @@ -1,5 +1,5 @@ """ -TwoDWalker.py is for controling the avatars in a 2D Scroller game environment. +TwoDWalker.py is for controlling the avatars in a 2D scroller game environment. """ from .GravityWalker import * diff --git a/direct/src/directdevices/DirectDeviceManager.py b/direct/src/directdevices/DirectDeviceManager.py index 76206f6c40..1ee3be6507 100644 --- a/direct/src/directdevices/DirectDeviceManager.py +++ b/direct/src/directdevices/DirectDeviceManager.py @@ -1,4 +1,4 @@ -""" Class used to create and control vrpn devices """ +"""Class used to create and control VRPN devices.""" from direct.showbase.DirectObject import DirectObject from panda3d.core import * diff --git a/direct/src/directnotify/DirectNotifyGlobal.py b/direct/src/directnotify/DirectNotifyGlobal.py index e25ddb11ad..96b10224ac 100644 --- a/direct/src/directnotify/DirectNotifyGlobal.py +++ b/direct/src/directnotify/DirectNotifyGlobal.py @@ -1,8 +1,12 @@ -"""instantiate global DirectNotify used in Direct""" +"""Instantiates global DirectNotify used in Direct.""" __all__ = ['directNotify', 'giveNotify'] from . import DirectNotify +#: The global :class:`~.DirectNotify.DirectNotify` object. directNotify = DirectNotify.DirectNotify() + +#: Shorthand function for adding a DirectNotify category to a given class +#: object. Alias of `.DirectNotify.DirectNotify.giveNotify`. giveNotify = directNotify.giveNotify diff --git a/direct/src/directnotify/LoggerGlobal.py b/direct/src/directnotify/LoggerGlobal.py index 610a009a8f..9fe05b3957 100644 --- a/direct/src/directnotify/LoggerGlobal.py +++ b/direct/src/directnotify/LoggerGlobal.py @@ -1,5 +1,6 @@ -"""instantiate global Logger object""" +"""Instantiates a global :class:`~.Logger.Logger` object.""" from . import Logger +#: Contains a global :class:`~.Logger.Logger` object. defaultLogger = Logger.Logger() diff --git a/direct/src/directnotify/Notifier.py b/direct/src/directnotify/Notifier.py index 35a916f8b3..571d7f43b0 100644 --- a/direct/src/directnotify/Notifier.py +++ b/direct/src/directnotify/Notifier.py @@ -8,6 +8,7 @@ from panda3d.core import ConfigVariableBool, NotifyCategory, StreamWriter, Notif import time import sys + class Notifier: serverDelta = 0 @@ -23,12 +24,11 @@ class Notifier: def __init__(self, name, logger=None): """ - name is a string - logger is a Logger - - Create a new instance of the Notifier class with a given name - and an optional Logger class for piping output to. If no logger - specified, use the global default + Parameters: + name (str): a string name given to this Notifier instance. + logger (Logger, optional): an optional Logger object for + piping output to. If none is specified, the global + :data:`~.LoggerGlobal.defaultLogger` is used. """ self.__name = name diff --git a/direct/src/directnotify/RotatingLog.py b/direct/src/directnotify/RotatingLog.py index e663da67ac..5eb5706c95 100755 --- a/direct/src/directnotify/RotatingLog.py +++ b/direct/src/directnotify/RotatingLog.py @@ -1,8 +1,7 @@ - - import os import time + class RotatingLog: """ A file() (or open()) replacement that will automatically open and write @@ -11,22 +10,23 @@ class RotatingLog: def __init__(self, path="./log_file", hourInterval=24, megabyteLimit=1024): """ - path is a full or partial path with file name. - hourInterval is the number of hours at which to rotate the file. - megabyteLimit is the number of megabytes of file size the log - may grow to, after which the log is rotated. Note: The log - file may get a bit larger than limit do to writing out whole - lines (last line may exceed megabyteLimit or "megabyteGuidline"). + Args: + path: a full or partial path with file name. + hourInterval: the number of hours at which to rotate the file. + megabyteLimit: the number of megabytes of file size the log may + grow to, after which the log is rotated. Note: The log file + may get a bit larger than limit do to writing out whole lines + (last line may exceed megabyteLimit or "megabyteGuidline"). """ - self.path=path - self.timeInterval=None - self.timeLimit=None - self.sizeLimit=None + self.path = path + self.timeInterval = None + self.timeLimit = None + self.sizeLimit = None if hourInterval is not None: - self.timeInterval=hourInterval*60*60 - self.timeLimit=time.time()+self.timeInterval + self.timeInterval = hourInterval*60*60 + self.timeLimit = time.time()+self.timeInterval if megabyteLimit is not None: - self.sizeLimit=megabyteLimit*1024*1024 + self.sizeLimit = megabyteLimit*1024*1024 def __del__(self): self.close() diff --git a/direct/src/directutil/Verify.py b/direct/src/directutil/Verify.py index ce23b1daa9..20a450ea92 100755 --- a/direct/src/directutil/Verify.py +++ b/direct/src/directutil/Verify.py @@ -1,27 +1,31 @@ """ -You can use verify() just like assert, with these small differences: - - you may need to "import Verify", if someone hasn't done it - for you. - - unlike assert where using parenthises are optional, verify() - requires them. - e.g.: - assert foo # OK - verify foo # Error - assert foo # Not Recomended (may be interpreted as a tuple) - verify(foo) # OK - - verify() will print something like the following before raising - an exception: - verify failed: - File "direct/src/showbase/ShowBase.py", line 60 - - verify() will optionally start pdb for you (this is currently - false by default). You can either edit Verify.py to set - wantVerifyPdb = 1 or if you are using ShowBase you can set - want-verify-pdb 1 in your Configrc to start pdb automatically. - - verify() will still function in the release build. It will - not be removed by -O like assert will. +You can use :func:`verify()` just like assert, with these small differences: -verify() will also throw an AssertionError, but you can ignore that if you -like (I don't suggest trying to catch it, it's just doing it so that it can +- you may need to ``import Verify``, if someone hasn't done it for you. + +- unlike assert where using parentheses are optional, :func:`verify()` + requires them, e.g.:: + + assert foo # OK + verify foo # Error + assert foo # Not Recomended (may be interpreted as a tuple) + verify(foo) # OK + +- :func:`verify()` will print something like this before raising an exception:: + + verify failed: + File "direct/src/showbase/ShowBase.py", line 60 + +- :func:`verify()` will optionally start pdb for you (this is currently false + by default). You can either edit Verify.py to set ``wantVerifyPdb = 1`` or + if you are using ShowBase you can set ``want-verify-pdb 1`` in your + Config.prc file to start pdb automatically. + +- :func:`verify()` will still function in the release build. It will not be + removed by -O like assert will. + +:func:`verify()` will also throw an AssertionError, but you can ignore that if +you like (I don't suggest trying to catch it, it's just doing it so that it can replace assert more fully). Please do not use assert for things that you want run on release builds. @@ -31,19 +35,20 @@ an exception can get it mistaken for an error handler. If your code needs to handle an error or throw an exception, you should do that (and not just assert for it). -If you want to be a super keen software engineer then avoid using verify(). -If you want to be, or already are, a super keen software engineer, but -you don't always have the time to write proper error handling, go ahead -and use verify() -- that's what it's for. +If you want to be a super keen software engineer then avoid using +:func:`verify()`. If you want to be, or already are, a super keen software +engineer, but you don't always have the time to write proper error handling, +go ahead and use :func:`verify()` -- that's what it's for. -Please use assert (properly) and do proper error handling; and use verify() -only when debugging (i.e. when it won't be checked-in) or where it helps -you resist using assert for error handling. +Please use assert (properly) and do proper error handling; and use +:func:`verify()` only when debugging (i.e. when it won't be checked-in) or +where it helps you resist using assert for error handling. """ from panda3d.core import ConfigVariableBool -wantVerifyPdb = ConfigVariableBool('want-verify-pdb', False) # Set to true to load pdb on failure. +# Set to true to load pdb on failure. +wantVerifyPdb = ConfigVariableBool('want-verify-pdb', False) def verify(assertion): @@ -54,7 +59,7 @@ def verify(assertion): if not assertion: print("\n\nverify failed:") import sys - print(" File \"%s\", line %d"%( + print(" File \"%s\", line %d" % ( sys._getframe(1).f_code.co_filename, sys._getframe(1).f_lineno)) if wantVerifyPdb: @@ -62,5 +67,6 @@ def verify(assertion): pdb.set_trace() raise AssertionError + if not hasattr(__builtins__, "verify"): __builtins__["verify"] = verify diff --git a/direct/src/dist/__init__.py b/direct/src/dist/__init__.py index e69de29bb2..882eaf97c9 100644 --- a/direct/src/dist/__init__.py +++ b/direct/src/dist/__init__.py @@ -0,0 +1,4 @@ +"""This package contains tools to help with distributing Panda3D +applications. See the :ref:`distribution` section in the programming +manual for further details. +""" diff --git a/direct/src/dist/commands.py b/direct/src/dist/commands.py index f8160ed546..b360fb2bc7 100644 --- a/direct/src/dist/commands.py +++ b/direct/src/dist/commands.py @@ -1,3 +1,9 @@ +"""Extends setuptools with the ``build_apps`` and ``bdist_apps`` commands. + +See the :ref:`distribution` section of the programming manual for information +on how to use these commands. +""" + from __future__ import print_function import collections diff --git a/direct/src/distributed/AsyncRequest.py b/direct/src/distributed/AsyncRequest.py index 1d30259a6e..10e00f3765 100755 --- a/direct/src/distributed/AsyncRequest.py +++ b/direct/src/distributed/AsyncRequest.py @@ -15,7 +15,7 @@ if __debug__: class AsyncRequest(DirectObject): """ - This class is used to make asynchronos reads and creates to a database. + This class is used to make asynchronous reads and creates to a database. You can create a list of self.neededObjects and then ask for each to be read or created, or if you only have one object that you need you can diff --git a/direct/src/distributed/DistributedObject.py b/direct/src/distributed/DistributedObject.py index 64fd3ecc20..84870b890c 100644 --- a/direct/src/distributed/DistributedObject.py +++ b/direct/src/distributed/DistributedObject.py @@ -26,11 +26,12 @@ ESNum2Str = { ESGenerated: 'ESGenerated', } + class DistributedObject(DistributedObjectBase): """ The Distributed Object class is the base class for all network based (i.e. distributed) objects. These will usually (always?) have a - dclass entry in a *.dc file. + dclass entry in a \\*.dc file. """ notify = directNotify.newCategory("DistributedObject") diff --git a/direct/src/distributed/DistributedObjectBase.py b/direct/src/distributed/DistributedObjectBase.py index 3d9b525067..066466df1d 100755 --- a/direct/src/distributed/DistributedObjectBase.py +++ b/direct/src/distributed/DistributedObjectBase.py @@ -1,11 +1,12 @@ from direct.showbase.DirectObject import DirectObject from direct.directnotify.DirectNotifyGlobal import directNotify + class DistributedObjectBase(DirectObject): """ The Distributed Object class is the base class for all network based (i.e. distributed) objects. These will usually (always?) have a - dclass entry in a *.dc file. + dclass entry in a \\*.dc file. """ notify = directNotify.newCategory("DistributedObjectBase") diff --git a/direct/src/distributed/DoCollectionManager.py b/direct/src/distributed/DoCollectionManager.py index fcff96e218..9dbf794dce 100755 --- a/direct/src/distributed/DoCollectionManager.py +++ b/direct/src/distributed/DoCollectionManager.py @@ -5,6 +5,7 @@ import re BAD_DO_ID = BAD_ZONE_ID = 0 # 0xFFFFFFFF BAD_CHANNEL_ID = 0 # 0xFFFFFFFFFFFFFFFF + class DoCollectionManager: def __init__(self): # Dict of {DistributedObject ids: DistributedObjects} @@ -186,7 +187,6 @@ class DoCollectionManager: strToReturn = '%s%s' % (strToReturn, self._returnObjects(self.getDoTable(ownerView=False))) return strToReturn - def printObjectCount(self): # print object counts by distributed object type print('==== OBJECT COUNT ====') @@ -199,13 +199,14 @@ class DoCollectionManager: def getDoList(self, parentId, zoneId=None, classType=None): """ - parentId is any distributed object id. - zoneId is a uint32, defaults to None (all zones). Try zone 2 if - you're not sure which zone to use (0 is a bad/null zone and - 1 has had reserved use in the past as a no messages zone, while - 2 has traditionally been a global, uber, misc stuff zone). - dclassType is a distributed class type filter, defaults - to None (no filter). + Args: + parentId: any distributed object id. + zoneId: a uint32, defaults to None (all zones). Try zone 2 if + you're not sure which zone to use (0 is a bad/null zone and + 1 has had reserved use in the past as a no messages zone, while + 2 has traditionally been a global, uber, misc stuff zone). + dclassType: a distributed class type filter, defaults to None + (no filter). If dclassName is None then all objects in the zone are returned; otherwise the list is filtered to only include objects of that type. diff --git a/direct/src/distributed/DoHierarchy.py b/direct/src/distributed/DoHierarchy.py index e06572ab2e..c7283f4ac2 100755 --- a/direct/src/distributed/DoHierarchy.py +++ b/direct/src/distributed/DoHierarchy.py @@ -26,15 +26,14 @@ class DoHierarchy: def getDoIds(self, getDo, parentId, zoneId=None, classType=None): """ - Moved from DoCollectionManager - ============================== - parentId is any distributed object id. - zoneId is a uint32, defaults to None (all zones). Try zone 2 if - you're not sure which zone to use (0 is a bad/null zone and - 1 has had reserved use in the past as a no messages zone, while - 2 has traditionally been a global, uber, misc stuff zone). - dclassType is a distributed class type filter, defaults - to None (no filter). + Args: + parentId: any distributed object id. + zoneId: a uint32, defaults to None (all zones). Try zone 2 if + you're not sure which zone to use (0 is a bad/null zone and + 1 has had reserved use in the past as a no messages zone, while + 2 has traditionally been a global, uber, misc stuff zone). + dclassType: a distributed class type filter, defaults to None + (no filter). If dclassName is None then all objects in the zone are returned; otherwise the list is filtered to only include objects of that type. diff --git a/direct/src/distributed/PyDatagram.py b/direct/src/distributed/PyDatagram.py index f45c3c52c1..1f1f56ad16 100755 --- a/direct/src/distributed/PyDatagram.py +++ b/direct/src/distributed/PyDatagram.py @@ -9,6 +9,7 @@ from panda3d.direct import * from direct.distributed.MsgTypes import * + class PyDatagram(Datagram): # This is a little helper Dict to replace the huge statement @@ -29,8 +30,6 @@ class PyDatagram(Datagram): STBlob32: (Datagram.addBlob32, None), } - #def addChannel(self, channelId): - # ... addChannel = Datagram.addUint64 def addServerHeader(self, channel, sender, code): @@ -39,14 +38,12 @@ class PyDatagram(Datagram): self.addChannel(sender) self.addUint16(code) - def addOldServerHeader(self, channel, sender, code): self.addChannel(channel) self.addChannel(sender) self.addChannel('A') self.addUint16(code) - def addServerControlHeader(self, code): self.addInt8(1) self.addChannel(CONTROL_CHANNEL) diff --git a/direct/src/distributed/PyDatagramIterator.py b/direct/src/distributed/PyDatagramIterator.py index 6ce96e77e4..bd27469c41 100755 --- a/direct/src/distributed/PyDatagramIterator.py +++ b/direct/src/distributed/PyDatagramIterator.py @@ -7,6 +7,7 @@ from panda3d.core import * from panda3d.direct import * # Import the type numbers + class PyDatagramIterator(DatagramIterator): # This is a little helper Dict to replace the huge statement diff --git a/direct/src/fsm/ClassicFSM.py b/direct/src/fsm/ClassicFSM.py index c954718e4d..18c0bd6a4d 100644 --- a/direct/src/fsm/ClassicFSM.py +++ b/direct/src/fsm/ClassicFSM.py @@ -1,9 +1,8 @@ """Finite State Machine module: contains the ClassicFSM class. -.. note:: - - This module and class exist only for backward compatibility with - existing code. New code should use the :mod:`.FSM` module instead. +Note: + This module and class exist only for backward compatibility with + existing code. New code should use the :mod:`.FSM` module instead. """ __all__ = ['ClassicFSM'] @@ -14,12 +13,14 @@ import weakref if __debug__: _debugFsms = {} + def printDebugFsmList(): global _debugFsms for k in sorted(_debugFsms.keys()): print("%s %s" % (k, _debugFsms[k]())) __builtins__['debugFsmList'] = printDebugFsmList + class ClassicFSM(DirectObject): """ Finite State Machine class. @@ -45,14 +46,14 @@ class ClassicFSM(DirectObject): """__init__(self, string, State[], string, string, int) ClassicFSM constructor: takes name, list of states, initial state and - final state as: + final state as:: - fsm = ClassicFSM.ClassicFSM('stopLight', - [State.State('red', enterRed, exitRed, ['green']), - State.State('yellow', enterYellow, exitYellow, ['red']), - State.State('green', enterGreen, exitGreen, ['yellow'])], - 'red', - 'red') + fsm = ClassicFSM.ClassicFSM('stopLight', + [State.State('red', enterRed, exitRed, ['green']), + State.State('yellow', enterYellow, exitYellow, ['red']), + State.State('green', enterGreen, exitGreen, ['yellow'])], + 'red', + 'red') each state's last argument, a list of allowed state transitions, is optional; if left out (or explicitly specified to be diff --git a/direct/src/fsm/FSM.py b/direct/src/fsm/FSM.py index 6af064e3d7..bae5dc094b 100644 --- a/direct/src/fsm/FSM.py +++ b/direct/src/fsm/FSM.py @@ -1,5 +1,8 @@ """The new Finite State Machine module. This replaces the module previously called FSM (now called :mod:`.ClassicFSM`). + +For more information on FSMs, consult the :ref:`finite-state-machines` section +of the programming manual. """ __all__ = ['FSMException', 'FSM'] @@ -14,12 +17,15 @@ from direct.stdpy.threading import RLock class FSMException(Exception): pass + class AlreadyInTransition(FSMException): pass + class RequestDenied(FSMException): pass + class FSM(DirectObject): """ A Finite State Machine. This is intended to be the base class @@ -34,25 +40,25 @@ class FSM(DirectObject): To define specialized behavior when entering or exiting a particular state, define a method named enterState() and/or - exitState(), where "State" is the name of the state, e.g.: + exitState(), where "State" is the name of the state, e.g.:: - def enterRed(self): - ... do stuff ... + def enterRed(self): + ... do stuff ... - def exitRed(self): - ... cleanup stuff ... + def exitRed(self): + ... cleanup stuff ... - def enterYellow(self): - ... do stuff ... + def enterYellow(self): + ... do stuff ... - def exitYellow(self): - ... cleanup stuff ... + def exitYellow(self): + ... cleanup stuff ... - def enterGreen(self): - ... do stuff ... + def enterGreen(self): + ... do stuff ... - def exitGreen(self): - ... cleanup stuff ... + def exitGreen(self): + ... cleanup stuff ... Both functions can access the previous state name as self.oldState, and the new state name we are transitioning to as @@ -70,22 +76,22 @@ class FSM(DirectObject): input is always a string and a tuple of optional parameters (which is often empty), and the return value should either be None to do nothing, or the name of the state to transition into. For - example: + example:: - def filterRed(self, request, args): - if request in ['Green']: - return (request,) + args - return None + def filterRed(self, request, args): + if request in ['Green']: + return (request,) + args + return None - def filterYellow(self, request, args): - if request in ['Red']: - return (request,) + args - return None + def filterYellow(self, request, args): + if request in ['Red']: + return (request,) + args + return None - def filterGreen(self, request, args): - if request in ['Yellow']: - return (request,) + args - return None + def filterGreen(self, request, args): + if request in ['Yellow']: + return (request,) + args + return None As above, the filterState() functions are optional. If any is omitted, the defaultFilter() method is called instead. A standard diff --git a/direct/src/fsm/FourState.py b/direct/src/fsm/FourState.py index 5188284baf..65a5b5b807 100755 --- a/direct/src/fsm/FourState.py +++ b/direct/src/fsm/FourState.py @@ -44,25 +44,22 @@ class FourState: def __init__(self, names, durations = [0, 1, None, 1, 1]): """ - names is a list of state names + Names is a list of state names. Some examples are:: - E.g. ['off', 'opening', 'open', 'closing', 'closed',] - e.g. 2: ['off', 'locking', 'locked', 'unlocking', 'unlocked',] - e.g. 3: ['off', 'deactivating', 'deactive', 'activating', 'activated',] durations is a list of time values (floats) or None values. Each list must have five entries. - More Details + .. rubric:: More Details Here is a diagram showing the where the names from the list - are used: + are used:: +---------+ | 0 (off) |----> (any other state and vice versa). diff --git a/direct/src/fsm/FourStateAI.py b/direct/src/fsm/FourStateAI.py index a17b9e4c62..09c83e7486 100755 --- a/direct/src/fsm/FourStateAI.py +++ b/direct/src/fsm/FourStateAI.py @@ -45,27 +45,25 @@ class FourStateAI: def __init__(self, names, durations = [0, 1, None, 1, 1]): """ - names is a list of state names - E.g. - ['off', 'opening', 'open', 'closing', 'closed',] + Names is a list of state names. Some examples are:: - e.g. 2: - ['off', 'locking', 'locked', 'unlocking', 'unlocked',] + ['off', 'opening', 'open', 'closing', 'closed',] - e.g. 3: - ['off', 'deactivating', 'deactive', 'activating', 'activated',] + ['off', 'locking', 'locked', 'unlocking', 'unlocked',] + + ['off', 'deactivating', 'deactive', 'activating', 'activated',] durations is a list of durations in seconds or None values. - The list of duration values should be the same length - as the list of state names and the lists correspond. - For each state, after n seconds, the ClassicFSM will move to - the next state. That does not happen for any duration - values of None. + The list of duration values should be the same length + as the list of state names and the lists correspond. + For each state, after n seconds, the ClassicFSM will move to + the next state. That does not happen for any duration + values of None. - More Details + .. rubric:: More Details Here is a diagram showing the where the names from the list - are used: + are used:: +---------+ | 0 (off) |----> (any other state and vice versa). diff --git a/direct/src/fsm/__init__.py b/direct/src/fsm/__init__.py index 365e539c4e..83f9f7414e 100644 --- a/direct/src/fsm/__init__.py +++ b/direct/src/fsm/__init__.py @@ -3,4 +3,7 @@ This package contains implementations of a Finite State Machine, an abstract construct that holds a particular state and can transition between several defined states. These are useful for a range of logic programming tasks. + +For more information on FSMs, consult the :ref:`finite-state-machines` section +of the programming manual. """ diff --git a/direct/src/gui/DirectDialog.py b/direct/src/gui/DirectDialog.py index ba56fdbfa0..8dd4bc51af 100644 --- a/direct/src/gui/DirectDialog.py +++ b/direct/src/gui/DirectDialog.py @@ -1,6 +1,9 @@ """This module defines various dialog windows for the DirectGUI system.""" -__all__ = ['findDialog', 'cleanupDialog', 'DirectDialog', 'OkDialog', 'OkCancelDialog', 'YesNoDialog', 'YesNoCancelDialog', 'RetryCancelDialog'] +__all__ = [ + 'findDialog', 'cleanupDialog', 'DirectDialog', 'OkDialog', + 'OkCancelDialog', 'YesNoDialog', 'YesNoCancelDialog', 'RetryCancelDialog', +] from panda3d.core import * from direct.showbase import ShowBaseGlobal @@ -9,9 +12,9 @@ from .DirectFrame import * from .DirectButton import * import types -def findDialog(uniqueName): - """findPanel(string uniqueName) +def findDialog(uniqueName): + """ Returns the panel whose uniqueName is given. This is mainly useful for debugging, to get a pointer to the current onscreen panel of a particular type. @@ -20,6 +23,7 @@ def findDialog(uniqueName): return DirectDialog.AllDialogs[uniqueName] return None + def cleanupDialog(uniqueName): """cleanupPanel(string uniqueName) @@ -35,52 +39,48 @@ def cleanupDialog(uniqueName): # self.cleanup() directly DirectDialog.AllDialogs[uniqueName].cleanup() + class DirectDialog(DirectFrame): AllDialogs = {} PanelIndex = 0 - def __init__(self, parent = None, **kw): - """ - DirectDialog(kw) - - Creates a popup dialog to alert and/or interact with user. + def __init__(self, parent=None, **kw): + """Creates a popup dialog to alert and/or interact with user. Some of the main keywords that can be used to customize the dialog: - Keyword Definition - ------- ---------- - text Text message/query displayed to user - geom Geometry to be displayed in dialog - buttonTextList List of text to show on each button - buttonGeomList List of geometry to show on each button - buttonImageList List of images to show on each button - buttonValueList List of values sent to dialog command for - each button. If value is [] then the - ordinal rank of the button is used as - its value - buttonHotKeyList List of hotkeys to bind to each button. - Typing hotkey is equivalent to pressing - the corresponding button. - suppressKeys Set to true if you wish to suppress keys - (i.e. Dialog eats key event), false if - you wish Dialog to pass along key event - buttonSize 4-tuple used to specify custom size for - each button (to make bigger then geom/text - for example) - pad Space between border and interior graphics - topPad Extra space added above text/geom/image - midPad Extra space added between text/buttons - sidePad Extra space added to either side of - text/buttons - buttonPadSF Scale factor used to expand/contract - button horizontal spacing - command Callback command used when a button is - pressed. Value supplied to command - depends on values in buttonValueList - Note: Number of buttons on the dialog depends upon the maximum - length of any button[Text|Geom|Image|Value]List specified. - Values of None are substituted for lists that are shorter - than the max length + Parameters: + text (str): Text message/query displayed to user + geom: Geometry to be displayed in dialog + buttonTextList: List of text to show on each button + buttonGeomList: List of geometry to show on each button + buttonImageList: List of images to show on each button + buttonValueList: List of values sent to dialog command for + each button. If value is [] then the ordinal rank of + the button is used as its value. + buttonHotKeyList: List of hotkeys to bind to each button. + Typing the hotkey is equivalent to pressing the + corresponding button. + suppressKeys: Set to true if you wish to suppress keys + (i.e. Dialog eats key event), false if you wish Dialog + to pass along key event. + buttonSize: 4-tuple used to specify custom size for each + button (to make bigger then geom/text for example) + pad: Space between border and interior graphics + topPad: Extra space added above text/geom/image + midPad: Extra space added between text/buttons + sidePad: Extra space added to either side of text/buttons + buttonPadSF: Scale factor used to expand/contract button + horizontal spacing + command: Callback command used when a button is pressed. + Value supplied to command depends on values in + buttonValueList. + + Note: + The number of buttons on the dialog depends on the maximum + length of any button[Text|Geom|Image|Value]List specified. + Values of None are substituted for lists that are shorter + than the max length """ # Inherits from DirectFrame diff --git a/direct/src/gui/DirectGui.py b/direct/src/gui/DirectGui.py index e0a59abb82..4b6d62b9db 100644 --- a/direct/src/gui/DirectGui.py +++ b/direct/src/gui/DirectGui.py @@ -1,4 +1,4 @@ -""" Imports all of the DirectGUI classes. """ +"""Imports all of the :ref:`directgui` classes.""" from . import DirectGuiGlobals as DGG from .OnscreenText import * diff --git a/direct/src/gui/DirectGuiBase.py b/direct/src/gui/DirectGuiBase.py index 3b47ac1973..fecfea608a 100644 --- a/direct/src/gui/DirectGuiBase.py +++ b/direct/src/gui/DirectGuiBase.py @@ -1,49 +1,57 @@ """ -Base class for all Direct Gui items. Handles composite widgets and +Base class for all DirectGui items. Handles composite widgets and command line argument parsing. -Code Overview: +Code overview: -1 Each widget defines a set of options (optiondefs) as a list of tuples - of the form ('name', defaultValue, handler). +1) Each widget defines a set of options (optiondefs) as a list of tuples + of the form ``('name', defaultValue, handler)``. 'name' is the name of the option (used during construction of configure) - handler can be: None, method, or INITOPT. If a method is specified, - it will be called during widget construction (via initialiseoptions), - if the Handler is specified as an INITOPT, this is an option that can - only be set during widget construction. + handler can be: None, method, or INITOPT. If a method is specified, it + will be called during widget construction (via initialiseoptions), if the + Handler is specified as an INITOPT, this is an option that can only be set + during widget construction. -2) DirectGuiBase.defineoptions is called. defineoption creates: +2) :func:`~DirectGuiBase.defineoptions` is called. defineoption creates: self._constructorKeywords = { keyword: [value, useFlag] } - a dictionary of the keyword options specified as part of the constructor - keywords can be of the form 'component_option', where component is - the name of a widget's component, a component group or a component alias + A dictionary of the keyword options specified as part of the + constructor keywords can be of the form 'component_option', where + component is the name of a widget's component, a component group or a + component alias. - self._dynamicGroups, a list of group names for which it is permissible - to specify options before components of that group are created. - If a widget is a derived class the order of execution would be: - foo.optiondefs = {} - foo.defineoptions() - fooParent() - fooParent.optiondefs = {} - fooParent.defineoptions() + self._dynamicGroups + A list of group names for which it is permissible to specify options + before components of that group are created. + If a widget is a derived class the order of execution would be:: -3) addoptions is called. This combines options specified as keywords to - the widget constructor (stored in self._constuctorKeywords) - with the default options (stored in optiondefs). Results are stored in - self._optionInfo = { keyword: [default, current, handler] } + foo.optiondefs = {} + foo.defineoptions() + fooParent() + fooParent.optiondefs = {} + fooParent.defineoptions() + +3) :func:`~DirectGuiBase.addoptions` is called. This combines options + specified as keywords to the widget constructor (stored in + self._constructorKeywords) with the default options (stored in optiondefs). + Results are stored in + ``self._optionInfo = { keyword: [default, current, handler] }``. If a keyword is of the form 'component_option' it is left in the self._constructorKeywords dictionary (for use by component constructors), otherwise it is 'used', and deleted from self._constructorKeywords. - Notes: - constructor keywords override the defaults. - - derived class default values override parent class defaults - - derived class handler functions override parent class functions + + Notes: + + - constructor keywords override the defaults. + - derived class default values override parent class defaults + - derived class handler functions override parent class functions 4) Superclass initialization methods are called (resulting in nested calls to define options (see 2 above) -5) Widget components are created via calls to self.createcomponent. - User can specify aliases and groups for each component created. +5) Widget components are created via calls to + :func:`~DirectGuiBase.createcomponent`. User can specify aliases and groups + for each component created. Aliases are alternate names for components, e.g. a widget may have a component with a name 'entryField', which itself may have a component @@ -55,8 +63,8 @@ Code Overview: Groups allow option specifications that apply to all members of the group. If a widget has components: 'text1', 'text2', and 'text3' which all belong to the 'text' group, they can be all configured with keywords of the form: - 'text_keyword' (e.g. text_font = 'comic.rgb'). A component's group - is stored as the fourth element of its entry in self.__componentInfo + 'text_keyword' (e.g. ``text_font='comic.rgb'``). A component's group + is stored as the fourth element of its entry in self.__componentInfo. Note: the widget constructors have access to all remaining keywords in _constructorKeywords (those not transferred to _optionInfo by @@ -71,9 +79,9 @@ Code Overview: component. If any constructor keywords remain at the end of component construction (and initialisation), an error is raised. -5) initialiseoptions is called. This method calls any option handlers to - respond to any keyword/default values, then checks to see if any keywords - are left unused. If so, an error is raised. +5) :func:`~DirectGuiBase.initialiseoptions` is called. This method calls any + option handlers to respond to any keyword/default values, then checks to + see if any keywords are left unused. If so, an error is raised. """ __all__ = ['DirectGuiBase', 'DirectGuiWidget'] diff --git a/direct/src/gui/DirectGuiGlobals.py b/direct/src/gui/DirectGuiGlobals.py index 96519fd9fc..59fd474900 100644 --- a/direct/src/gui/DirectGuiGlobals.py +++ b/direct/src/gui/DirectGuiGlobals.py @@ -17,8 +17,9 @@ drawOrder = 100 panel = None # USEFUL GUI CONSTANTS -# Constant used to indicate that an option can only be set by a call -# to the constructor. + +#: Constant used to indicate that an option can only be set by a call +#: to the constructor. INITOPT = ['initopt'] # Mouse buttons @@ -158,7 +159,3 @@ def getDefaultPanel(): def setDefaultPanel(newPanel): global panel panel = newPanel - -#from OnscreenText import * -#from OnscreenGeom import * -#from OnscreenImage import * diff --git a/direct/src/gui/OnscreenImage.py b/direct/src/gui/OnscreenImage.py index 026076fc69..3d8a9b0633 100644 --- a/direct/src/gui/OnscreenImage.py +++ b/direct/src/gui/OnscreenImage.py @@ -1,4 +1,8 @@ -"""OnscreenImage module: contains the OnscreenImage class""" +"""OnscreenImage module: contains the OnscreenImage class. + +See the :ref:`onscreenimage` page in the programming manual for explanation of +this class. +""" __all__ = ['OnscreenImage'] @@ -21,14 +25,15 @@ class OnscreenImage(DirectObject, NodePath): parent = None, sort = 0): """ - Make a image node from string or a node path, - put it into the 2d sg and set it up with all the indicated parameters. + Make a image node from string or a `~panda3d.core.NodePath`, put + it into the 2-D scene graph and set it up with all the indicated + parameters. - The parameters are as follows: + Parameters: image: the actual geometry to display or a file name. - This may be omitted and specified later via setImage() - if you don't have it available. + This may be omitted and specified later via setImage() + if you don't have it available. pos: the x, y, z position of the geometry on the screen. This maybe a 3-tuple of floats or a vector. diff --git a/direct/src/gui/OnscreenText.py b/direct/src/gui/OnscreenText.py index c3accf191d..4491c918e9 100644 --- a/direct/src/gui/OnscreenText.py +++ b/direct/src/gui/OnscreenText.py @@ -1,4 +1,8 @@ -"""OnscreenText module: contains the OnscreenText class""" +"""OnscreenText module: contains the OnscreenText class. + +See the :ref:`onscreentext` page in the programming manual for explanation of +this class. +""" __all__ = ['OnscreenText', 'Plain', 'ScreenTitle', 'ScreenPrompt', 'NameConfirm', 'BlackOnWhite'] @@ -41,7 +45,7 @@ class OnscreenText(NodePath): Make a text node from string, put it into the 2d sg and set it up with all the indicated parameters. - The parameters are as follows: + Parameters: text: the actual text to display. This may be omitted and specified later via setText() if you don't have it diff --git a/direct/src/gui/__init__.py b/direct/src/gui/__init__.py index 5cc1895b62..4e55aa3655 100644 --- a/direct/src/gui/__init__.py +++ b/direct/src/gui/__init__.py @@ -1,5 +1,5 @@ """ -This package contains the DirectGui system, a set of classes +This package contains the :ref:`directgui` system, a set of classes responsible for drawing graphical widgets to the 2-D scene graph. It is based on the lower-level PGui system, which is implemented in diff --git a/direct/src/interval/ActorInterval.py b/direct/src/interval/ActorInterval.py index 6ac026497b..8d5044c2b5 100644 --- a/direct/src/interval/ActorInterval.py +++ b/direct/src/interval/ActorInterval.py @@ -1,4 +1,8 @@ -"""ActorInterval module: contains the ActorInterval class""" +"""ActorInterval module: contains the ActorInterval class. + +See the :ref:`actor-intervals` page in the programming manual for explanation +of this class. +""" __all__ = ['ActorInterval', 'LerpAnimInterval'] diff --git a/direct/src/interval/ParticleInterval.py b/direct/src/interval/ParticleInterval.py index b5a3b09b73..de1f533b63 100644 --- a/direct/src/interval/ParticleInterval.py +++ b/direct/src/interval/ParticleInterval.py @@ -34,26 +34,22 @@ class ParticleInterval(Interval): cleanup = False, name = None): """ - particleEffect is a ParticleEffect - parent is a NodePath: this is where the effect will be - parented in the scenegraph - worldRelative is a boolean: this will override 'renderParent' - with render - renderParent is a NodePath: this is where the particles will - be rendered in the scenegraph - duration is a float: for the time - softStopT is a float: no effect if 0.0, - a positive value will count from the - start of the interval, - a negative value will count from the - end of the interval - cleanup is a boolean: if True the effect will be destroyed - and removed from the scenegraph upon - interval completion - set to False if planning on reusing - the interval - name is a string: use this for unique intervals so that - they can be easily found in the taskMgr + Args: + particleEffect (ParticleEffect): a particle effect + parent (NodePath): this is where the effect will be parented in the + scene graph + worldRelative (bool): this will override 'renderParent' with render + renderParent (NodePath): this is where the particles will be + rendered in the scenegraph + duration (float): for the time + softStopT (float): no effect if 0.0, a positive value will count + from the start of the interval, a negative value will count + from the end of the interval + cleanup (boolean): if True the effect will be destroyed and removed + from the scenegraph upon interval completion. Set to False if + planning on reusing the interval. + name (string): use this for unique intervals so that they can be + easily found in the taskMgr. """ # Generate unique name diff --git a/direct/src/interval/__init__.py b/direct/src/interval/__init__.py index 5f3e8e4332..46dc3f0c2a 100644 --- a/direct/src/interval/__init__.py +++ b/direct/src/interval/__init__.py @@ -9,4 +9,6 @@ All interval types can be conveniently imported from the :mod:`.IntervalGlobal` module:: from direct.interval.IntervalGlobal import * + +For more information about intervals, see the :ref:`intervals` manual page. """ diff --git a/direct/src/p3d/AppRunner.py b/direct/src/p3d/AppRunner.py index aae03754e6..9a5e1a7948 100644 --- a/direct/src/p3d/AppRunner.py +++ b/direct/src/p3d/AppRunner.py @@ -10,6 +10,10 @@ The global AppRunner instance may be imported as follows:: from direct.showbase.AppRunnerGlobal import appRunner This will be None if Panda was not run from the runtime environment. + +.. deprecated:: 1.10.0 + The p3d packaging system has been replaced with the new setuptools-based + system. See the :ref:`distribution` manual section. """ __all__ = ["AppRunner", "dummyAppRunner", "ArgumentError"] diff --git a/direct/src/p3d/DeploymentTools.py b/direct/src/p3d/DeploymentTools.py index ebc20bfda9..12b90a080c 100644 --- a/direct/src/p3d/DeploymentTools.py +++ b/direct/src/p3d/DeploymentTools.py @@ -1,6 +1,11 @@ """ This module is used to build a graphical installer or a standalone executable from a p3d file. It will try -to build for as many platforms as possible. """ +to build for as many platforms as possible. + +.. deprecated:: 1.10.0 + The p3d packaging system has been replaced with the new setuptools-based + system. See the :ref:`distribution` manual section. +""" __all__ = ["Standalone", "Installer"] diff --git a/direct/src/p3d/JavaScript.py b/direct/src/p3d/JavaScript.py index b59deb1aa2..5c08039086 100644 --- a/direct/src/p3d/JavaScript.py +++ b/direct/src/p3d/JavaScript.py @@ -1,6 +1,10 @@ """ This module defines some simple classes and instances which are useful when writing code that integrates with JavaScript, especially -code that runs in a browser via the web plugin. """ +code that runs in a browser via the web plugin. + +.. deprecated:: 1.10.0 + The browser plug-in is no longer supported. +""" __all__ = ["UndefinedObject", "Undefined", "ConcreteStruct", "BrowserObject", "MethodWrapper"] diff --git a/direct/src/p3d/Packager.py b/direct/src/p3d/Packager.py index 4e8a303f7f..07c8a56425 100644 --- a/direct/src/p3d/Packager.py +++ b/direct/src/p3d/Packager.py @@ -1,7 +1,12 @@ """ This module is used to build a "Package", a collection of files within a Panda3D Multifile, which can be easily be downloaded and/or patched onto a client machine, for the purpose of running a large -application. """ +application. + +.. deprecated:: 1.10.0 + The p3d packaging system has been replaced with the new setuptools-based + system. See the :ref:`distribution` manual section. +""" __all__ = ["Packager", "PackagerError", "OutsideOfPackageError", "ArgumentError"] @@ -3926,21 +3931,22 @@ class metaclass_def(type): return type.__new__(self, name, bases, dict) + # Define these dynamically to stay compatible with Python 2 and 3. class_p3d = metaclass_def(str('class_p3d'), (), {}) class_package = metaclass_def(str('class_package'), (), {}) class_solo = metaclass_def(str('class_solo'), (), {}) -class func_closure: +class func_closure: """ This class is used to create a closure on the function name, - and also allows the *args, **kw syntax. In Python, the lambda + and also allows the ``*args, **kw`` syntax. In Python, the lambda syntax, used with default parameters, is used more often to create a closure (that is, a binding of one or more variables into a - callable object), but that syntax doesn't work with **kw. + callable object), but that syntax doesn't work with ``**kw``. Fortunately, a class method is also a form of a closure, because it binds self; and this doesn't have any syntax problems with - **kw. """ + ``**kw``. """ def __init__(self, name): self.name = name diff --git a/direct/src/p3d/__init__.py b/direct/src/p3d/__init__.py index e6ab93b09d..ee0bdf6fb0 100644 --- a/direct/src/p3d/__init__.py +++ b/direct/src/p3d/__init__.py @@ -1,4 +1,8 @@ """ This package provides the Python interface to functionality relating to the Panda3D Runtime environment. + +.. deprecated:: 1.10.0 + The p3d packaging system has been replaced with the new setuptools-based + system. See the :ref:`distribution` manual section. """ diff --git a/direct/src/particles/Particles.py b/direct/src/particles/Particles.py index d05700c3b1..adbfc8bf3f 100644 --- a/direct/src/particles/Particles.py +++ b/direct/src/particles/Particles.py @@ -1,3 +1,9 @@ +"""The Python specialization of the particle system. + +See the :ref:`particle-effects` section in the manual for an explanation +of the particle system. +""" + from panda3d.core import * from panda3d.physics import PhysicalNode @@ -29,6 +35,7 @@ from . import SpriteParticleRendererExt from direct.directnotify.DirectNotifyGlobal import directNotify import sys + class Particles(ParticleSystem): notify = directNotify.newCategory('Particles') id = 1 @@ -575,7 +582,6 @@ class Particles(ParticleSystem): return dict(zip(('min','median','max'),[l*s/b for l,s,b in zip(litterRange,lifespanRange,birthRateRange)])) - def accelerate(self,time,stepCount = 1,stepTime=0.0): if time > 0.0: if stepTime == 0.0: diff --git a/direct/src/particles/__init__.py b/direct/src/particles/__init__.py index d3525ee464..f739d016c1 100644 --- a/direct/src/particles/__init__.py +++ b/direct/src/particles/__init__.py @@ -4,4 +4,7 @@ system. Also see the :mod:`panda3d.physics` module, which contains the C++ implementation of the particle system. + +For more information about the particle system, see the :ref:`particle-effects` +page in the manual. """ diff --git a/direct/src/showbase/AppRunnerGlobal.py b/direct/src/showbase/AppRunnerGlobal.py index 2ab5c0ccf9..facb0add07 100644 --- a/direct/src/showbase/AppRunnerGlobal.py +++ b/direct/src/showbase/AppRunnerGlobal.py @@ -4,8 +4,13 @@ runp3d.py or via the Panda3D plugin or standalone executable. This is needed for apps that start themselves by importing DirectStart; it provides a place for these apps to look for -the AppRunner at startup. """ +the AppRunner at startup. -#: Contains the global AppRunner instance, or None if this application -#: was not run from the runtime environment. +.. deprecated:: 1.10.0 + The p3d packaging system has been replaced with the new setuptools-based + system. See the :ref:`distribution` manual section. +""" + +#: Contains the global :class:`~.AppRunner.AppRunner` instance, or None +#: if this application was not run from the runtime environment. appRunner = None diff --git a/direct/src/showbase/BufferViewer.py b/direct/src/showbase/BufferViewer.py index 48dff3a1ea..ec46e0ff62 100644 --- a/direct/src/showbase/BufferViewer.py +++ b/direct/src/showbase/BufferViewer.py @@ -1,6 +1,16 @@ """Contains the BufferViewer class, which is used as a debugging aid when debugging render-to-texture effects. It shows different views at -the bottom of the screen showing the various render targets.""" +the bottom of the screen showing the various render targets. + +When using ShowBase, the normal way to enable the BufferViewer is using the +following code:: + + base.bufferViewer.toggleEnable() + +Or, you can enable the following variable in your Config.prc:: + + show-buffers true +""" __all__ = ['BufferViewer'] @@ -11,6 +21,7 @@ from direct.directnotify.DirectNotifyGlobal import * from direct.showbase.DirectObject import DirectObject import math + class BufferViewer(DirectObject): notify = directNotify.newCategory('BufferViewer') @@ -100,11 +111,13 @@ class BufferViewer(DirectObject): def setPosition(self, pos): """Set the position of the cards. The valid values are: - * llcorner - put them in the lower-left corner of the window - * lrcorner - put them in the lower-right corner of the window - * ulcorner - put them in the upper-left corner of the window - * urcorner - put them in the upper-right corner of the window - * window - put them in a separate window + + - *llcorner* - put them in the lower-left corner of the window + - *lrcorner* - put them in the lower-right corner of the window + - *ulcorner* - put them in the upper-left corner of the window + - *urcorner* - put them in the upper-right corner of the window + - *window* - put them in a separate window + The initial value is 'lrcorner'.""" valid=["llcorner","lrcorner","ulcorner","urcorner","window"] if (valid.count(pos)==0): @@ -119,11 +132,13 @@ class BufferViewer(DirectObject): def setLayout(self, lay): """Set the layout of the cards. The valid values are: - * vline - display them in a vertical line - * hline - display them in a horizontal line - * vgrid - display them in a vertical grid - * hgrid - display them in a horizontal grid - * cycle - display one card at a time, using selectCard/advanceCard + + - *vline* - display them in a vertical line + - *hline* - display them in a horizontal line + - *vgrid* - display them in a vertical grid + - *hgrid* - display them in a horizontal grid + - *cycle* - display one card at a time, using selectCard/advanceCard + The default value is 'hline'.""" valid=["vline","hline","vgrid","hgrid","cycle"] if (valid.count(lay)==0): diff --git a/direct/src/showbase/BulletinBoardGlobal.py b/direct/src/showbase/BulletinBoardGlobal.py index dd750d9a22..1dd41e9a24 100755 --- a/direct/src/showbase/BulletinBoardGlobal.py +++ b/direct/src/showbase/BulletinBoardGlobal.py @@ -1,7 +1,8 @@ -"""instantiate global BulletinBoard object""" +"""Instantiates the global :class:`~.BulletinBoard.BulletinBoard` object.""" __all__ = ['bulletinBoard'] from . import BulletinBoard +#: The global :class:`~.BulletinBoard.BulletinBoard` object. bulletinBoard = BulletinBoard.BulletinBoard() diff --git a/direct/src/showbase/DistancePhasedNode.py b/direct/src/showbase/DistancePhasedNode.py index a1bd879af0..385f94ae70 100755 --- a/direct/src/showbase/DistancePhasedNode.py +++ b/direct/src/showbase/DistancePhasedNode.py @@ -3,16 +3,18 @@ from direct.directnotify.DirectNotifyGlobal import directNotify from panda3d.core import * from .PhasedObject import PhasedObject + class DistancePhasedNode(PhasedObject, DirectObject, NodePath): """ - This class defines a PhasedObject,NodePath object that will handle the phasing - of an object in the scene graph according to its distance from some - other collider object(such as an avatar). + This class defines a PhasedObject,NodePath object that will handle + the phasing of an object in the scene graph according to its + distance from some other collider object(such as an avatar). Since it's a NodePath, you can parent it to another object in the scene graph, or even inherit from this class to get its functionality. What you will need to define to use this class: + - The distances at which you want the phases to load/unload - Whether you want the object to clean itself up or not when exitting the largest distance sphere @@ -22,14 +24,14 @@ class DistancePhasedNode(PhasedObject, DirectObject, NodePath): - (Optional) A 'from' collision node to collide into our 'into' spheres You specify the distances and function names by the phaseParamMap - parameter to __init__(). For example: + parameter to `__init__()`. For example:: - phaseParamMap = {'Alias': distance, ...} - ... - def loadPhaseAlias(self): - pass - def unloadPhaseAlias(self): - pass + phaseParamMap = {'Alias': distance, ...} + ... + def loadPhaseAlias(self): + pass + def unloadPhaseAlias(self): + pass If the 'fromCollideNode' is supplied, we will set up our own traverser and only traverse below this node. It will send out @@ -40,14 +42,15 @@ class DistancePhasedNode(PhasedObject, DirectObject, NodePath): Most of the time, it will be reacting to events from the main collision traverser. - IMPORTANT!: The following only applies when autoCleanup == True: - If you unload the last phase, by either calling - cleanup() or by exitting the last phase's distance, - you will need to explicitly call reset() to get the - distance phasing to work again. This was done so if - either this node or the collider is removed from the - scene graph(eg. avatar teleport), the phased object - will clean itself up automatically. + IMPORTANT: + + The following only applies when ``autoCleanup is True``: + If you unload the last phase, by either calling `cleanup()` or + by exiting the last phase's distance, you will need to + explicitly call `reset()` to get the distance phasing to work + again. This was done so if either this node or the collider is + removed from the scene graph (e.g. avatar teleport), the phased + object will clean itself up automatically. """ notify = directNotify.newCategory("DistancePhasedObject") @@ -118,7 +121,6 @@ class DistancePhasedNode(PhasedObject, DirectObject, NodePath): def __str__(self): return '%s in phase \'%s\'' % (NodePath.__str__(self), self.getPhase()) - def cleanup(self): """ Disables all collisions. @@ -262,9 +264,9 @@ class BufferedDistancePhasedNode(DistancePhasedNode): border. You specify the buffer amount in the bufferParamMap parameter - to __init__(). It has this format: + to :meth:`__init__()`. It has this format:: - bufferParamMap = {'alias':(distance, bufferAmount), ...} + bufferParamMap = {'alias':(distance, bufferAmount), ...} """ notify = directNotify.newCategory("BufferedDistancePhasedObject") diff --git a/direct/src/showbase/ExceptionVarDump.py b/direct/src/showbase/ExceptionVarDump.py index 42aca9b7c9..90fa052a0c 100755 --- a/direct/src/showbase/ExceptionVarDump.py +++ b/direct/src/showbase/ExceptionVarDump.py @@ -179,6 +179,7 @@ def _excepthookDumpVars(eType, eValue, tb): oldExcepthook(eType, eValue, origTb) def install(log, upload): + """Installs the exception hook.""" global oldExcepthook global wantStackDumpLog global wantStackDumpUpload diff --git a/direct/src/showbase/GarbageReportScheduler.py b/direct/src/showbase/GarbageReportScheduler.py index 4705cd3344..e26da9ccc5 100755 --- a/direct/src/showbase/GarbageReportScheduler.py +++ b/direct/src/showbase/GarbageReportScheduler.py @@ -1,7 +1,9 @@ from direct.showbase.GarbageReport import GarbageReport + class GarbageReportScheduler: - # runs a garbage report every once in a while and logs the results + """Runs a garbage report every once in a while and logs the results.""" + def __init__(self, waitBetween=None, waitScale=None): # waitBetween is in seconds # waitScale is a multiplier for the waitBetween every time around @@ -30,6 +32,7 @@ class GarbageReportScheduler: self._taskName) # and increase the delay every time around self._waitBetween = self._waitBetween * self._waitScale + def _runGarbageReport(self, task): # run a garbage report and schedule the next one after this one finishes # give this job 3 times as many timeslices as normal-priority jobs diff --git a/direct/src/showbase/InputStateGlobal.py b/direct/src/showbase/InputStateGlobal.py index ff04825133..802e77e089 100644 --- a/direct/src/showbase/InputStateGlobal.py +++ b/direct/src/showbase/InputStateGlobal.py @@ -1,4 +1,4 @@ -"""instantiate global InputState object""" +"""Instantiates the global :class:`~.InputState.InputState` object.""" __all__ = ['inputState'] @@ -7,4 +7,5 @@ __all__ = ['inputState'] from direct.controls import InputState +#: The global :class:`~.InputState.InputState` object. inputState = InputState.InputState() diff --git a/direct/src/showbase/Job.py b/direct/src/showbase/Job.py index 02407b29c4..01b7a0c8b7 100755 --- a/direct/src/showbase/Job.py +++ b/direct/src/showbase/Job.py @@ -3,14 +3,22 @@ from direct.showbase.DirectObject import DirectObject if __debug__: from panda3d.core import PStatCollector -class Job(DirectObject): - # Base class for cpu-intensive or non-time-critical operations that - # are run through the JobManager. - # values to yield from your run() generator method +class Job(DirectObject): + """Base class for cpu-intensive or non-time-critical operations that + are run through the :class:`.JobManager`. + + To use, subclass and override the `run()` method. + """ + + #: Yielded from the `run()` generator method when the job is done. Done = object() - Continue = None # 'yield None' is acceptable in place of 'yield Job.Continue' - Sleep = object() # yield any remaining time for this job until next frame + + #: ``yield None`` is acceptable in place of ``yield Job.Continue`` + Continue = None + + #: Yield any remaining time for this job until next frame. + Sleep = object() # These priorities determine how many timeslices a job gets relative to other # jobs. A job with priority of 1000 will run 10 times more often than a job @@ -37,13 +45,14 @@ class Job(DirectObject): return 'job-finished-%s' % self._id def run(self): - # this is a generator - # override and do your processing - # yield Job.Continue when possible/reasonable - # try not to run longer than the JobManager's timeslice between yields - # - # when done, yield Job.Done - # + """This should be overridden with a generator that does the + needful processing. + + yield `Job.Continue` when possible/reasonable, and try not to run + longer than the JobManager's timeslice between yields. + + When done, yield `Job.Done`. + """ raise NotImplementedError("don't call down") def getPriority(self): @@ -57,23 +66,22 @@ class Job(DirectObject): self._printing = False def resume(self): - # called every time JobManager is going to start running this job - """ - if self._printing: - # we may be suspended/resumed multiple times per frame, that gets spammy - # if we need to pick out the output of a job, put a prefix onto each line - # of the output - print 'JOB:%s:RESUME' % self._name - """ - pass + """Called every time JobManager is going to start running this job.""" + #if self._printing: + # # we may be suspended/resumed multiple times per frame, that gets spammy + # # if we need to pick out the output of a job, put a prefix onto each line + # # of the output + # print('JOB:%s:RESUME' % self._name) + def suspend(self): - # called when JobManager is going to stop running this job for a while + """Called when JobManager is going to stop running this job for a + while. """ - if self._printing: - #print 'JOB:%s:SUSPEND' % self._name - pass - """ - pass + + #if self._printing: + # #print('JOB:%s:SUSPEND' % self._name) + # pass + # """ def _setFinished(self): self._finished = True diff --git a/direct/src/showbase/JobManagerGlobal.py b/direct/src/showbase/JobManagerGlobal.py index 767f4ce342..4952a31462 100755 --- a/direct/src/showbase/JobManagerGlobal.py +++ b/direct/src/showbase/JobManagerGlobal.py @@ -2,4 +2,5 @@ __all__ = ['jobMgr'] from . import JobManager +#: Contains the global :class:`~.JobManager.JobManager` object. jobMgr = JobManager.JobManager() diff --git a/direct/src/showbase/LeakDetectors.py b/direct/src/showbase/LeakDetectors.py index 38d45d225b..b2a17b5617 100755 --- a/direct/src/showbase/LeakDetectors.py +++ b/direct/src/showbase/LeakDetectors.py @@ -1,4 +1,6 @@ -# objects that report different types of leaks to the ContainerLeakDetector +"""Contains objects that report different types of leaks to the +ContainerLeakDetector. +""" from panda3d.core import * from direct.showbase.DirectObject import DirectObject diff --git a/direct/src/showbase/Loader.py b/direct/src/showbase/Loader.py index 988982ab28..f0afbc06ec 100644 --- a/direct/src/showbase/Loader.py +++ b/direct/src/showbase/Loader.py @@ -1,4 +1,6 @@ -"""Loader module: contains the Loader class""" +"""This module contains a high-level interface for loading models, textures, +sound, music, shaders and fonts from disk. +""" __all__ = ['Loader'] diff --git a/direct/src/showbase/Messenger.py b/direct/src/showbase/Messenger.py index f1b7bcc1a7..c8d72cb6b4 100644 --- a/direct/src/showbase/Messenger.py +++ b/direct/src/showbase/Messenger.py @@ -1,5 +1,6 @@ """This defines the Messenger class, which is responsible for most of the -event handling that happens on the Python side.""" +event handling that happens on the Python side. +""" __all__ = ['Messenger'] @@ -10,26 +11,28 @@ import types from direct.stdpy.threading import Lock + class Messenger: notify = DirectNotifyGlobal.directNotify.newCategory("Messenger") def __init__(self): """ - One is keyed off the event name. It has the following structure: + One is keyed off the event name. It has the following structure:: + {event1: {object1: [method, extraArgs, persistent], object2: [method, extraArgs, persistent]}, event2: {object1: [method, extraArgs, persistent], object2: [method, extraArgs, persistent]}} - This dictionary allow for efficient callbacks when the messenger - hears an event. + This dictionary allows for efficient callbacks when the + messenger hears an event. A second dictionary remembers which objects are accepting which events. This allows for efficient ignoreAll commands. + Or, for an example with more real data:: - Or, for an example with more real data: {'mouseDown': {avatar: [avatar.jump, [2.0], 1]}} """ # eventName->objMsgrId->callbackInfo @@ -281,20 +284,20 @@ class Messenger: """ return (not self.isAccepting(event, object)) - def send(self, event, sentArgs=[], taskChain = None): + def send(self, event, sentArgs=[], taskChain=None): """ - Send this event, optionally passing in arguments + Send this event, optionally passing in arguments. - event is usually a string. - sentArgs is a list of any data that you want passed along to the - handlers listening to this event. - - If taskChain is not None, it is the name of the task chain - which should receive the event. If taskChain is None, the - event is handled immediately. Setting a non-None taskChain - will defer the event (possibly till next frame or even later) - and create a new, temporary task within the named taskChain, - but this is the only way to send an event across threads. + Args: + event (str): The name of the event. + sentArgs (list): A list of arguments to be passed along to the + handlers listening to this event. + taskChain (str, optional): If not None, the name of the task chain + which should receive the event. If None, then the event is + handled immediately. Setting a non-None taskChain will defer + the event (possibly till next frame or even later) and create a + new, temporary task within the named taskChain, but this is the + only way to send an event across threads. """ if Messenger.notify.getDebug() and not self.quieting.get(event): assert Messenger.notify.debug( @@ -485,7 +488,7 @@ class Messenger: This is intended for debugging use only. This function is not defined if python is ran with -O (optimize). - See Also: unwatch + See Also: `unwatch` """ if not self.__watching.get(needle): self.__isWatching += 1 @@ -499,7 +502,7 @@ class Messenger: This is intended for debugging use only. This function is not defined if python is ran with -O (optimize). - See Also: watch + See Also: `watch` """ if self.__watching.get(needle): self.__isWatching -= 1 @@ -514,7 +517,7 @@ class Messenger: This is intended for debugging use only. This function is not defined if python is ran with -O (optimize). - See Also: unquiet + See Also: `unquiet` """ if not self.quieting.get(message): self.quieting[message]=1 @@ -528,7 +531,7 @@ class Messenger: This is intended for debugging use only. This function is not defined if python is ran with -O (optimize). - See Also: quiet + See Also: `quiet` """ if self.quieting.get(message): del self.quieting[message] @@ -658,4 +661,3 @@ class Messenger: detailed_repr = detailedRepr get_all_accepting = getAllAccepting toggle_verbose = toggleVerbose - diff --git a/direct/src/showbase/MessengerGlobal.py b/direct/src/showbase/MessengerGlobal.py index f5a534c0d1..ba516ab38d 100644 --- a/direct/src/showbase/MessengerGlobal.py +++ b/direct/src/showbase/MessengerGlobal.py @@ -1,7 +1,8 @@ -"""instantiate global Messenger object""" +"""Instantiates the global :class:`~.Messenger.Messenger` object.""" __all__ = ['messenger'] from . import Messenger +#: Contains the global :class:`~.Messenger.Messenger` instance. messenger = Messenger.Messenger() diff --git a/direct/src/showbase/MirrorDemo.py b/direct/src/showbase/MirrorDemo.py index 0c5090cbc4..1e43f7621b 100755 --- a/direct/src/showbase/MirrorDemo.py +++ b/direct/src/showbase/MirrorDemo.py @@ -1,5 +1,5 @@ """This file demonstrates one way to create a mirror effect in Panda. -Call setupMirror() to create a mirror in the world that reflects +Call :func:`setupMirror()` to create a mirror in the world that reflects everything in front of it. The approach taken here is to create an offscreen buffer with its own diff --git a/direct/src/showbase/PhysicsManagerGlobal.py b/direct/src/showbase/PhysicsManagerGlobal.py index 9be21b6060..f1c3d51dc6 100644 --- a/direct/src/showbase/PhysicsManagerGlobal.py +++ b/direct/src/showbase/PhysicsManagerGlobal.py @@ -1,7 +1,8 @@ -"""PhysicsManagerGlobal module: contains the global physics manager""" +"""Instantiates the global :class:`~panda3d.physics.PhysicsManager` object.""" __all__ = ['physicsMgr'] from panda3d.physics import PhysicsManager +#: Contains the global :class:`~panda3d.physics.PhysicsManager` instance. physicsMgr = PhysicsManager() diff --git a/direct/src/showbase/Pool.py b/direct/src/showbase/Pool.py index 5c1782d629..9c11979c6a 100755 --- a/direct/src/showbase/Pool.py +++ b/direct/src/showbase/Pool.py @@ -7,11 +7,13 @@ or be the same type. Internally the pool is implemented with 2 lists, free items and used items. -Example:: +Example: - p = Pool([1, 2, 3, 4, 5]) - x = p.checkout() - p.checkin(x) + .. code-block:: python + + p = Pool([1, 2, 3, 4, 5]) + x = p.checkout() + p.checkin(x) """ @@ -20,6 +22,7 @@ __all__ = ['Pool'] from direct.directnotify import DirectNotifyGlobal + class Pool: notify = DirectNotifyGlobal.directNotify.newCategory("Pool") diff --git a/direct/src/showbase/PythonUtil.py b/direct/src/showbase/PythonUtil.py index fbef9ecc70..7af79603b3 100644 --- a/direct/src/showbase/PythonUtil.py +++ b/direct/src/showbase/PythonUtil.py @@ -1,36 +1,35 @@ """Contains miscellaneous utility functions and classes.""" -__all__ = ['indent', -'doc', 'adjust', 'difference', 'intersection', 'union', -'sameElements', 'makeList', 'makeTuple', 'list2dict', 'invertDict', -'invertDictLossless', 'uniqueElements', 'disjoint', 'contains', -'replace', 'reduceAngle', 'fitSrcAngle2Dest', 'fitDestAngle2Src', -'closestDestAngle2', 'closestDestAngle', 'getSetterName', -'getSetter', 'Functor', 'Stack', 'Queue', -'bound', 'clamp', 'lerp', 'average', 'addListsByValue', -'boolEqual', 'lineupPos', 'formatElapsedSeconds', 'solveQuadratic', -'findPythonModule', 'mostDerivedLast', -'clampScalar', 'weightedChoice', 'randFloat', 'normalDistrib', -'weightedRand', 'randUint31', 'randInt32', -'SerialNumGen', 'serialNum', 'uniqueName', 'Enum', 'Singleton', -'SingletonError', 'printListEnum', 'safeRepr', -'fastRepr', 'isDefaultValue', -'ScratchPad', 'Sync', 'itype', 'getNumberedTypedString', -'getNumberedTypedSortedString', -'printNumberedTyped', 'DelayedCall', 'DelayedFunctor', -'FrameDelayedCall', 'SubframeCall', 'getBase', 'GoldenRatio', -'GoldenRectangle', 'rad90', 'rad180', 'rad270', 'rad360', -'nullGen', 'loopGen', 'makeFlywheelGen', 'flywheel', -'listToIndex2item', 'listToItem2index', -'formatTimeCompact','deeptype','StdoutCapture','StdoutPassthrough', -'Averager', 'getRepository', 'formatTimeExact', 'startSuperLog', 'endSuperLog', -'typeName', 'safeTypeName', 'histogramDict', 'unescapeHtmlString'] +__all__ = [ + + 'indent', 'doc', 'adjust', 'difference', 'intersection', 'union', + 'sameElements', 'makeList', 'makeTuple', 'list2dict', 'invertDict', + 'invertDictLossless', 'uniqueElements', 'disjoint', 'contains', 'replace', + 'reduceAngle', 'fitSrcAngle2Dest', 'fitDestAngle2Src', 'closestDestAngle2', + 'closestDestAngle', 'getSetterName', 'getSetter', 'Functor', 'Stack', + 'Queue', 'bound', 'clamp', 'lerp', 'average', 'addListsByValue', + 'boolEqual', 'lineupPos', 'formatElapsedSeconds', 'solveQuadratic', + 'findPythonModule', 'mostDerivedLast', 'clampScalar', 'weightedChoice', + 'randFloat', 'normalDistrib', 'weightedRand', 'randUint31', 'randInt32', + 'SerialNumGen', 'serialNum', 'uniqueName', 'Enum', 'Singleton', + 'SingletonError', 'printListEnum', 'safeRepr', 'fastRepr', + 'isDefaultValue', 'ScratchPad', 'Sync', 'itype', 'getNumberedTypedString', + 'getNumberedTypedSortedString', 'printNumberedTyped', 'DelayedCall', + 'DelayedFunctor', 'FrameDelayedCall', 'SubframeCall', 'getBase', + 'GoldenRatio', 'GoldenRectangle', 'rad90', 'rad180', 'rad270', 'rad360', + 'nullGen', 'loopGen', 'makeFlywheelGen', 'flywheel', 'listToIndex2item', + 'listToItem2index', 'formatTimeCompact', 'deeptype', 'StdoutCapture', + 'StdoutPassthrough', 'Averager', 'getRepository', 'formatTimeExact', + 'startSuperLog', 'endSuperLog', 'typeName', 'safeTypeName', + 'histogramDict', 'unescapeHtmlString', +] if __debug__: - __all__ += ['StackTrace', 'traceFunctionCall', 'traceParentCall', 'printThisCall', - 'stackEntryInfo', 'lineInfo', 'callerInfo', 'lineTag', - 'profileFunc', 'profiled', 'startProfile', 'printProfile', - 'getProfileResultString', 'printStack', 'printReverseStack'] + __all__ += ['StackTrace', 'traceFunctionCall', 'traceParentCall', + 'printThisCall', 'stackEntryInfo', 'lineInfo', 'callerInfo', + 'lineTag', 'profileFunc', 'profiled', 'startProfile', + 'printProfile', 'getProfileResultString', 'printStack', + 'printReverseStack'] import types import math @@ -652,13 +651,15 @@ if __debug__: """ decorator for profiling functions turn categories on and off via "want-profile-categoryName 1" - e.g. + e.g.:: - @profiled('particles') - def loadParticles(): - ... + @profiled('particles') + def loadParticles(): + ... - want-profile-particles 1 + :: + + want-profile-particles 1 """ assert type(category) in (str, type(None)), "must provide a category name for @profiled" @@ -1195,13 +1196,14 @@ def normalDistrib(a, b, gauss=random.gauss): def weightedRand(valDict, rng=random.random): """ - pass in a dictionary with a selection -> weight mapping. Eg. - {"Choice 1": 10, - "Choice 2": 30, - "bear": 100} + pass in a dictionary with a selection -> weight mapping. E.g.:: - -Weights need not add up to any particular value. - -The actual selection will be returned. + {"Choice 1": 10, + "Choice 2": 30, + "bear": 100} + + - Weights need not add up to any particular value. + - The actual selection will be returned. """ selections = list(valDict.keys()) weights = list(valDict.values()) @@ -1997,42 +1999,42 @@ def report(types = [], prefix = '', xform = None, notifyFunc = None, dConfigPara has no effect and no wrapping/transform occurs. So in production, it's as if the report has been asserted out. - Parameters:: - types : A subset list of ['timeStamp', 'frameCount', 'avLocation'] - This allows you to specify certain useful bits of info. + Parameters: + types: A subset list of ['timeStamp', 'frameCount', 'avLocation'] + This allows you to specify certain useful bits of info: - module: Prints the module that this report statement - can be found in. - args: Prints the arguments as they were passed to - this function. - timeStamp: Adds the current frame time to the output. - deltaStamp: Adds the current AI synched frame time to - the output - frameCount: Adds the current frame count to the output. - Usually cleaner than the timeStamp output. - avLocation: Adds the localAvatar's network location - to the output. Useful for interest debugging. - interests: Prints the current interest state after the - report. - stackTrace: Prints a stack trace after the report. + - *module*: Prints the module that this report statement + can be found in. + - *args*: Prints the arguments as they were passed to this + function. + - *timeStamp*: Adds the current frame time to the output. + - *deltaStamp*: Adds the current AI synched frame time to + the output + - *frameCount*: Adds the current frame count to the output. + Usually cleaner than the timeStamp output. + - *avLocation*: Adds the localAvatar's network location to + the output. Useful for interest debugging. + - *interests*: Prints the current interest state after the + report. + - *stackTrace*: Prints a stack trace after the report. - prefix: Optional string to prepend to output, just before the function. - Allows for easy grepping and is useful when merging AI/Client - reports into a single file. + prefix: Optional string to prepend to output, just before the + function. Allows for easy grepping and is useful when + merging AI/Client reports into a single file. - xform: Optional callback that accepts a single parameter: argument 0 to - the decorated function. (assumed to be 'self') - It should return a value to be inserted into the report output string. + xform: Optional callback that accepts a single parameter: + argument 0 to the decorated function. (assumed to be 'self') + It should return a value to be inserted into the report + output string. - notifyFunc: A notify function such as info, debug, warning, etc. - By default the report will be printed to stdout. This - will allow you send the report to a designated 'notify' - output. + notifyFunc: A notify function such as info, debug, warning, etc. + By default the report will be printed to stdout. This will + allow you send the report to a designated 'notify' output. - dConfigParam: A list of Config.prc string variables. - By default the report will always print. If you - specify this param, it will only print if one of the - specified config strings resolve to True. + dConfigParam: A list of Config.prc string variables. + By default the report will always print. If you specify + this param, it will only print if one of the specified + config strings resolve to True. """ diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index f79d1a68c5..e79cc31751 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -61,7 +61,19 @@ class ShowBase(DirectObject.DirectObject): config = DConfig notify = directNotify.newCategory("ShowBase") - def __init__(self, fStartDirect = True, windowType = None): + def __init__(self, fStartDirect=True, windowType=None): + """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. + + To prevent a window from being opened, set windowType to the string + 'none' (or 'offscreen' to create an offscreen buffer). If this is not + specified, the default value is taken from the 'window-type' + configuration variable. + + This constructor will add various things to the Python builtins scope, + including this instance itself (under the name ``base``). + """ + self.__dev__ = self.config.GetBool('want-dev', __debug__) builtins.__dev__ = self.__dev__ @@ -1854,6 +1866,7 @@ class ShowBase(DirectObject.DirectObject): self.notify.debug("Disabling music") def SetAllSfxEnables(self, bEnabled): + """Calls ``setActive(bEnabled)`` on all valid SFX managers.""" for i in range(len(self.sfxManagerList)): if (self.sfxManagerIsValidList[i]): self.sfxManagerList[i].setActive(bEnabled) @@ -2587,9 +2600,9 @@ class ShowBase(DirectObject.DirectObject): sourceLens = None): """ - Similar to screenshot(), this sets up a temporary cube map - Texture which it uses to take a series of six snapshots of the - current scene, one in each of the six cube map directions. + Similar to :meth:`screenshot()`, this sets up a temporary cube + map Texture which it uses to take a series of six snapshots of + the current scene, one in each of the six cube map directions. This requires rendering a new frame. Unlike screenshot(), source may only be a GraphicsWindow, @@ -2651,19 +2664,19 @@ class ShowBase(DirectObject.DirectObject): cameraMask = PandaNode.getAllCameraMask(), numVertices = 1000, sourceLens = None): """ - This works much like saveCubeMap(), and uses the graphics - API's hardware cube-mapping ability to get a 360-degree view - of the world. But then it converts the six cube map faces - into a single fisheye texture, suitable for applying as a - static environment map (sphere map). + This works much like :meth:`saveCubeMap()`, and uses the + graphics API's hardware cube-mapping ability to get a 360-degree + view of the world. But then it converts the six cube map faces + into a single fisheye texture, suitable for applying as a static + environment map (sphere map). - For eye-relative static environment maps, sphere maps are - often preferable to cube maps because they require only a - single texture and because they are supported on a broader - range of hardware. + For eye-relative static environment maps, sphere maps are often + preferable to cube maps because they require only a single + texture and because they are supported on a broader range of + hardware. - The return value is the filename if successful, or None if - there is a problem. + The return value is the filename if successful, or None if there + is a problem. """ if source == None: source = self.win @@ -2740,17 +2753,22 @@ class ShowBase(DirectObject.DirectObject): format = 'png', sd = 4, source = None): """ Spawn a task to capture a movie using the screenshot function. - - namePrefix will be used to form output file names (can include - path information (e.g. '/i/beta/frames/myMovie') - - duration is the length of the movie in seconds - - fps is the frame rate of the resulting movie - - format specifies output file format (e.g. png, bmp) - - sd specifies number of significant digits for frame count in the - output file name (e.g. if sd = 4, movie_0001.png) - - source is the Window, Buffer, DisplayRegion, or Texture from which - to save the resulting images. The default is the main window. - The task is returned, so that it can be awaited. + Args: + namePrefix (str): used to form output file names (can + include path information (e.g. '/i/beta/frames/myMovie') + duration (float): the length of the movie in seconds + fps (float): the frame rate of the resulting movie + format (str): specifies output file format (e.g. png, bmp) + sd (int): specifies number of significant digits for frame + count in the output file name (e.g. if sd = 4, the name + will be something like movie_0001.png) + source: the Window, Buffer, DisplayRegion, or Texture from + which to save the resulting images. The default is the + main window. + + Returns: + A `~direct.task.Task` that can be awaited. """ globalClock.setMode(ClockObject.MNonRealTime) globalClock.setDt(1.0/float(fps)) @@ -3113,11 +3131,12 @@ class ShowBase(DirectObject.DirectObject): self.startDirect(fWantDirect = fDirect, fWantTk = fTk, fWantWx = fWx) def run(self): - """ This method runs the TaskManager when self.appRunner is - None, which is to say, when we are not running from within a - p3d file. When we *are* within a p3d file, the Panda - runtime has to be responsible for running the main loop, so - we can't allow the application to do it. """ + """This method runs the :class:`~direct.task.Task.TaskManager` + when ``self.appRunner is None``, which is to say, when we are + not running from within a p3d file. When we *are* within a p3d + file, the Panda3D runtime has to be responsible for running the + main loop, so we can't allow the application to do it. + """ if self.appRunner is None or self.appRunner.dummy or \ (self.appRunner.interactiveConsole and not self.appRunner.initialAppImport): diff --git a/direct/src/showbase/ShowBaseGlobal.py b/direct/src/showbase/ShowBaseGlobal.py index 845e1cccdc..8acd70d18d 100644 --- a/direct/src/showbase/ShowBaseGlobal.py +++ b/direct/src/showbase/ShowBaseGlobal.py @@ -1,5 +1,6 @@ -"""This module serves as a container to hold the global ShowBase instance, as -an alternative to using the builtin scope. +"""This module serves as a container to hold the global +:class:`~.ShowBase.ShowBase` instance, as an alternative to using the builtin +scope. Note that you cannot directly import `base` from this module since ShowBase may not have been created yet; instead, ShowBase dynamically adds itself to @@ -16,6 +17,7 @@ from . import DConfig as config __dev__ = config.GetBool('want-dev', __debug__) +#: The global instance of the :class:`panda3d.core.VirtualFileSystem`. vfs = VirtualFileSystem.getGlobalPtr() ostream = Notify.out() globalClock = ClockObject.getGlobalClock() @@ -30,17 +32,23 @@ hidden = NodePath("hidden") # Set direct notify categories now that we have config directNotify.setDconfigLevels() + def run(): + """Deprecated alias for :meth:`base.run() <.ShowBase.run>`.""" assert ShowBase.notify.warning("run() is deprecated, use base.run() instead") base.run() + def inspect(anObject): + """Opens up a :mod:`direct.tkpanels.Inspector` GUI panel for inspecting an + object.""" # Don't use a regular import, to prevent ModuleFinder from picking # it up as a dependency when building a .p3d package. import importlib Inspector = importlib.import_module('direct.tkpanels.Inspector') return Inspector.inspect(anObject) + import sys if sys.version_info >= (3, 0): import builtins diff --git a/direct/src/showbase/TkGlobal.py b/direct/src/showbase/TkGlobal.py index 673d337e3c..6a3aee18be 100644 --- a/direct/src/showbase/TkGlobal.py +++ b/direct/src/showbase/TkGlobal.py @@ -36,4 +36,5 @@ del bordercolors def spawnTkLoop(): + """Alias for :meth:`base.spawnTkLoop() <.ShowBase.spawnTkLoop>`.""" base.spawnTkLoop() diff --git a/direct/src/showbase/VFSImporter.py b/direct/src/showbase/VFSImporter.py index e6849fd503..b59965ae3c 100644 --- a/direct/src/showbase/VFSImporter.py +++ b/direct/src/showbase/VFSImporter.py @@ -1,3 +1,10 @@ +"""The VFS importer allows importing Python modules from Panda3D's virtual +file system, through Python's standard import mechanism. + +Calling the :func:`register()` function to register the import hooks should be +sufficient to enable this functionality. +""" + __all__ = ['register', 'sharedPackages', 'reloadSharedPackage', 'reloadSharedPackages'] @@ -8,19 +15,18 @@ import marshal import imp import types -# The sharedPackages dictionary lists all of the "shared packages", -# special Python packages that automatically span multiple directories -# via magic in the VFSImporter. You can make a package "shared" -# simply by adding its name into this dictionary (and then calling -# reloadSharedPackages() if it's already been imported). - -# When a package name is in this dictionary at import time, *all* -# instances of the package are located along sys.path, and merged into -# a single Python module with a __path__ setting that represents the -# union. Thus, you can have a direct.showbase.foo in your own -# application, and loading it won't shadow the system -# direct.showbase.ShowBase which is in a different directory on disk. - +#: The sharedPackages dictionary lists all of the "shared packages", +#: special Python packages that automatically span multiple directories +#: via magic in the VFSImporter. You can make a package "shared" +#: simply by adding its name into this dictionary (and then calling +#: reloadSharedPackages() if it's already been imported). +#: +#: When a package name is in this dictionary at import time, *all* +#: instances of the package are located along sys.path, and merged into +#: a single Python module with a __path__ setting that represents the +#: union. Thus, you can have a direct.showbase.foo in your own +#: application, and loading it won't shadow the system +#: direct.showbase.ShowBase which is in a different directory on disk. sharedPackages = {} vfs = VirtualFileSystem.getGlobalPtr() @@ -31,6 +37,7 @@ if not __debug__: # We implement that by reversing the extension names. compiledExtensions = [ 'pyo', 'pyc' ] + class VFSImporter: """ This class serves as a Python importer to support loading Python .py and .pyc/.pyo files from Panda's Virtual File System, @@ -326,6 +333,7 @@ class VFSLoader: return code + class VFSSharedImporter: """ This is a special importer that is added onto the meta_path list, so that it is called before sys.path is traversed. It uses @@ -418,6 +426,7 @@ class VFSSharedImporter: # Couldn't figure it out. return None + class VFSSharedLoader: """ The second part of VFSSharedImporter, this imports a list of packages and combines them. """ @@ -470,6 +479,7 @@ class VFSSharedLoader: return mod + _registered = False def register(): """ Register the VFSImporter on the path_hooks, if it has not @@ -488,6 +498,7 @@ def register(): # folders that previously were loaded directly. sys.path_importer_cache = {} + def reloadSharedPackage(mod): """ Reloads the specific module as a shared package, adding any new directories that might have appeared on the search path. """ @@ -515,6 +526,7 @@ def reloadSharedPackage(mod): sharedPackages[childname] = True reloadSharedPackage(child) + def reloadSharedPackages(): """ Walks through the sharedPackages list, and forces a reload of any modules on that list that have already been loaded. This @@ -530,4 +542,3 @@ def reloadSharedPackages(): continue reloadSharedPackage(mod) - diff --git a/direct/src/showbase/WxGlobal.py b/direct/src/showbase/WxGlobal.py index ae2e618102..dd43c673b5 100755 --- a/direct/src/showbase/WxGlobal.py +++ b/direct/src/showbase/WxGlobal.py @@ -1,4 +1,6 @@ """ This module is now vestigial. """ + def spawnWxLoop(): + """Alias for :meth:`base.spawnWxLoop() <.ShowBase.spawnWxLoop>`.""" base.spawnWxLoop() diff --git a/direct/src/stdpy/file.py b/direct/src/stdpy/file.py index 02cec1050d..458406a1e0 100644 --- a/direct/src/stdpy/file.py +++ b/direct/src/stdpy/file.py @@ -34,6 +34,11 @@ else: def open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True): + """This function emulates the built-in Python open() function, additionally + providing support for Panda's virtual file system. It takes the same + arguments as Python's built-in open() function. + """ + if sys.version_info >= (3, 0): # Python 3 is much stricter than Python 2, which lets # unknown flags fall through. diff --git a/direct/src/stdpy/pickle.py b/direct/src/stdpy/pickle.py index 027888e281..fefdeae9ff 100644 --- a/direct/src/stdpy/pickle.py +++ b/direct/src/stdpy/pickle.py @@ -14,9 +14,9 @@ mechanism for sharing context between different objects written to the same pickle stream, so each NodePath has to write itself without knowing about the other NodePaths that will also be writing to the same stream. This replacement module solves this problem by defining -a __reduce_persist__() replacement method for __reduce__(), which -accepts a pointer to the Pickler object itself, allowing for shared -context between all objects written by that Pickler. +a ``__reduce_persist__()`` replacement method for ``__reduce__()``, +which accepts a pointer to the Pickler object itself, allowing for +shared context between all objects written by that Pickler. Unfortunately, cPickle cannot be supported, because it does not support extensions of this nature. """ diff --git a/direct/src/task/Task.py b/direct/src/task/Task.py index 892d5c5bee..e67f191d83 100644 --- a/direct/src/task/Task.py +++ b/direct/src/task/Task.py @@ -1,6 +1,10 @@ """ This module defines a Python-level wrapper around the C++ -AsyncTaskManager interface. It replaces the old full-Python -implementation of the Task system. """ +:class:`~panda3d.core.AsyncTaskManager` interface. It replaces the old +full-Python implementation of the Task system. + +For more information about the task system, consult the +:ref:`tasks-and-event-handling` page in the programming manual. +""" __all__ = ['Task', 'TaskManager', 'cont', 'done', 'again', 'pickup', 'exit', @@ -68,7 +72,7 @@ again = AsyncTask.DSAgain pickup = AsyncTask.DSPickup exit = AsyncTask.DSExit -# Alias PythonTask to Task for historical purposes. +#: Task aliases to :class:`panda3d.core.PythonTask` for historical purposes. Task = PythonTask # Copy the module-level enums above into the class level. This funny @@ -274,7 +278,7 @@ class TaskManager: def getTasksMatching(self, taskPattern): """Returns a list of all tasks, active or sleeping, with a name that matches the pattern, which can include standard - shell globbing characters like *, ?, and []. """ + shell globbing characters like \\*, ?, and []. """ return self.__makeTaskList(self.mgr.findTasksMatching(GlobPattern(taskPattern))) @@ -302,7 +306,7 @@ class TaskManager: uponDeath = None, appendTask = False, owner = None): """Adds a task to be performed at some time in the future. - This is identical to add(), except that the specified + This is identical to `add()`, except that the specified delayTime is applied to the Task object first, which means that the task will not begin executing until at least the indicated delayTime (in seconds) has elapsed. @@ -326,59 +330,61 @@ class TaskManager: def add(self, funcOrTask, name = None, sort = None, extraArgs = None, priority = None, uponDeath = None, appendTask = False, taskChain = None, owner = None): - """ Add a new task to the taskMgr. The task will begin executing immediately, or next frame if its sort value has already passed this frame. - The parameters are: + Parameters: + funcOrTask: either an existing Task object (not already + added to the task manager), or a callable function + object. If this is a function, a new Task object will be + created and returned. You may also pass in a coroutine + object. - funcOrTask - either an existing Task object (not already added - to the task manager), or a callable function object. If this - is a function, a new Task object will be created and returned. - You may also pass in a coroutine object. + name (str): the name to assign to the Task. Required, + unless you are passing in a Task object that already has + a name. - name - the name to assign to the Task. Required, unless you - are passing in a Task object that already has a name. + extraArgs (list): the list of arguments to pass to the task + function. If this is omitted, the list is just the task + object itself. - extraArgs - the list of arguments to pass to the task - function. If this is omitted, the list is just the task - object itself. + appendTask (bool): If this is true, then the task object + itself will be appended to the end of the extraArgs list + before calling the function. - appendTask - a boolean flag. If this is true, then the task - object itself will be appended to the end of the extraArgs - list before calling the function. + sort (int): the sort value to assign the task. The default + sort is 0. Within a particular task chain, it is + guaranteed that the tasks with a lower sort value will + all run before tasks with a higher sort value run. - sort - the sort value to assign the task. The default sort is - 0. Within a particular task chain, it is guaranteed that the - tasks with a lower sort value will all run before tasks with a - higher sort value run. + priority (int): the priority at which to run the task. The + default priority is 0. Higher priority tasks are run + sooner, and/or more often. For historical purposes, if + you specify a priority without also specifying a sort, + the priority value is understood to actually be a sort + value. (Previously, there was no priority value, only a + sort value, and it was called "priority".) - priority - the priority at which to run the task. The default - priority is 0. Higher priority tasks are run sooner, and/or - more often. For historical purposes, if you specify a - priority without also specifying a sort, the priority value is - understood to actually be a sort value. (Previously, there - was no priority value, only a sort value, and it was called - "priority".) + uponDeath (bool): a function to call when the task + terminates, either because it has run to completion, or + because it has been explicitly removed. - uponDeath - a function to call when the task terminates, - either because it has run to completion, or because it has - been explicitly removed. + taskChain (str): the name of the task chain to assign the + task to. - taskChain - the name of the task chain to assign the task to. - - owner - an optional Python object that is declared as the - "owner" of this task for maintenance purposes. The owner must - have two methods: owner._addTask(self, task), which is called - when the task begins, and owner._clearTask(self, task), which - is called when the task terminates. This is all the owner - means. - - The return value of add() is the new Task object that has been - added, or the original Task object that was passed in. + owner: an optional Python object that is declared as the + "owner" of this task for maintenance purposes. The + owner must have two methods: + ``owner._addTask(self, task)``, which is called when the + task begins, and ``owner._clearTask(self, task)``, which + is called when the task terminates. This is all the + ownermeans. + Returns: + The new Task object that has been added, or the original + Task object that was passed in. """ task = self.__setupTask(funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath) @@ -458,8 +464,8 @@ class TaskManager: def removeTasksMatching(self, taskPattern): """Removes all tasks whose names match the pattern, which can - include standard shell globbing characters like *, ?, and []. - See also remove(). + include standard shell globbing characters like \\*, ?, and []. + See also :meth:`remove()`. Returns the number of tasks removed. """ diff --git a/direct/src/task/TaskManagerGlobal.py b/direct/src/task/TaskManagerGlobal.py index 792938cfc4..e760565db1 100644 --- a/direct/src/task/TaskManagerGlobal.py +++ b/direct/src/task/TaskManagerGlobal.py @@ -1,4 +1,4 @@ -"""TaskManagerGlobal module: contains the global task manager""" +"""Contains the global :class:`~.Task.TaskManager` object.""" __all__ = ['taskMgr'] diff --git a/direct/src/task/__init__.py b/direct/src/task/__init__.py index 40a5246131..6a75e7b904 100644 --- a/direct/src/task/__init__.py +++ b/direct/src/task/__init__.py @@ -5,4 +5,7 @@ manages scheduled functions that are executed at designated intervals. The global task manager object can be imported as a singleton:: from direct.task.TaskManagerGlobal import taskMgr + +For more information about the task system, consult the +:ref:`tasks-and-event-handling` page in the programming manual. """ diff --git a/direct/src/tkpanels/FSMInspector.py b/direct/src/tkpanels/FSMInspector.py index 14b307b300..42ab82a37d 100644 --- a/direct/src/tkpanels/FSMInspector.py +++ b/direct/src/tkpanels/FSMInspector.py @@ -1,4 +1,106 @@ -""" Finite State Machine Inspector module """ +"""Defines the `FSMInspector` class, which opens a Tkinter window for +inspecting :ref:`finite-state-machines`. + +Using the Finite State Inspector +-------------------------------- + +1) In your Config.prc add:: + + want-tk #t + +2) Start up the show and create a Finite State Machine:: + + from direct.showbase.ShowBaseGlobal import * + + from direct.fsm import ClassicFSM + from direct.fsm import State + + def enterState(): + print('enterState') + + def exitState(): + print 'exitState' + + fsm = ClassicFSM.ClassicFSM('stopLight', + [State.State('red', enterState, exitState, ['green']), + State.State('yellow', enterState, exitState, ['red']), + State.State('green', enterState, exitState, ['yellow'])], + 'red', + 'red') + + import FSMInspector + + inspector = FSMInspector.FSMInspector(fsm, title = fsm.getName()) + + # Note, the inspectorPos argument is optional, the inspector will + # automagically position states on startup + fsm = ClassicFSM.ClassicFSM('stopLight', [ + State.State('yellow', + enterState, + exitState, + ['red'], + inspectorPos = [95.9, 48.0]), + State.State('red', + enterState, + exitState, + ['green'], + inspectorPos = [0.0, 0.0]), + State.State('green', + enterState, + exitState, + ['yellow'], + inspectorPos = [0.0, 95.9])], + 'red', + 'red') + +3) Pop open a viewer:: + + import FSMInspector + insp = FSMInspector.FSMInspector(fsm) + +or if you wish to be fancy:: + + insp = FSMInspector.FSMInspector(fsm, title = fsm.getName()) + +Features: + + - Right mouse button over a state pops up a menu allowing you to + request a transition to that state + - Middle mouse button will grab the canvas and slide things around if + your state machine is bigger than the viewing area + - There are some self explanatory menu options up at the top, the most + useful being: "print ClassicFSM layout" which will print out Python + code which will create an ClassicFSM augmented with layout + information for the viewer so everything shows up in the same place + the next time you inspect the state machine + +Caveat +------ + +There is an unexplained problem with using Tk and emacs right now which +occasionally results in everything locking up. This procedure seems to +avoid the problem for me:: + + # Start up the show + from direct.showbase.ShowBaseGlobal import * + + # You will see the window and a Tk panel pop open + + # Type a number at the emacs prompt + >>> 123 + + # At this point everything will lock up and you won't get your prompt back + + # Hit a bunch of Control-C's in rapid succession, in most cases + # this will break you out of whatever badness you were in and + # from that point on everything will behave normally + + + # This is how you pop up an inspector + import FSMInspector + inspector = FSMInspector.FSMInspector(fsm, title = fsm.getName()) + +""" __all__ = ['FSMInspector', 'StateInspector'] @@ -14,6 +116,7 @@ else: DELTA = (5.0 / 360.) * 2.0 * math.pi + class FSMInspector(AppShell): # Override class variables appname = 'ClassicFSM Inspector' @@ -445,104 +548,3 @@ class StateInspector(Pmw.MegaArchetype): def exitedState(self): self._canvas.itemconfigure(self.marker, fill = 'CornflowerBlue') - - -""" -# USING FINITE STATE INSPECTOR - -1) in your Configrc add: - -want-tk #t - -2) start up the show and create a Finite State Machine - -from direct.showbase.ShowBaseGlobal import * - -from direct.fsm import ClassicFSM -from direct.fsm import State - -def enterState(): - print 'enterState' - -def exitState(): - print 'exitState' - -fsm = ClassicFSM.ClassicFSM('stopLight', - [State.State('red', enterState, exitState, ['green']), - State.State('yellow', enterState, exitState, ['red']), - State.State('green', enterState, exitState, ['yellow'])], - 'red', - 'red') - -import FSMInspector - -inspector = FSMInspector.FSMInspector(fsm, title = fsm.getName()) - -# Note, the inspectorPos argument is optional, the inspector will -# automagically position states on startup -fsm = ClassicFSM.ClassicFSM('stopLight', [ - State.State('yellow', - enterState, - exitState, - ['red'], - inspectorPos = [95.9, 48.0]), - State.State('red', - enterState, - exitState, - ['green'], - inspectorPos = [0.0, 0.0]), - State.State('green', - enterState, - exitState, - ['yellow'], - inspectorPos = [0.0, 95.9])], - 'red', - 'red') - -3) Pop open a viewer - -import FSMInspector -insp = FSMInspector.FSMInspector(fsm) - -or if you wish to be fancy: - -insp = FSMInspector.FSMInspector(fsm, title = fsm.getName()) - -Features: - - Right mouse button over a state pops up a menu allowing you to - request a transition to that state - - Middle mouse button will grab the canvas and slide things around - if your state machine is bigger than the viewing area - - There are some self explanatory menu options up at the top, the most - useful being: "print ClassicFSM layout" which will print out python code - which will create an ClassicFSM augmented with layout information for the - viewer so everything shows up in the same place the next time you - inspect the state machine - -CAVEAT: - -There is some unexplained problems with using TK and emacs right now which -occasionally results in everything locking up. This procedure seems to -avoid the problem for me: - -# Start up the show -from direct.showbase.ShowBaseGlobal import * - -# You will see the window and a Tk panel pop open - -# Type a number at the emacs prompt ->>> 123 - -# At this point everything will lock up and you won't get your prompt back - -# Hit a bunch of Control-C's in rapid succession, in most cases -# this will break you out of whatever badness you were in and -# from that point on everything will behave normally - - -# This is how you pop up an inspector -import FSMInspector -inspector = FSMInspector.FSMInspector(fsm, title = fsm.getName()) - -""" - diff --git a/direct/src/tkpanels/__init__.py b/direct/src/tkpanels/__init__.py index e69de29bb2..af339608b6 100644 --- a/direct/src/tkpanels/__init__.py +++ b/direct/src/tkpanels/__init__.py @@ -0,0 +1,3 @@ +"""This package provides various GUI panels useful during Panda3D development +written using the Tkinter framework. +""" diff --git a/direct/src/tkwidgets/__init__.py b/direct/src/tkwidgets/__init__.py index e69de29bb2..18c32074c6 100644 --- a/direct/src/tkwidgets/__init__.py +++ b/direct/src/tkwidgets/__init__.py @@ -0,0 +1 @@ +"""This package provides various Tkinter widgets."""