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

This commit is contained in:
rdb 2016-02-12 22:20:27 +01:00
parent 591ce04ab1
commit 0d03207d1b
14 changed files with 767 additions and 1007 deletions

View File

@ -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. 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): def verify(assertion):

View File

@ -12,7 +12,6 @@ from OnscreenImage import *
from direct.directtools.DirectUtil import ROUND_TO from direct.directtools.DirectUtil import ROUND_TO
from direct.showbase import DirectObject from direct.showbase import DirectObject
from direct.task import Task from direct.task import Task
from direct.showbase.PythonUtil import recordCreationStackStr
import types import types
guiObjectCollector = PStatCollector("Client::GuiObjects") guiObjectCollector = PStatCollector("Client::GuiObjects")
@ -651,13 +650,6 @@ def toggleGuiGridSnap():
def setGuiGridSpacing(spacing): def setGuiGridSpacing(spacing):
DirectGuiWidget.gridSpacing = 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): class DirectGuiWidget(DirectGuiBase, NodePath):
# Toggle if you wish widget's to snap to grid when draggin # Toggle if you wish widget's to snap to grid when draggin

View File

@ -72,13 +72,6 @@ class ProjectileInterval(Interval):
self.projectileIntervalNum) self.projectileIntervalNum)
ProjectileInterval.projectileIntervalNum += 1 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, args = (startPos, endPos, duration, startVel, endZ,
wayPoint, timeToWayPoint, gravityMult) wayPoint, timeToWayPoint, gravityMult)
self.implicitStartPos = 0 self.implicitStartPos = 0

View File

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

View File

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

View File

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

View File

