|
|
@@ -3,7 +3,10 @@ from direct.showbase.PythonUtil import Queue, invertDictLossless
|
|
|
from direct.showbase.PythonUtil import safeRepr
|
|
|
from direct.showbase.Job import Job
|
|
|
from direct.showbase.JobManagerGlobal import jobMgr
|
|
|
+from direct.showbase.ContainerLeakDetector import deadEndTypes
|
|
|
import types
|
|
|
+import sys
|
|
|
+import io
|
|
|
|
|
|
|
|
|
class ContainerReport(Job):
|
|
|
@@ -89,14 +92,6 @@ class ContainerReport(Job):
|
|
|
if isinstance(parentObj, (str, bytes)):
|
|
|
continue
|
|
|
|
|
|
- if type(parentObj) in (types.ModuleType, types.InstanceType):
|
|
|
- child = parentObj.__dict__
|
|
|
- if self._examine(child):
|
|
|
- assert self._queue.back() is child
|
|
|
- self._instanceDictIds.add(id(child))
|
|
|
- self._id2pathStr[id(child)] = str(self._id2pathStr[id(parentObj)])
|
|
|
- continue
|
|
|
-
|
|
|
if isinstance(parentObj, dict):
|
|
|
key = None
|
|
|
attr = None
|
|
|
@@ -126,7 +121,25 @@ class ContainerReport(Job):
|
|
|
del attr
|
|
|
continue
|
|
|
|
|
|
- if type(parentObj) is not types.FileType:
|
|
|
+ # types.CellType was added in Python 3.8
|
|
|
+ if sys.version_info >= (3, 8) and type(parentObj) is types.CellType:
|
|
|
+ child = parentObj.cell_contents
|
|
|
+ if self._examine(child):
|
|
|
+ assert (self._queue.back() is child)
|
|
|
+ self._instanceDictIds.add(id(child))
|
|
|
+ self._id2pathStr[id(child)] = str(self._id2pathStr[id(parentObj)]) + '.cell_contents'
|
|
|
+ continue
|
|
|
+
|
|
|
+ if hasattr(parentObj, '__dict__'):
|
|
|
+ # Instance of a class
|
|
|
+ child = parentObj.__dict__
|
|
|
+ if self._examine(child):
|
|
|
+ assert (self._queue.back() is child)
|
|
|
+ self._instanceDictIds.add(id(child))
|
|
|
+ self._id2pathStr[id(child)] = str(self._id2pathStr[id(parentObj)])
|
|
|
+ continue
|
|
|
+
|
|
|
+ if not isinstance(parentObj, io.TextIOWrapper):
|
|
|
try:
|
|
|
itr = iter(parentObj)
|
|
|
except:
|
|
|
@@ -161,7 +174,10 @@ class ContainerReport(Job):
|
|
|
childName = None
|
|
|
child = None
|
|
|
for childName in childNames:
|
|
|
- child = getattr(parentObj, childName)
|
|
|
+ try:
|
|
|
+ child = getattr(parentObj, childName)
|
|
|
+ except:
|
|
|
+ continue
|
|
|
if id(child) not in self._visitedIds:
|
|
|
self._visitedIds.add(id(child))
|
|
|
if self._examine(child):
|
|
|
@@ -198,9 +214,7 @@ class ContainerReport(Job):
|
|
|
self._type2id2len[type(obj)][objId] = length
|
|
|
def _examine(self, obj):
|
|
|
# return False if it's an object that can't contain or lead to other objects
|
|
|
- if type(obj) in (bool, types.BuiltinFunctionType, types.BuiltinMethodType,
|
|
|
- complex, float, int, type(None), type(NotImplemented),
|
|
|
- type, types.CodeType, types.FunctionType):
|
|
|
+ if type(obj) in deadEndTypes:
|
|
|
return False
|
|
|
# if it's an internal object, ignore it
|
|
|
if id(obj) in ContainerReport.PrivateIds:
|
|
|
@@ -243,7 +257,7 @@ class ContainerReport(Job):
|
|
|
for i in self._outputType(type, **kArgs):
|
|
|
yield None
|
|
|
otherTypes = list(set(self._type2id2len.keys()).difference(set(initialTypes)))
|
|
|
- otherTypes.sort()
|
|
|
+ otherTypes.sort(key=lambda obj: obj.__name__)
|
|
|
for type in otherTypes:
|
|
|
for i in self._outputType(type, **kArgs):
|
|
|
yield None
|