Browse Source

Dramatically reduce size of frozen/compiled code by pruning/masking unnecessary imports/code

rdb 9 years ago
parent
commit
0d03207d1b

+ 3 - 1
direct/src/directutil/Verify.py

@@ -41,7 +41,9 @@ only when debugging (i.e. when it won't be checked-in) or where it helps
 you resist using assert for error handling.
 """
 
-wantVerifyPdb = 0 # Set to true to load pdb on failure.
+from panda3d.core import ConfigVariableBool
+
+wantVerifyPdb = ConfigVariableBool('want-verify-pdb', False) # Set to true to load pdb on failure.
 
 
 def verify(assertion):

+ 0 - 8
direct/src/gui/DirectGuiBase.py

@@ -12,7 +12,6 @@ from OnscreenImage import *
 from direct.directtools.DirectUtil import ROUND_TO
 from direct.showbase import DirectObject
 from direct.task import Task
-from direct.showbase.PythonUtil import recordCreationStackStr
 import types
 
 guiObjectCollector = PStatCollector("Client::GuiObjects")
@@ -651,13 +650,6 @@ def toggleGuiGridSnap():
 def setGuiGridSpacing(spacing):
     DirectGuiWidget.gridSpacing = spacing
 
-# this should trigger off of __dev__, but it's not available at this point.
-# __debug__ works because the production client is not __debug__ and the
-# production AI doesn't create any GUI.
-if get_config_showbase().GetBool('record-gui-creation-stack', __debug__):
-    # this will help track down the code that created DirectGui objects
-    # call obj.printCreationStackTrace() to figure out what code created it
-    DirectGuiBase = recordCreationStackStr(DirectGuiBase)
 
 class DirectGuiWidget(DirectGuiBase, NodePath):
     # Toggle if you wish widget's to snap to grid when draggin

+ 0 - 7
direct/src/interval/ProjectileInterval.py

@@ -72,13 +72,6 @@ class ProjectileInterval(Interval):
                               self.projectileIntervalNum)
             ProjectileInterval.projectileIntervalNum += 1
 
-            """
-            # attempt to add info about the caller
-            file, line, func = PythonUtil.callerInfo()
-            if file is not None:
-                name += '-%s:%s:%s' % (file, line, func)
-            """
-
         args = (startPos, endPos, duration, startVel, endZ,
                 wayPoint, timeToWayPoint, gravityMult)
         self.implicitStartPos = 0

+ 3 - 3
direct/src/showbase/ExceptionVarDump.py

@@ -1,4 +1,5 @@
-from panda3d.direct import get_config_showbase
+__all__ = ["install"]
+
 from direct.directnotify.DirectNotifyGlobal import directNotify
 from direct.showbase.PythonUtil import fastRepr
 import sys
@@ -6,7 +7,6 @@ import types
 import traceback
 
 notify = directNotify.newCategory("ExceptionVarDump")
-config = get_config_showbase()
 
 reentry = 0
 
@@ -187,7 +187,7 @@ def install(log, upload):
     wantStackDumpLog = log
     wantStackDumpUpload = upload
 
-    dumpOnExceptionInit = config.GetBool('variable-dump-on-exception-init', 0)
+    dumpOnExceptionInit = ConfigVariableBool('variable-dump-on-exception-init', False)
     if dumpOnExceptionInit:
         # this mode doesn't completely work because exception objects
         # thrown by the interpreter don't get created until the

+ 3 - 3
direct/src/showbase/GarbageReport.py

@@ -281,7 +281,7 @@ class GarbageReport(Job):
         if self._args.findCycles:
             s = ['===== GarbageReport: \'%s\' (%s %s) =====' % (
                 self._args.name, self.numCycles,
-                choice(self.numCycles == 1, 'cycle', 'cycles'))]
+                ('cycle' if self.numCycles == 1 else 'cycles'))]
         else:
             s = ['===== GarbageReport: \'%s\' =====' % (
                 self._args.name)]
@@ -499,7 +499,7 @@ class GarbageReport(Job):
         rootId = index
         # check if the root object is one of the garbage instances (has __del__)
         objId = id(self.garbage[rootId])
-        numDelInstances = choice(objId in self.garbageInstanceIds, 1, 0)
+        numDelInstances = int(objId in self.garbageInstanceIds)
         stateStack.push(([rootId], rootId, numDelInstances, 0))
         while True:
             yield None
@@ -535,7 +535,7 @@ class GarbageReport(Job):
                 elif refId is not None:
                     # check if this object is one of the garbage instances (has __del__)
                     objId = id(self.garbage[refId])
-                    numDelInstances += choice(objId in self.garbageInstanceIds, 1, 0)
+                    numDelInstances += int(objId in self.garbageInstanceIds)
                     # this refId does not complete a cycle. Mark down
                     # where we are in this list of referents, then
                     # start looking through the referents of the new refId

+ 2 - 7
direct/src/showbase/ObjectPool.py

@@ -5,7 +5,6 @@ __all__ = ['Diff', 'ObjectPool']
 from direct.directnotify.DirectNotifyGlobal import directNotify
 from direct.showbase.PythonUtil import invertDictLossless, makeList, safeRepr
 from direct.showbase.PythonUtil import getNumberedTypedString, getNumberedTypedSortedString
-from direct.showbase.PythonUtil import getNumberedTypedSortedStringWithReferrersGen
 import gc
 
 class Diff:
@@ -97,7 +96,7 @@ class ObjectPool:
                 s += '\n%s\t%s' % (count, typ)
         return s
 
-    def printObjsByType(self, printReferrers=False):
+    def printObjsByType(self):
         print   'Object Pool: Objects By Type'
         print '\n============================'
         counts = list(set(self._count2types.keys()))
@@ -109,11 +108,7 @@ class ObjectPool:
             types = makeList(self._count2types[count])
             for typ in types:
                 print 'TYPE: %s, %s objects' % (repr(typ), len(self._type2objs[typ]))
-                if printReferrers:
-                    for line in getNumberedTypedSortedStringWithReferrersGen(self._type2objs[typ]):
-                        print line
-                else:
-                    print getNumberedTypedSortedString(self._type2objs[typ])
+                print getNumberedTypedSortedString(self._type2objs[typ])
 
     def containerLenStr(self):
         s  =   'Object Pool: Container Lengths'

File diff suppressed because it is too large
+ 431 - 494
direct/src/showbase/PythonUtil.py


+ 59 - 48
direct/src/showbase/ShowBase.py

@@ -26,24 +26,22 @@ from BulletinBoardGlobal import bulletinBoard
 from direct.task.TaskManagerGlobal import taskMgr
 from JobManagerGlobal import jobMgr
 from EventManagerGlobal import eventMgr
-from PythonUtil import *
-from direct.showbase import PythonUtil
-#from direct.interval.IntervalManager import ivalMgr
+#from PythonUtil import *
 from direct.interval import IntervalManager
 from direct.showbase.BufferViewer import BufferViewer
 from direct.task import Task
-from direct.directutil import Verify
-from direct.showbase import GarbageReport
 import sys
 import Loader
 import time
 import atexit
+import importlib
 from direct.showbase import ExceptionVarDump
 import DirectObject
 import SfxPlayer
 if __debug__:
+    from direct.showbase import GarbageReport
     from direct.directutil import DeltaProfiler
-import OnScreenDebug
+    import OnScreenDebug
 import AppRunnerGlobal
 
 def legacyRun():
@@ -73,7 +71,8 @@ class ShowBase(DirectObject.DirectObject):
         if logStackDump or uploadStackDump:
             ExceptionVarDump.install(logStackDump, uploadStackDump)
 
-        self.__autoGarbageLogging = self.__dev__ and self.config.GetBool('auto-garbage-logging', False)
+        if __debug__:
+            self.__autoGarbageLogging = self.__dev__ and self.config.GetBool('auto-garbage-logging', False)
 
         ## The directory containing the main Python file of this application.
         self.mainDir = ExecutionEnvironment.getEnvironmentVariable("MAIN_DIR")
@@ -88,9 +87,6 @@ class ShowBase(DirectObject.DirectObject):
         #debug running multiplier
         self.debugRunningMultiplier = 4
 
-        # Setup wantVerifyPdb as soon as reasonable:
-        Verify.wantVerifyPdb = self.config.GetBool('want-verify-pdb', 0)
-
         # [gjeon] to disable sticky keys
         if self.config.GetBool('disable-sticky-keys', 0):
             storeAccessibilityShortcutKeys()
@@ -373,8 +369,8 @@ class ShowBase(DirectObject.DirectObject):
         builtins.wantUberdog = self.config.GetBool('want-uberdog', 1)
         if __debug__:
             builtins.deltaProfiler = DeltaProfiler.DeltaProfiler("ShowBase")
-        self.onScreenDebug = OnScreenDebug.OnScreenDebug()
-        builtins.onScreenDebug = self.onScreenDebug
+            self.onScreenDebug = OnScreenDebug.OnScreenDebug()
+            builtins.onScreenDebug = self.onScreenDebug
 
         if self.wantRender2dp:
             builtins.render2dp = self.render2dp
@@ -388,10 +384,6 @@ class ShowBase(DirectObject.DirectObject):
 
         self.createBaseAudioManagers()
 
-        # set up recording of Functor creation stacks in __dev__
-        if self.__dev__ and self.config.GetBool('record-functor-creation-stacks', False):
-            PythonUtil.recordFunctorCreationStacks()
-
         if self.__dev__ or self.config.GetBool('want-e3-hacks', False):
             if self.config.GetBool('track-gui-items', True):
                 # dict of guiId to gui item, for tracking down leaks
@@ -465,7 +457,8 @@ class ShowBase(DirectObject.DirectObject):
         some Panda config settings. """
 
         try:
-            import profile, pstats
+            profile = importlib.import_module('profile')
+            pstats = importlib.import_module('pstats')
         except ImportError:
             return
 
@@ -1647,23 +1640,26 @@ class ShowBase(DirectObject.DirectObject):
 
     def addAngularIntegrator(self):
         if not self.physicsMgrAngular:
-            from panda3d.physics import AngularEulerIntegrator
+            physics = importlib.import_module('panda3d.physics')
             self.physicsMgrAngular = 1
-            integrator = AngularEulerIntegrator()
+            integrator = physics.AngularEulerIntegrator()
             self.physicsMgr.attachAngularIntegrator(integrator)
 
     def enableParticles(self):
         if not self.particleMgrEnabled:
+            # Use importlib to prevent this import from being picked up
+            # by modulefinder when packaging an application.
+
             if not self.particleMgr:
-                from direct.particles.ParticleManagerGlobal import particleMgr
-                self.particleMgr = particleMgr
+                PMG = importlib.import_module('direct.particles.ParticleManagerGlobal')
+                self.particleMgr = PMG.particleMgr
                 self.particleMgr.setFrameStepping(1)
 
             if not self.physicsMgr:
-                from PhysicsManagerGlobal import physicsMgr
-                from panda3d.physics import LinearEulerIntegrator
-                self.physicsMgr = physicsMgr
-                integrator = LinearEulerIntegrator()
+                PMG = importlib.import_module('direct.showbase.PhysicsManagerGlobal')
+                physics = importlib.import_module('panda3d.physics')
+                self.physicsMgr = PMG.physicsMgr
+                integrator = physics.LinearEulerIntegrator()
                 self.physicsMgr.attachLinearIntegrator(integrator)
 
             self.particleMgrEnabled = 1
@@ -1886,9 +1882,10 @@ class ShowBase(DirectObject.DirectObject):
         return Task.cont
 
     def __igLoop(self, state):
-        # We render the watch variables for the onScreenDebug as soon
-        # as we reasonably can before the renderFrame().
-        self.onScreenDebug.render()
+        if __debug__:
+            # We render the watch variables for the onScreenDebug as soon
+            # as we reasonably can before the renderFrame().
+            self.onScreenDebug.render()
 
         if self.recorder:
             self.recorder.recordFrame()
@@ -1900,9 +1897,10 @@ class ShowBase(DirectObject.DirectObject):
         if self.multiClientSleep:
             time.sleep(0)
 
-        # We clear the text buffer for the onScreenDebug as soon
-        # as we reasonably can after the renderFrame().
-        self.onScreenDebug.clear()
+        if __debug__:
+            # We clear the text buffer for the onScreenDebug as soon
+            # as we reasonably can after the renderFrame().
+            self.onScreenDebug.clear()
 
         if self.recorder:
             self.recorder.playFrame()
@@ -1925,9 +1923,10 @@ class ShowBase(DirectObject.DirectObject):
 
 
     def __igLoopSync(self, state):
-        # We render the watch variables for the onScreenDebug as soon
-        # as we reasonably can before the renderFrame().
-        self.onScreenDebug.render()
+        if __debug__:
+            # We render the watch variables for the onScreenDebug as soon
+            # as we reasonably can before the renderFrame().
+            self.onScreenDebug.render()
 
         if self.recorder:
             self.recorder.recordFrame()
@@ -1941,9 +1940,10 @@ class ShowBase(DirectObject.DirectObject):
         if self.multiClientSleep:
             time.sleep(0)
 
-        # We clear the text buffer for the onScreenDebug as soon
-        # as we reasonably can after the renderFrame().
-        self.onScreenDebug.clear()
+        if __debug__:
+            # We clear the text buffer for the onScreenDebug as soon
+            # as we reasonably can after the renderFrame().
+            self.onScreenDebug.clear()
 
         if self.recorder:
             self.recorder.playFrame()
@@ -2178,8 +2178,10 @@ class ShowBase(DirectObject.DirectObject):
             self.texmem = None
             return
 
-        from direct.showutil.TexMemWatcher import TexMemWatcher
-        self.texmem = TexMemWatcher()
+        # Use importlib to prevent this import from being picked up
+        # by modulefinder when packaging an application.
+        TMW = importlib.import_module('direct.showutil.TexMemWatcher')
+        self.texmem = TMW.TexMemWatcher()
 
     def toggleShowVertices(self):
         """ Toggles a mode that visualizes vertex density per screen
@@ -2675,16 +2677,18 @@ class ShowBase(DirectObject.DirectObject):
             if not properties.getOpen():
                 # If the user closes the main window, we should exit.
                 self.notify.info("User closed main window.")
-                if self.__autoGarbageLogging:
-                    GarbageReport.b_checkForGarbageLeaks()
+                if __debug__:
+                    if self.__autoGarbageLogging:
+                        GarbageReport.b_checkForGarbageLeaks()
                 self.userExit()
 
             if properties.getForeground() and not self.mainWinForeground:
                 self.mainWinForeground = 1
             elif not properties.getForeground() and self.mainWinForeground:
                 self.mainWinForeground = 0
-                if self.__autoGarbageLogging:
-                    GarbageReport.b_checkForGarbageLeaks()
+                if __debug__:
+                    if self.__autoGarbageLogging:
+                        GarbageReport.b_checkForGarbageLeaks()
 
             if properties.getMinimized() and not self.mainWinMinimized:
                 # If the main window is minimized, throw an event to
@@ -2814,7 +2818,10 @@ class ShowBase(DirectObject.DirectObject):
 
         init_app_for_gui()
 
-        import wx
+        # Use importlib to prevent this import from being picked up
+        # by modulefinder when packaging an application.
+        wx = importlib.import_module('wx')
+
         # Create a new base.wxApp.
         self.wxApp = wx.PySimpleApp(redirect = False)
 
@@ -2889,8 +2896,10 @@ class ShowBase(DirectObject.DirectObject):
             # Don't do this twice.
             return
 
-        from Tkinter import tkinter
-        import Pmw
+        # Use importlib to prevent this import from being picked up
+        # by modulefinder when packaging an application.
+        tkinter = importlib.import_module('Tkinter').tkinter
+        Pmw = importlib.import_module('Pmw')
 
         # Create a new Tk root.
         self.tkRoot = Pmw.initialise()
@@ -2953,8 +2962,10 @@ class ShowBase(DirectObject.DirectObject):
         self.startWx(fWantWx)
         self.wantDirect = fWantDirect
         if self.wantDirect:
-            from direct.directtools.DirectSession import DirectSession
-            self.direct = DirectSession()
+            # Use importlib to prevent this import from being picked up
+            # by modulefinder when packaging an application.
+            DirectSession = importlib.import_module('direct.directtools.DirectSession')
+            self.direct = DirectSession.DirectSession()
             self.direct.enable()
             builtins.direct = self.direct
         else:

+ 1 - 1
direct/src/showbase/Transitions.py

@@ -3,7 +3,7 @@
 __all__ = ['Transitions']
 
 from panda3d.core import *
-from direct.gui.DirectGui import *
+from direct.gui.DirectGui import DirectFrame
 from direct.gui import DirectGuiGlobals as DGG
 from direct.interval.LerpInterval import LerpColorScaleInterval, LerpColorInterval, LerpScaleInterval, LerpPosInterval
 from direct.interval.MetaInterval import Sequence, Parallel

+ 2 - 2
direct/src/showutil/FreezeTool.py

@@ -30,8 +30,8 @@ isDebugBuild = (python.lower().endswith('_d'))
 # These are modules that Python always tries to import up-front.  They
 # must be frozen in any main.exe.
 startupModules = [
-    'site', 'sitecustomize', 'os', 'encodings.cp1252',
-    'encodings.latin_1', 'encodings.utf_8', 'io', 'org',
+    'os', 'encodings.cp1252',
+    'encodings.latin_1', 'encodings.utf_8', 'io',
     ]
 
 # These are missing modules that we've reported already this session.

+ 7 - 0
direct/src/stdpy/thread.py

@@ -70,6 +70,13 @@ class LockType:
     def __exit__(self, t, v, tb):
         self.release()
 
+# Helper to generate new thread names
+_counter = 0
+def _newname(template="Thread-%d"):
+    global _counter
+    _counter = _counter + 1
+    return template % _counter
+
 _threads = {}
 _nextThreadId = 0
 _threadsLock = core.Mutex('thread._threadsLock')

+ 106 - 105
direct/src/stdpy/threading.py

@@ -42,6 +42,7 @@ __all__ = [
     ]
 
 local = _thread._local
+_newname = _thread._newname
 
 class ThreadBase:
     """ A base class for both Thread and ExternalThread in this
@@ -98,8 +99,7 @@ class Thread(ThreadBase):
         self.__kwargs = kwargs
 
         if not name:
-            import threading2
-            name = threading2._newname()
+            name = _newname()
 
         current = current_thread()
         self.__dict__['daemon'] = current.daemon
@@ -404,106 +404,107 @@ def setprofile(func):
 def stack_size(size = None):
     raise ThreadError
 
-def _test():
-
-    from collections import deque
-    _sleep = core.Thread.sleep
-
-    _VERBOSE = False
-
-    class _Verbose(object):
-
-        def __init__(self, verbose=None):
-            if verbose is None:
-                verbose = _VERBOSE
-            self.__verbose = verbose
-
-        def _note(self, format, *args):
-            if self.__verbose:
-                format = format % args
-                format = "%s: %s\n" % (
-                    currentThread().getName(), format)
-                _sys.stderr.write(format)
-
-    class BoundedQueue(_Verbose):
-
-        def __init__(self, limit):
-            _Verbose.__init__(self)
-            self.mon = Lock(name = "BoundedQueue.mon")
-            self.rc = Condition(self.mon)
-            self.wc = Condition(self.mon)
-            self.limit = limit
-            self.queue = deque()
-
-        def put(self, item):
-            self.mon.acquire()
-            while len(self.queue) >= self.limit:
-                self._note("put(%s): queue full", item)
-                self.wc.wait()
-            self.queue.append(item)
-            self._note("put(%s): appended, length now %d",
-                       item, len(self.queue))
-            self.rc.notify()
-            self.mon.release()
-
-        def get(self):
-            self.mon.acquire()
-            while not self.queue:
-                self._note("get(): queue empty")
-                self.rc.wait()
-            item = self.queue.popleft()
-            self._note("get(): got %s, %d left", item, len(self.queue))
-            self.wc.notify()
-            self.mon.release()
-            return item
-
-    class ProducerThread(Thread):
-
-        def __init__(self, queue, quota):
-            Thread.__init__(self, name="Producer")
-            self.queue = queue
-            self.quota = quota
-
-        def run(self):
-            from random import random
-            counter = 0
-            while counter < self.quota:
-                counter = counter + 1
-                self.queue.put("%s.%d" % (self.getName(), counter))
-                _sleep(random() * 0.00001)
-
-
-    class ConsumerThread(Thread):
-
-        def __init__(self, queue, count):
-            Thread.__init__(self, name="Consumer")
-            self.queue = queue
-            self.count = count
-
-        def run(self):
-            while self.count > 0:
-                item = self.queue.get()
-                print item
-                self.count = self.count - 1
-
-    NP = 3
-    QL = 4
-    NI = 5
-
-    Q = BoundedQueue(QL)
-    P = []
-    for i in range(NP):
-        t = ProducerThread(Q, NI)
-        t.setName("Producer-%d" % (i+1))
-        P.append(t)
-    C = ConsumerThread(Q, NI*NP)
-    for t in P:
-        t.start()
-        _sleep(0.000001)
-    C.start()
-    for t in P:
-        t.join()
-    C.join()
-
-if __name__ == '__main__':
-    _test()
+if __debug__:
+    def _test():
+        from collections import deque
+
+        _sleep = core.Thread.sleep
+
+        _VERBOSE = False
+
+        class _Verbose(object):
+
+            def __init__(self, verbose=None):
+                if verbose is None:
+                    verbose = _VERBOSE
+                self.__verbose = verbose
+
+            def _note(self, format, *args):
+                if self.__verbose:
+                    format = format % args
+                    format = "%s: %s\n" % (
+                        currentThread().getName(), format)
+                    _sys.stderr.write(format)
+
+        class BoundedQueue(_Verbose):
+
+            def __init__(self, limit):
+                _Verbose.__init__(self)
+                self.mon = Lock(name = "BoundedQueue.mon")
+                self.rc = Condition(self.mon)
+                self.wc = Condition(self.mon)
+                self.limit = limit
+                self.queue = deque()
+
+            def put(self, item):
+                self.mon.acquire()
+                while len(self.queue) >= self.limit:
+                    self._note("put(%s): queue full", item)
+                    self.wc.wait()
+                self.queue.append(item)
+                self._note("put(%s): appended, length now %d",
+                           item, len(self.queue))
+                self.rc.notify()
+                self.mon.release()
+
+            def get(self):
+                self.mon.acquire()
+                while not self.queue:
+                    self._note("get(): queue empty")
+                    self.rc.wait()
+                item = self.queue.popleft()
+                self._note("get(): got %s, %d left", item, len(self.queue))
+                self.wc.notify()
+                self.mon.release()
+                return item
+
+        class ProducerThread(Thread):
+
+            def __init__(self, queue, quota):
+                Thread.__init__(self, name="Producer")
+                self.queue = queue
+                self.quota = quota
+
+            def run(self):
+                from random import random
+                counter = 0
+                while counter < self.quota:
+                    counter = counter + 1
+                    self.queue.put("%s.%d" % (self.getName(), counter))
+                    _sleep(random() * 0.00001)
+
+
+        class ConsumerThread(Thread):
+
+            def __init__(self, queue, count):
+                Thread.__init__(self, name="Consumer")
+                self.queue = queue
+                self.count = count
+
+            def run(self):
+                while self.count > 0:
+                    item = self.queue.get()
+                    print item
+                    self.count = self.count - 1
+
+        NP = 3
+        QL = 4
+        NI = 5
+
+        Q = BoundedQueue(QL)
+        P = []
+        for i in range(NP):
+            t = ProducerThread(Q, NI)
+            t.setName("Producer-%d" % (i+1))
+            P.append(t)
+        C = ConsumerThread(Q, NI*NP)
+        for t in P:
+            t.start()
+            _sleep(0.000001)
+        C.start()
+        for t in P:
+            t.join()
+        C.join()
+
+    if __name__ == '__main__':
+        _test()

+ 86 - 93
direct/src/stdpy/threading2.py

@@ -16,13 +16,12 @@ implementation. """
 import sys as _sys
 
 from direct.stdpy import thread
-from direct.stdpy.thread import stack_size, _local as local
+from direct.stdpy.thread import stack_size, _newname, _local as local
 from panda3d import core
 _sleep = core.Thread.sleep
 
 from time import time as _time
 from traceback import format_exc as _format_exc
-from collections import deque
 
 # Rename some stuff so "from threading import *" is safe
 __all__ = ['activeCount', 'Condition', 'currentThread', 'enumerate', 'Event',
@@ -377,13 +376,6 @@ class _Event(_Verbose):
         finally:
             self.__cond.release()
 
-# Helper to generate new thread names
-_counter = 0
-def _newname(template="Thread-%d"):
-    global _counter
-    _counter = _counter + 1
-    return template % _counter
-
 # Active thread administration
 _active_limbo_lock = _allocate_lock()
 _active = {}    # maps thread id to Thread object
@@ -741,88 +733,89 @@ _shutdown = _MainThread()._exitfunc
 
 
 # Self-test code
+if __debug__:
+    def _test():
+        from collections import deque
+
+        class BoundedQueue(_Verbose):
+
+            def __init__(self, limit):
+                _Verbose.__init__(self)
+                self.mon = RLock()
+                self.rc = Condition(self.mon)
+                self.wc = Condition(self.mon)
+                self.limit = limit
+                self.queue = deque()
+
+            def put(self, item):
+                self.mon.acquire()
+                while len(self.queue) >= self.limit:
+                    self._note("put(%s): queue full", item)
+                    self.wc.wait()
+                self.queue.append(item)
+                self._note("put(%s): appended, length now %d",
+                           item, len(self.queue))
+                self.rc.notify()
+                self.mon.release()
+
+            def get(self):
+                self.mon.acquire()
+                while not self.queue:
+                    self._note("get(): queue empty")
+                    self.rc.wait()
+                item = self.queue.popleft()
+                self._note("get(): got %s, %d left", item, len(self.queue))
+                self.wc.notify()
+                self.mon.release()
+                return item
+
+        class ProducerThread(Thread):
+
+            def __init__(self, queue, quota):
+                Thread.__init__(self, name="Producer")
+                self.queue = queue
+                self.quota = quota
+
+            def run(self):
+                from random import random
+                counter = 0
+                while counter < self.quota:
+                    counter = counter + 1
+                    self.queue.put("%s.%d" % (self.getName(), counter))
+                    _sleep(random() * 0.00001)
+
+
+        class ConsumerThread(Thread):
+
+            def __init__(self, queue, count):
+                Thread.__init__(self, name="Consumer")
+                self.queue = queue
+                self.count = count
+
+            def run(self):
+                while self.count > 0:
+                    item = self.queue.get()
+                    print item
+                    self.count = self.count - 1
+
+        NP = 3
+        QL = 4
+        NI = 5
+
+        Q = BoundedQueue(QL)
+        P = []
+        for i in range(NP):
+            t = ProducerThread(Q, NI)
+            t.setName("Producer-%d" % (i+1))
+            P.append(t)
+        C = ConsumerThread(Q, NI*NP)
+        for t in P:
+            t.start()
+            _sleep(0.000001)
+        C.start()
+        for t in P:
+            t.join()
+        C.join()
 
-def _test():
-
-    class BoundedQueue(_Verbose):
-
-        def __init__(self, limit):
-            _Verbose.__init__(self)
-            self.mon = RLock()
-            self.rc = Condition(self.mon)
-            self.wc = Condition(self.mon)
-            self.limit = limit
-            self.queue = deque()
-
-        def put(self, item):
-            self.mon.acquire()
-            while len(self.queue) >= self.limit:
-                self._note("put(%s): queue full", item)
-                self.wc.wait()
-            self.queue.append(item)
-            self._note("put(%s): appended, length now %d",
-                       item, len(self.queue))
-            self.rc.notify()
-            self.mon.release()
-
-        def get(self):
-            self.mon.acquire()
-            while not self.queue:
-                self._note("get(): queue empty")
-                self.rc.wait()
-            item = self.queue.popleft()
-            self._note("get(): got %s, %d left", item, len(self.queue))
-            self.wc.notify()
-            self.mon.release()
-            return item
-
-    class ProducerThread(Thread):
-
-        def __init__(self, queue, quota):
-            Thread.__init__(self, name="Producer")
-            self.queue = queue
-            self.quota = quota
-
-        def run(self):
-            from random import random
-            counter = 0
-            while counter < self.quota:
-                counter = counter + 1
-                self.queue.put("%s.%d" % (self.getName(), counter))
-                _sleep(random() * 0.00001)
-
-
-    class ConsumerThread(Thread):
-
-        def __init__(self, queue, count):
-            Thread.__init__(self, name="Consumer")
-            self.queue = queue
-            self.count = count
-
-        def run(self):
-            while self.count > 0:
-                item = self.queue.get()
-                print item
-                self.count = self.count - 1
-
-    NP = 3
-    QL = 4
-    NI = 5
-
-    Q = BoundedQueue(QL)
-    P = []
-    for i in range(NP):
-        t = ProducerThread(Q, NI)
-        t.setName("Producer-%d" % (i+1))
-        P.append(t)
-    C = ConsumerThread(Q, NI*NP)
-    for t in P:
-        t.start()
-        _sleep(0.000001)
-    C.start()
-    for t in P:
-        t.join()
-    C.join()
-
-if __name__ == '__main__':
-    _test()
+    if __name__ == '__main__':
+        _test()

+ 10 - 10
direct/src/task/Task.py

@@ -12,6 +12,7 @@ from direct.showbase.PythonUtil import *
 from direct.showbase.MessengerGlobal import messenger
 import types
 import random
+import importlib
 
 try:
     import signal
@@ -591,7 +592,6 @@ class TaskManager:
     def popupControls(self):
         # Don't use a regular import, to prevent ModuleFinder from picking
         # it up as a dependency when building a .p3d package.
-        import importlib
         TaskManagerPanel = importlib.import_module('direct.tkpanels.TaskManagerPanel')
         return TaskManagerPanel.TaskManagerPanel(self)
 
@@ -602,8 +602,8 @@ class TaskManager:
 
         # Defer this import until we need it: some Python
         # distributions don't provide the profile and pstats modules.
-        from direct.showbase.ProfileSession import ProfileSession
-        return ProfileSession(name)
+        PS = importlib.import_module('direct.showbase.ProfileSession')
+        return PS.ProfileSession(name)
 
     def profileFrames(self, num=None, session=None, callback=None):
         if num is None:
@@ -629,8 +629,8 @@ class TaskManager:
         self._profileFrames.set(profileFrames)
         if (not self._frameProfiler) and profileFrames:
             # import here due to import dependencies
-            from direct.task.FrameProfiler import FrameProfiler
-            self._frameProfiler = FrameProfiler()
+            FP = importlib.import_module('direct.task.FrameProfiler')
+            self._frameProfiler = FP.FrameProfiler()
 
     def getProfileTasks(self):
         return self._profileTasks.get()
@@ -642,8 +642,8 @@ class TaskManager:
         self._profileTasks.set(profileTasks)
         if (not self._taskProfiler) and profileTasks:
             # import here due to import dependencies
-            from direct.task.TaskProfiler import TaskProfiler
-            self._taskProfiler = TaskProfiler()
+            TP = importlib.import_module('direct.task.TaskProfiler')
+            self._taskProfiler = TP.TaskProfiler()
 
     def logTaskProfiles(self, name=None):
         if self._taskProfiler:
@@ -689,9 +689,9 @@ class TaskManager:
 
         # Defer this import until we need it: some Python
         # distributions don't provide the profile and pstats modules.
-        from direct.showbase.ProfileSession import ProfileSession
-        profileSession = ProfileSession('profiled-task-%s' % task.getName(),
-                                        Functor(profileInfo.taskFunc, *profileInfo.taskArgs))
+        PS = importlib.import_module('direct.showbase.ProfileSession')
+        profileSession = PS.ProfileSession('profiled-task-%s' % task.getName(),
+                                           Functor(profileInfo.taskFunc, *profileInfo.taskArgs))
         ret = profileSession.run()
 
         # set these values *after* profiling in case we're profiling the TaskProfiler

Some files were not shown because too many files changed in this diff