@ -1,18 +1,14 @@
"""Contains miscellaneous utility functions and classes."""
"""Undocumented Module"""
__all__ = ['indent', __all__ = ['indent',
'StackTrace', 'traceFunctionCall', 'traceParentCall', 'printThisCall',
'doc', 'adjust', 'difference', 'intersection', 'union', 'doc', 'adjust', 'difference', 'intersection', 'union',
'sameElements', 'makeList', 'makeTuple', 'list2dict', 'invertDict', 'sameElements', 'makeList', 'makeTuple', 'list2dict', 'invertDict',
'invertDictLossless', 'uniqueElements', 'disjoint', 'contains', 'invertDictLossless', 'uniqueElements', 'disjoint', 'contains',
'replace', 'reduceAngle', 'fitSrcAngle2Dest', 'fitDestAngle2Src', 'replace', 'reduceAngle', 'fitSrcAngle2Dest', 'fitDestAngle2Src',
'closestDestAngle2', 'closestDestAngle', 'binaryRepr', 'profileFunc', 'closestDestAngle2', 'closestDestAngle', 'getSetterName',
'profiled', 'startProfile', 'printProfile', 'getSetterName',
'getSetter', 'Functor', 'Stack', 'Queue', 'getSetter', 'Functor', 'Stack', 'Queue',
'bound', 'clamp', 'lerp', 'average', 'addListsByValue', 'bound', 'clamp', 'lerp', 'average', 'addListsByValue',
'boolEqual', 'lineupPos', 'formatElapsedSeconds', 'solveQuadratic', 'boolEqual', 'lineupPos', 'formatElapsedSeconds', 'solveQuadratic',
'stackEntryInfo', 'lineInfo', 'callerInfo', 'lineTag',
'findPythonModule', 'mostDerivedLast', 'findPythonModule', 'mostDerivedLast',
'weightedChoice', 'randFloat', 'normalDistrib', 'weightedChoice', 'randFloat', 'normalDistrib',
'weightedRand', 'randUint31', 'randInt32', 'randUint32', 'weightedRand', 'randUint31', 'randInt32', 'randUint32',
@ -20,41 +16,36 @@ __all__ = ['indent',
'SingletonError', 'printListEnum', 'safeRepr', 'SingletonError', 'printListEnum', 'safeRepr',
'fastRepr', 'isDefaultValue', 'fastRepr', 'isDefaultValue',
'ScratchPad', 'Sync', 'itype', 'getNumberedTypedString', 'ScratchPad', 'Sync', 'itype', 'getNumberedTypedString',
'getNumberedTypedSortedString', 'getNumberedTypedSortedStringWithReferrers', 'getNumberedTypedSortedString',
'getNumberedTypedSortedStringWithReferrersGen',
'printNumberedTyped', 'DelayedCall', 'DelayedFunctor', 'printNumberedTyped', 'DelayedCall', 'DelayedFunctor',
'FrameDelayedCall', 'SubframeCall', 'getBase', 'FrameDelayedCall', 'SubframeCall', 'getBase', 'GoldenRatio',
'HotkeyBreaker','logMethodCalls','GoldenRatio',
'GoldenRectangle', 'rad90', 'rad180', 'rad270', 'rad360', 'GoldenRectangle', 'rad90', 'rad180', 'rad270', 'rad360',
'nullGen', 'loopGen', 'makeFlywheelGen', 'flywheel', 'choice', 'nullGen', 'loopGen', 'makeFlywheelGen', 'flywheel',
'printStack', 'printReverseStack', 'listToIndex2item', 'listToItem2index', 'listToIndex2item', 'listToItem2index',
'pandaBreak','pandaTrace','formatTimeCompact', 'formatTimeCompact','deeptype','StdoutCapture','StdoutPassthrough',
'deeptype','getProfileResultString','StdoutCapture','StdoutPassthrough',
'Averager', 'getRepository', 'formatTimeExact', 'startSuperLog', 'endSuperLog', 'Averager', 'getRepository', 'formatTimeExact', 'startSuperLog', 'endSuperLog',
'typeName', 'safeTypeName', 'histogramDict', 'unescapeHtmlString'] 'typeName', 'safeTypeName', 'histogramDict', 'unescapeHtmlString']
if __debug__:
__all__ += ['StackTrace', 'traceFunctionCall', 'traceParentCall', 'printThisCall',
'stackEntryInfo', 'lineInfo', 'callerInfo', 'lineTag',
'profileFunc', 'profiled', 'startProfile', 'printProfile',
'getProfileResultString', 'printStack', 'printReverseStack']
import types import types
import string import string
import math import math
import operator
import inspect
import os import os
import sys import sys
import random import random
import time import time
import gc
#if __debug__:
import traceback
import __builtin__ import __builtin__
from StringIO import StringIO import importlib
import marshal
__report_indent = 3 __report_indent = 3
from panda3d.core import ConfigVariableBool from panda3d.core import ConfigVariableBool
ScalarTypes = (types.FloatType, types.IntType, types.LongType)
""" """
# with one integer positional arg, this uses about 4/5 of the memory of the Functor class below # with one integer positional arg, this uses about 4/5 of the memory of the Functor class below
def Functor(function, *args, **kArgs): def Functor(function, *args, **kArgs):
@ -92,15 +83,6 @@ class Functor:
_kargs.update(kargs) _kargs.update(kargs)
return self._function(*(self._args + args), **_kargs) return self._function(*(self._args + args), **_kargs)
# this method is used in place of __call__ if we are recording creation stacks
def _exceptionLoggedCreationStack__call__(self, *args, **kargs):
try:
return self._do__call__(*args, **kargs)
except Exception, e:
print '-->Functor creation stack (%s): %s' % (
self.__name__, self.getCreationStackTraceCompactStr())
raise
__call__ = _do__call__ __call__ = _do__call__
def __repr__(self): def __repr__(self):
@ -186,10 +168,10 @@ def indent(stream, numIndents, str):
stream.write(' ' * numIndents + str) stream.write(' ' * numIndents + str)
#if __debug__: #RAU accdg to Darren its's ok that StackTrace is not protected by __debug__ if __debug__:
# DCR: if somebody ends up using StackTrace in production, either import traceback
# A) it will be OK because it hardly ever gets called, or import marshal
# B) it will be easy to track it down (grep for StackTrace)
class StackTrace: class StackTrace:
def __init__(self, label="", start=0, limit=None): def __init__(self, label="", start=0, limit=None):
""" """
@ -327,7 +309,6 @@ def adjust(command = None, dim = 1, parent = None, **kw):
# Make sure we enable Tk # Make sure we enable Tk
# Don't use a regular import, to prevent ModuleFinder from picking # Don't use a regular import, to prevent ModuleFinder from picking
# it up as a dependency when building a .p3d package. # it up as a dependency when building a .p3d package.
import importlib
Valuator = importlib.import_module('direct.tkwidgets.Valuator') Valuator = importlib.import_module('direct.tkwidgets.Valuator')
# Set command if specified # Set command if specified
if command: if command:
@ -579,19 +560,6 @@ def closestDestAngle(src, dest):
# otherwise just go to the original destination # otherwise just go to the original destination
return dest return dest
def binaryRepr(number, max_length = 32):
# This will only work reliably for relatively small numbers.
# Increase the value of max_length if you think you're going
# to use long integers
assert number < 2L << max_length
shifts = map (operator.rshift, max_length * [number], \
range (max_length - 1, -1, -1))
digits = map (operator.mod, shifts, max_length * [2])
if not digits.count (1): return 0
digits = digits [digits.index (1):]
return ''.join([repr(digit) for digit in digits])
class StdoutCapture: class StdoutCapture:
# redirects stdout to a string # redirects stdout to a string
def __init__(self): def __init__(self):
@ -618,6 +586,9 @@ class StdoutPassthrough(StdoutCapture):
self._oldStdout.write(string) self._oldStdout.write(string)
# constant profile defaults # constant profile defaults
if __debug__:
from StringIO import StringIO
PyUtilProfileDefaultFilename = 'profiledata' PyUtilProfileDefaultFilename = 'profiledata'
PyUtilProfileDefaultLines = 80 PyUtilProfileDefaultLines = 80
PyUtilProfileDefaultSorts = ['cumulative', 'time', 'calls'] PyUtilProfileDefaultSorts = ['cumulative', 'time', 'calls']
@ -1032,6 +1003,7 @@ def solveQuadratic(a, b, c):
root2 = ((-b) + sqrtD) / twoA root2 = ((-b) + sqrtD) / twoA
return [root1, root2] return [root1, root2]
if __debug__:
def stackEntryInfo(depth=0, baseFileName=1): def stackEntryInfo(depth=0, baseFileName=1):
""" """
returns the sourcefilename, line number, and function name of returns the sourcefilename, line number, and function name of
@ -1042,6 +1014,8 @@ def stackEntryInfo(depth=0, baseFileName=1):
returns (fileName, lineNum, funcName) --> (string, int, string) returns (fileName, lineNum, funcName) --> (string, int, string)
returns (None, None, None) on error returns (None, None, None) on error
""" """
import inspect
try: try:
stack = None stack = None
frame = None frame = None
@ -1756,43 +1730,6 @@ def getNumberedTypedSortedString(items, maxLen=5000, numPrefix=''):
s += format % (i, itype(items[i]), strs[i]) s += format % (i, itype(items[i]), strs[i])
return s return s
def getNumberedTypedSortedStringWithReferrersGen(items, maxLen=10000, numPrefix=''):
"""get a string that has each item of the list on its own line,
the items are stringwise-sorted, the object's referrers are shown,
and each item is numbered on the left from zero"""
digits = 0
n = len(items)
while n > 0:
digits += 1
n //= 10
digits = digits
format = numPrefix + '%0' + '%s' % digits + 'i:%s @ %s \t%s'
snip = '<SNIP>'
strs = []
for item in items:
strs.append(fastRepr(item))
strs.sort()
for i in xrange(len(strs)):
item = items[i]
objStr = strs[i]
objStr += ', \tREFERRERS=['
referrers = gc.get_referrers(item)
for ref in referrers:
objStr += '%s@%s, ' % (itype(ref), id(ref))
objStr += ']'
if len(objStr) > maxLen:
objStr = '%s%s' % (objStr[:(maxLen-len(snip))], snip)
yield format % (i, itype(items[i]), id(items[i]), objStr)
def getNumberedTypedSortedStringWithReferrers(items, maxLen=10000, numPrefix=''):
"""get a string that has each item of the list on its own line,
the items are stringwise-sorted, the object's referrers are shown,
and each item is numbered on the left from zero"""
s = ''
for line in getNumberedTypedSortedStringWithReferrersGen(items, maxLen, numPrefix):
s += '%s\n' % line
return s
def printNumberedTyped(items, maxLen=5000): def printNumberedTyped(items, maxLen=5000):
"""print out each item of the list on its own line, """print out each item of the list on its own line,
with each item numbered on the left from zero""" with each item numbered on the left from zero"""
@ -2114,7 +2051,7 @@ def report(types = [], prefix = '', xform = None, notifyFunc = None, dConfigPara
except NameError,e: except NameError,e:
return decorator return decorator
from direct.distributed.ClockDelta import globalClockDelta globalClockDelta = importlib.import_module("direct.distributed.ClockDelta").globalClockDelta
def decorator(f): def decorator(f):
def wrap(*args,**kwargs): def wrap(*args,**kwargs):
@ -2210,7 +2147,7 @@ def getRepository():
return simbase.air return simbase.air
exceptionLoggedNotify = None exceptionLoggedNotify = None
if __debug__:
def exceptionLogged(append=True): def exceptionLogged(append=True):
"""decorator that outputs the function name and all arguments """decorator that outputs the function name and all arguments
if an exception passes back through the stack frame if an exception passes back through the stack frame
@ -2262,76 +2199,6 @@ def exceptionLogged(append=True):
return _exceptionLogged return _exceptionLogged
return _decoratorFunc return _decoratorFunc
# class 'decorator' that records the stack at the time of creation
# be careful with this, it creates a StackTrace, and that can take a
# lot of CPU
def recordCreationStack(cls):
if not hasattr(cls, '__init__'):
raise 'recordCreationStack: class \'%s\' must define __init__' % cls.__name__
cls.__moved_init__ = cls.__init__
def __recordCreationStack_init__(self, *args, **kArgs):
self._creationStackTrace = StackTrace(start=1)
return self.__moved_init__(*args, **kArgs)
def getCreationStackTrace(self):
return self._creationStackTrace
def getCreationStackTraceCompactStr(self):
return self._creationStackTrace.compact()
def printCreationStackTrace(self):
print self._creationStackTrace
cls.__init__ = __recordCreationStack_init__
cls.getCreationStackTrace = getCreationStackTrace
cls.getCreationStackTraceCompactStr = getCreationStackTraceCompactStr
cls.printCreationStackTrace = printCreationStackTrace
return cls
# like recordCreationStack but stores the stack as a compact stack list-of-strings
# scales well for memory usage
def recordCreationStackStr(cls):
if not hasattr(cls, '__init__'):
raise 'recordCreationStackStr: class \'%s\' must define __init__' % cls.__name__
cls.__moved_init__ = cls.__init__
def __recordCreationStackStr_init__(self, *args, **kArgs):
# store as list of strings to conserve memory
self._creationStackTraceStrLst = StackTrace(start=1).compact().split(',')
return self.__moved_init__(*args, **kArgs)
def getCreationStackTraceCompactStr(self):
return ','.join(self._creationStackTraceStrLst)
def printCreationStackTrace(self):
print ','.join(self._creationStackTraceStrLst)
cls.__init__ = __recordCreationStackStr_init__
cls.getCreationStackTraceCompactStr = getCreationStackTraceCompactStr
cls.printCreationStackTrace = printCreationStackTrace
return cls
# class 'decorator' that logs all method calls for a particular class
def logMethodCalls(cls):
if not hasattr(cls, 'notify'):
raise 'logMethodCalls: class \'%s\' must have a notify' % cls.__name__
for name in dir(cls):
method = getattr(cls, name)
if hasattr(method, '__call__'):
def getLoggedMethodCall(method):
def __logMethodCall__(obj, *args, **kArgs):
s = '%s(' % method.__name__
for arg in args:
try:
argStr = repr(arg)
except:
argStr = 'bad repr: %s' % arg.__class__
s += '%s, ' % argStr
for karg, value in kArgs.items():
s += '%s=%s, ' % (karg, repr(value))
if len(args) or len(kArgs):
s = s[:-2]
s += ')'
obj.notify.info(s)
return method(obj, *args, **kArgs)
return __logMethodCall__
setattr(cls, name, getLoggedMethodCall(method))
__logMethodCall__ = None
return cls
# http://en.wikipedia.org/wiki/Golden_ratio # http://en.wikipedia.org/wiki/Golden_ratio
GoldenRatio = (1. + math.sqrt(5.)) / 2. GoldenRatio = (1. + math.sqrt(5.)) / 2.
class GoldenRectangle: class GoldenRectangle:
@ -2342,45 +2209,6 @@ class GoldenRectangle:
def getShorterEdge(longer): def getShorterEdge(longer):
return longer / GoldenRatio return longer / GoldenRatio
class HotkeyBreaker:
def __init__(self,breakKeys = []):
from direct.showbase.DirectObject import DirectObject
self.do = DirectObject()
self.breakKeys = {}
if not isinstance(breakKeys, (list,tuple)):
breakKeys = (breakKeys,)
for key in breakKeys:
self.addBreakKey(key)
def addBreakKey(self,breakKey):
if __dev__:
self.do.accept(breakKey,self.breakFunc,extraArgs = [breakKey])
def removeBreakKey(self,breakKey):
if __dev__:
self.do.ignore(breakKey)
def breakFunc(self,breakKey):
if __dev__:
self.breakKeys[breakKey] = True
def setBreakPt(self, breakKey = None, persistent = False):
if __dev__:
if not breakKey:
import pdb;pdb.set_trace()
return True
else:
if self.breakKeys.get(breakKey,False):
if not persistent:
self.breakKeys.pop(breakKey)
import pdb;pdb.set_trace()
return True
return True
def clearBreakPt(self, breakKey):
if __dev__:
return bool(self.breakKeys.pop(breakKey,None))
def nullGen(): def nullGen():
# generator that ends immediately # generator that ends immediately
if False: if False:
@ -2480,6 +2308,7 @@ if __debug__ and __name__ == '__main__':
assert obj2count[3] == 3 * 3 assert obj2count[3] == 3 * 3
assert obj2count[4] == 4 * 3 assert obj2count[4] == 4 * 3
if __debug__:
def quickProfile(name="unnamed"): def quickProfile(name="unnamed"):
import pstats import pstats
def profileDecorator(f): def profileDecorator(f):
@ -2496,6 +2325,7 @@ def quickProfile(name="unnamed"):
print "Function %s.%s took %s seconds"%(f.__module__, f.__name__,s) print "Function %s.%s took %s seconds"%(f.__module__, f.__name__,s)
else: else:
import profile as prof, pstats import profile as prof, pstats
#detailed profile, stored in base.stats under ( #detailed profile, stored in base.stats under (
if(not hasattr(base,"stats")): if(not hasattr(base,"stats")):
base.stats={} base.stats={}
@ -2533,13 +2363,6 @@ def getAnnounceGenerateTime(stat):
return val return val
def choice(condition, ifTrue, ifFalse):
# equivalent of C++ (condition ? ifTrue : ifFalse)
if condition:
return ifTrue
else:
return ifFalse
class MiniLog: class MiniLog:
def __init__(self, name): def __init__(self, name):
self.indent = 1 self.indent = 1
@ -2611,14 +2434,6 @@ class HierarchyException(Exception):
def __repr__(self): def __repr__(self):
return 'HierarchyException(%s)' % (self.owner, ) return 'HierarchyException(%s)' % (self.owner, )
# __dev__ is not defined at import time, call this after it's defined
def recordFunctorCreationStacks():
global Functor
if not hasattr(Functor, '_functorCreationStacksRecorded'):
Functor = recordCreationStackStr(Functor)
Functor._functorCreationStacksRecorded = True
Functor.__call__ = Functor._exceptionLoggedCreationStack__call__
def formatTimeCompact(seconds): def formatTimeCompact(seconds):
# returns string in format '1d3h22m43s' # returns string in format '1d3h22m43s'
result = '' result = ''
@ -2735,57 +2550,6 @@ if __debug__ and __name__ == '__main__':
testAlphabetCounter() testAlphabetCounter()
del testAlphabetCounter del testAlphabetCounter
globalPdb = None
traceCalled = False
def setupPdb():
import pdb;
class pandaPdb(pdb.Pdb):
def stop_here(self, frame):
global traceCalled
if(traceCalled):
result = pdb.Pdb.stop_here(self, frame)
if(result == True):
traceCalled = False
return result
if frame is self.stopframe:
return True
return False
global globalPdb
globalPdb = pandaPdb()
globalPdb.reset()
sys.settrace(globalPdb.trace_dispatch)
def pandaTrace():
if __dev__:
if not globalPdb:
setupPdb()
global traceCalled
globalPdb.set_trace(sys._getframe().f_back)
traceCalled = True
packageMap = {
"toontown":"$TOONTOWN",
"direct":"$DIRECT",
"otp":"$OTP",
"pirates":"$PIRATES",
}
#assuming . dereferncing for nice linking to imports
def pandaBreak(dotpath, linenum, temporary = 0, cond = None):
if __dev__:
from panda3d.core import Filename
if not globalPdb:
setupPdb()
dirs = dotpath.split(".")
root = Filename.expandFrom(packageMap[dirs[0]]).toOsSpecific()
filename = root + "\\src"
for d in dirs[1:]:
filename="%s\\%s"%(filename,d)
print filename
globalPdb.set_break(filename+".py", linenum, temporary, cond)
class Default: class Default:
# represents 'use the default value' # represents 'use the default value'
@ -2917,15 +2681,17 @@ __builtin__.SerialMaskedGen = SerialMaskedGen
__builtin__.ScratchPad = ScratchPad __builtin__.ScratchPad = ScratchPad
__builtin__.uniqueName = uniqueName __builtin__.uniqueName = uniqueName
__builtin__.serialNum = serialNum __builtin__.serialNum = serialNum
if __debug__:
__builtin__.profiled = profiled __builtin__.profiled = profiled
__builtin__.itype = itype
__builtin__.exceptionLogged = exceptionLogged __builtin__.exceptionLogged = exceptionLogged
__builtin__.itype = itype
__builtin__.appendStr = appendStr __builtin__.appendStr = appendStr
__builtin__.bound = bound __builtin__.bound = bound
__builtin__.clamp = clamp __builtin__.clamp = clamp
__builtin__.lerp = lerp __builtin__.lerp = lerp
__builtin__.makeList = makeList __builtin__.makeList = makeList
__builtin__.makeTuple = makeTuple __builtin__.makeTuple = makeTuple
if __debug__:
__builtin__.printStack = printStack __builtin__.printStack = printStack
__builtin__.printReverseStack = printReverseStack __builtin__.printReverseStack = printReverseStack
__builtin__.printVerboseStack = printVerboseStack __builtin__.printVerboseStack = printVerboseStack
@ -2942,8 +2708,8 @@ __builtin__.fastRepr = fastRepr
__builtin__.nullGen = nullGen __builtin__.nullGen = nullGen
__builtin__.flywheel = flywheel __builtin__.flywheel = flywheel
__builtin__.loopGen = loopGen __builtin__.loopGen = loopGen
if __debug__:
__builtin__.StackTrace = StackTrace __builtin__.StackTrace = StackTrace
__builtin__.choice = choice
__builtin__.report = report __builtin__.report = report
__builtin__.pstatcollect = pstatcollect __builtin__.pstatcollect = pstatcollect
__builtin__.MiniLog = MiniLog __builtin__.MiniLog = MiniLog

View File

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

View File

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

View File

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

View File

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

View File

@ -42,6 +42,7 @@ __all__ = [
] ]
local = _thread._local local = _thread._local
_newname = _thread._newname
class ThreadBase: class ThreadBase:
""" A base class for both Thread and ExternalThread in this """ A base class for both Thread and ExternalThread in this
@ -98,8 +99,7 @@ class Thread(ThreadBase):
self.__kwargs = kwargs self.__kwargs = kwargs
if not name: if not name:
import threading2 name = _newname()
name = threading2._newname()
current = current_thread() current = current_thread()
self.__dict__['daemon'] = current.daemon self.__dict__['daemon'] = current.daemon
@ -404,9 +404,10 @@ def setprofile(func):
def stack_size(size = None): def stack_size(size = None):
raise ThreadError raise ThreadError
if __debug__:
def _test(): def _test():
from collections import deque from collections import deque
_sleep = core.Thread.sleep _sleep = core.Thread.sleep
_VERBOSE = False _VERBOSE = False

View File

@ -16,13 +16,12 @@ implementation. """
import sys as _sys import sys as _sys
from direct.stdpy import thread 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 from panda3d import core
_sleep = core.Thread.sleep _sleep = core.Thread.sleep
from time import time as _time from time import time as _time
from traceback import format_exc as _format_exc from traceback import format_exc as _format_exc
from collections import deque
# Rename some stuff so "from threading import *" is safe # Rename some stuff so "from threading import *" is safe
__all__ = ['activeCount', 'Condition', 'currentThread', 'enumerate', 'Event', __all__ = ['activeCount', 'Condition', 'currentThread', 'enumerate', 'Event',
@ -377,13 +376,6 @@ class _Event(_Verbose):
finally: finally:
self.__cond.release() 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 thread administration
_active_limbo_lock = _allocate_lock() _active_limbo_lock = _allocate_lock()
_active = {} # maps thread id to Thread object _active = {} # maps thread id to Thread object
@ -741,8 +733,9 @@ _shutdown = _MainThread()._exitfunc
# Self-test code # Self-test code
if __debug__:
def _test(): def _test():
from collections import deque
class BoundedQueue(_Verbose): class BoundedQueue(_Verbose):

View File

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