Browse Source

More Python 3 support, and a bit of work toward being able to compile as panda3d/core.pyd, etc.

rdb 12 years ago
parent
commit
2275784525

+ 43 - 18
direct/src/extensions_native/extension_native_helpers.py

@@ -1,7 +1,7 @@
 ###  Tools
 ###  Tools
 __all__ = ["Dtool_ObjectToDict", "Dtool_funcToMethod", "Dtool_PreloadDLL"]
 __all__ = ["Dtool_ObjectToDict", "Dtool_funcToMethod", "Dtool_PreloadDLL"]
 
 
-import imp,sys,os
+import imp, sys, os
 
 
 # The following code exists to work around a problem that exists
 # The following code exists to work around a problem that exists
 # with Python 2.5 or greater.
 # with Python 2.5 or greater.
@@ -15,6 +15,7 @@ dll_suffix = ''
 if sys.platform == "win32":
 if sys.platform == "win32":
     # On Windows, dynamic libraries end in ".dll".
     # On Windows, dynamic libraries end in ".dll".
     dll_ext = '.dll'
     dll_ext = '.dll'
+    module_ext = '.pyd'
 
 
     # We allow the caller to preload dll_suffix into the sys module.
     # We allow the caller to preload dll_suffix into the sys module.
     dll_suffix = getattr(sys, 'dll_suffix', None)
     dll_suffix = getattr(sys, 'dll_suffix', None)
@@ -33,9 +34,11 @@ elif sys.platform == "darwin":
         from direct.extensions_native.extensions_darwin import dll_ext
         from direct.extensions_native.extensions_darwin import dll_ext
     except ImportError:
     except ImportError:
         dll_ext = '.dylib'
         dll_ext = '.dylib'
+    module_ext = '.so'
 else:
 else:
     # On most other UNIX systems (including linux), .so is used.
     # On most other UNIX systems (including linux), .so is used.
     dll_ext = '.so'
     dll_ext = '.so'
+    module_ext = '.so'
 
 
 if sys.platform == "win32":
 if sys.platform == "win32":
     # On Windows, we must furthermore ensure that the PATH is modified
     # On Windows, we must furthermore ensure that the PATH is modified
@@ -51,47 +54,69 @@ if sys.platform == "win32":
             target = dir
             target = dir
     if target == None:
     if target == None:
         message = "Cannot find %s" % (filename)
         message = "Cannot find %s" % (filename)
-        raise ImportError, message
+        raise ImportError(message)
 
 
     # And add that directory to the system path.
     # And add that directory to the system path.
     path = os.environ["PATH"]
     path = os.environ["PATH"]
     if not path.startswith(target + ";"):
     if not path.startswith(target + ";"):
         os.environ["PATH"] = target + ";" + path
         os.environ["PATH"] = target + ";" + path
 
 
+def Dtool_FindModule(module):
+    # Finds a .pyd module on the Python path.
+    filename = module.replace('.', os.path.sep) + module_ext
+    for dir in sys.path:
+        lib = os.path.join(dir, filename)
+        if (os.path.exists(lib)):
+            return lib
+
+    return None
+
 def Dtool_PreloadDLL(module):
 def Dtool_PreloadDLL(module):
     if module in sys.modules:
     if module in sys.modules:
         return
         return
 
 
+    # First find it as a .pyd module on the Python path.
+    if Dtool_FindModule(module):
+        # OK, we should have no problem importing it as is.
+        return
+
+    # Nope, we'll need to search for a dynamic lib and preload it.
     # Search for the appropriate directory.
     # Search for the appropriate directory.
     target = None
     target = None
-    filename = module + dll_suffix + dll_ext
+    filename = module.replace('.', os.path.sep) + dll_suffix + dll_ext
     for dir in sys.path + [sys.prefix]:
     for dir in sys.path + [sys.prefix]:
         lib = os.path.join(dir, filename)
         lib = os.path.join(dir, filename)
         if (os.path.exists(lib)):
         if (os.path.exists(lib)):
             target = dir
             target = dir
             break
             break
-    if target == None:
+
+    if target is None:
         message = "DLL loader cannot find %s." % (module)
         message = "DLL loader cannot find %s." % (module)
-        raise ImportError, message
+        raise ImportError(message)
 
 
     # Now import the file explicitly.
     # Now import the file explicitly.
     pathname = os.path.join(target, filename)
     pathname = os.path.join(target, filename)
-    imp.load_dynamic(module, pathname)
+    imp.load_dynamic(module, pathname)    
 
 
-Dtool_PreloadDLL("libpandaexpress")
-from libpandaexpress import *
+# Nowadays, we can compile libpandaexpress with libpanda into a
+# .pyd file called panda3d/core.pyd which can be imported without
+# any difficulty.  Let's see if this is the case.
+if Dtool_FindModule("panda3d.core"):
+    from panda3d.core import *
+else:
+    Dtool_PreloadDLL("libpandaexpress")
+    from libpandaexpress import *
 
 
-def Dtool_ObjectToDict(clas, name, obj):
-    clas.DtoolClassDict[name] = obj;
+def Dtool_ObjectToDict(cls, name, obj):
+    cls.DtoolClassDict[name] = obj;
 
 
-def Dtool_funcToMethod(func, clas, method_name=None):
+def Dtool_funcToMethod(func, cls, method_name=None):
     """Adds func to class so it is an accessible method; use method_name to specify the name to be used for calling the method.
     """Adds func to class so it is an accessible method; use method_name to specify the name to be used for calling the method.
     The new method is accessible to any instance immediately."""
     The new method is accessible to any instance immediately."""
-    func.im_class=clas
-    func.im_func=func
-    func.im_self=None
+    if sys.version_info < (3, 0):
+        func.im_class = cls
+    func.im_func = func
+    func.im_self = None
     if not method_name:
     if not method_name:
-            method_name = func.__name__
-    clas.DtoolClassDict[method_name] = func;
-
-
+        method_name = func.__name__
+    cls.DtoolClassDict[method_name] = func;

+ 29 - 6
direct/src/ffi/DoGenPyCode.py

@@ -224,7 +224,7 @@ def doErrorCheck():
         FFIConstants.CodeModuleNameList = codeLibs
         FFIConstants.CodeModuleNameList = codeLibs
 
 
 def generateNativeWrappers():
 def generateNativeWrappers():
-    from direct.extensions_native.extension_native_helpers import Dtool_PreloadDLL
+    from direct.extensions_native.extension_native_helpers import Dtool_FindModule, Dtool_PreloadDLL
 
 
     # Empty out the output directories of unnecessary crud from
     # Empty out the output directories of unnecessary crud from
     # previous runs before we begin.
     # previous runs before we begin.
@@ -256,27 +256,50 @@ def generateNativeWrappers():
     for moduleName in FFIConstants.CodeModuleNameList:
     for moduleName in FFIConstants.CodeModuleNameList:
         print('Importing code library: ' + moduleName)
         print('Importing code library: ' + moduleName)
         Dtool_PreloadDLL(moduleName)
         Dtool_PreloadDLL(moduleName)
-        exec('import %s as module' % moduleName)
+
+        __import__(moduleName)
+        module = sys.modules[moduleName]
+
+        # Make a suitable meta module name
+        metaModuleName = ""
+        nextCap = False
+        for ch in moduleName:
+            if ch == '.':
+                nextCap = True
+            elif nextCap:
+                metaModuleName += ch.upper()
+                nextCap = False
+            else:
+                metaModuleName += ch
+        metaModuleName += "Modules"
 
 
         # Wrap the import in a try..except so that we can continue if
         # Wrap the import in a try..except so that we can continue if
         # the library isn't present.  This is particularly necessary
         # the library isn't present.  This is particularly necessary
         # in the runtime (plugin) environment, where all libraries are
         # in the runtime (plugin) environment, where all libraries are
         # not necessarily downloaded.
         # not necessarily downloaded.
-        pandaModules.write('try:\n  from %sModules import *\nexcept ImportError, err:\n  if "DLL loader cannot find" not in str(err):\n    raise\n' % (moduleName))
+        if sys.version_info >= (3, 0):
+            pandaModules.write('try:\n  from .%s import *\nexcept ImportError as err:\n  if "DLL loader cannot find" not in str(err):\n    raise\n' % (metaModuleName))
+        else:
+            pandaModules.write('try:\n  from %s import *\nexcept ImportError, err:\n  if "DLL loader cannot find" not in str(err):\n    raise\n' % (metaModuleName))
+
         # Not sure if this message is helpful or annoying.
         # Not sure if this message is helpful or annoying.
         #pandaModules.write('  print("Failed to import %s")\n' % (moduleName))
         #pandaModules.write('  print("Failed to import %s")\n' % (moduleName))
         pandaModules.write('\n')
         pandaModules.write('\n')
 
 
-        moduleModulesFilename = os.path.join(outputCodeDir, '%sModules.py' % (moduleName))
+        moduleModulesFilename = os.path.join(outputCodeDir, '%s.py' % (metaModuleName))
         moduleModules = open(moduleModulesFilename, 'w')
         moduleModules = open(moduleModulesFilename, 'w')
 
 
-        moduleModules.write('from extension_native_helpers import *\n')
+        if sys.version_info >= (3, 0):
+            moduleModules.write('from .extension_native_helpers import *\n')
+        else:
+            moduleModules.write('from extension_native_helpers import *\n')
         moduleModules.write('Dtool_PreloadDLL("%s")\n' % (moduleName))
         moduleModules.write('Dtool_PreloadDLL("%s")\n' % (moduleName))
+
         moduleModules.write('from %s import *\n\n' % (moduleName))
         moduleModules.write('from %s import *\n\n' % (moduleName))
 
 
         # Now look for extensions
         # Now look for extensions
         for className, classDef in module.__dict__.items():
         for className, classDef in module.__dict__.items():
-            if type(classDef) == types.TypeType:
+            if isinstance(classDef, type):
                 extensionFilename = os.path.join(extensionsDir, '%s_extensions.py' % (className))
                 extensionFilename = os.path.join(extensionsDir, '%s_extensions.py' % (className))
                 if os.path.exists(extensionFilename):
                 if os.path.exists(extensionFilename):
                     print('  Found extensions for class: %s' % (className))
                     print('  Found extensions for class: %s' % (className))

+ 1 - 1
direct/src/fsm/StatePush.py

@@ -238,7 +238,7 @@ class FunctionCall(ReceivesMultipleStateChanges, PushesStateChanges):
     def _recvMultiStatePush(self, key, source):
     def _recvMultiStatePush(self, key, source):
         # one of the arguments changed
         # one of the arguments changed
         # pick up the new value
         # pick up the new value
-        if isinstance(key, types.StringType):
+        if isinstance(key, str):
             self._bakedKargs[key] = source.getState()
             self._bakedKargs[key] = source.getState()
         else:
         else:
             self._bakedArgs[key] = source.getState()
             self._bakedArgs[key] = source.getState()

+ 0 - 1
direct/src/showbase/ExceptionVarDump.py

@@ -1,7 +1,6 @@
 from pandac.PandaModules import getConfigShowbase
 from pandac.PandaModules import getConfigShowbase
 from direct.directnotify.DirectNotifyGlobal import directNotify
 from direct.directnotify.DirectNotifyGlobal import directNotify
 from direct.showbase.PythonUtil import fastRepr
 from direct.showbase.PythonUtil import fastRepr
-from exceptions import Exception
 import sys
 import sys
 import types
 import types
 import traceback
 import traceback

+ 18 - 19
direct/src/showbase/Finder.py

@@ -5,7 +5,6 @@ __all__ = ['findClass', 'rebindClass', 'copyFuncs', 'replaceMessengerFunc', 'rep
 import time
 import time
 import types
 import types
 import os
 import os
-import new
 import sys
 import sys
 
 
 def findClass(className):
 def findClass(className):
@@ -107,24 +106,24 @@ def copyFuncs(fromClass, toClass):
                 #   SystemError: cellobject.c:22: bad argument to internal function
                 #   SystemError: cellobject.c:22: bad argument to internal function
                 # Give the new function code the same filename as the old function
                 # Give the new function code the same filename as the old function
                 # Perhaps there is a cleaner way to do this? This was my best idea.
                 # Perhaps there is a cleaner way to do this? This was my best idea.
-                newCode = new.code(newFunc.func_code.co_argcount,
-                                   newFunc.func_code.co_nlocals,
-                                   newFunc.func_code.co_stacksize,
-                                   newFunc.func_code.co_flags,
-                                   newFunc.func_code.co_code,
-                                   newFunc.func_code.co_consts,
-                                   newFunc.func_code.co_names,
-                                   newFunc.func_code.co_varnames,
-                                   # Use the oldFunc's filename here. Tricky!
-                                   oldFunc.func_code.co_filename,
-                                   newFunc.func_code.co_name,
-                                   newFunc.func_code.co_firstlineno,
-                                   newFunc.func_code.co_lnotab)
-                newFunc = new.function(newCode,
-                                       newFunc.func_globals,
-                                       newFunc.func_name,
-                                       newFunc.func_defaults,
-                                       newFunc.func_closure)
+                newCode = types.CodeType(newFunc.func_code.co_argcount,
+                                         newFunc.func_code.co_nlocals,
+                                         newFunc.func_code.co_stacksize,
+                                         newFunc.func_code.co_flags,
+                                         newFunc.func_code.co_code,
+                                         newFunc.func_code.co_consts,
+                                         newFunc.func_code.co_names,
+                                         newFunc.func_code.co_varnames,
+                                         # Use the oldFunc's filename here. Tricky!
+                                         oldFunc.func_code.co_filename,
+                                         newFunc.func_code.co_name,
+                                         newFunc.func_code.co_firstlineno,
+                                         newFunc.func_code.co_lnotab)
+                newFunc = types.FunctionType(newCode,
+                                             newFunc.func_globals,
+                                             newFunc.func_name,
+                                             newFunc.func_defaults,
+                                             newFunc.func_closure)
                 """
                 """
                 replaceFuncList.append((oldFunc, funcName, newFunc))
                 replaceFuncList.append((oldFunc, funcName, newFunc))
             else:
             else:

+ 19 - 17
direct/src/showbase/PythonUtil.py

@@ -168,7 +168,7 @@ class Queue:
     def __len__(self):
     def __len__(self):
         return len(self.__list)
         return len(self.__list)
 
 
-if __debug__:
+if __debug__ and __name__ == '__main__':
     q = Queue()
     q = Queue()
     assert q.isEmpty()
     assert q.isEmpty()
     q.clear()
     q.clear()
@@ -615,7 +615,7 @@ class Signature:
                 l.append('*' + specials['positional'])
                 l.append('*' + specials['positional'])
             if 'keyword' in specials:
             if 'keyword' in specials:
                 l.append('**' + specials['keyword'])
                 l.append('**' + specials['keyword'])
-            return "%s(%s)" % (self.name, string.join(l, ', '))
+            return "%s(%s)" % (self.name, ', '.join(l))
         else:
         else:
             return "%s(?)" % self.name
             return "%s(?)" % self.name
 
 
@@ -908,7 +908,7 @@ def binaryRepr(number, max_length = 32):
     digits = map (operator.mod, shifts, max_length * [2])
     digits = map (operator.mod, shifts, max_length * [2])
     if not digits.count (1): return 0
     if not digits.count (1): return 0
     digits = digits [digits.index (1):]
     digits = digits [digits.index (1):]
-    return string.join (map (repr, digits), '')
+    return ''.join([repr(digit) for digit in digits])
 
 
 class StdoutCapture:
 class StdoutCapture:
     # redirects stdout to a string
     # redirects stdout to a string
@@ -1194,7 +1194,7 @@ def extractProfile(*args, **kArgs):
 def getSetterName(valueName, prefix='set'):
 def getSetterName(valueName, prefix='set'):
     # getSetterName('color') -> 'setColor'
     # getSetterName('color') -> 'setColor'
     # getSetterName('color', 'get') -> 'getColor'
     # getSetterName('color', 'get') -> 'getColor'
-    return '%s%s%s' % (prefix, string.upper(valueName[0]), valueName[1:])
+    return '%s%s%s' % (prefix, valueName[0].upper(), valueName[1:])
 def getSetter(targetObj, valueName, prefix='set'):
 def getSetter(targetObj, valueName, prefix='set'):
     # getSetter(smiley, 'pos') -> smiley.setPos
     # getSetter(smiley, 'pos') -> smiley.setPos
     return getattr(targetObj, getSetterName(valueName, prefix))
     return getattr(targetObj, getSetterName(valueName, prefix))
@@ -1427,6 +1427,8 @@ class ParamObj:
                 # we've already compiled the defaults for this class
                 # we've already compiled the defaults for this class
                 return
                 return
             bases = list(cls.__bases__)
             bases = list(cls.__bases__)
+            if object in bases:
+                bases.remove(object)
             # bring less-derived classes to the front
             # bring less-derived classes to the front
             mostDerivedLast(bases)
             mostDerivedLast(bases)
             cls._Params = {}
             cls._Params = {}
@@ -1612,7 +1614,7 @@ class ParamObj:
             argStr += '%s=%s,' % (param, repr(value))
             argStr += '%s=%s,' % (param, repr(value))
         return '%s(%s)' % (self.__class__.__name__, argStr)
         return '%s(%s)' % (self.__class__.__name__, argStr)
 
 
-if __debug__:
+if __debug__ and __name__ == '__main__':
     class ParamObjTest(ParamObj):
     class ParamObjTest(ParamObj):
         class ParamSet(ParamObj.ParamSet):
         class ParamSet(ParamObj.ParamSet):
             Params = {
             Params = {
@@ -1809,7 +1811,7 @@ class POD:
             argStr += '%s=%s,' % (name, repr(getSetter(self, name, 'get')()))
             argStr += '%s=%s,' % (name, repr(getSetter(self, name, 'get')()))
         return '%s(%s)' % (self.__class__.__name__, argStr)
         return '%s(%s)' % (self.__class__.__name__, argStr)
 
 
-if __debug__:
+if __debug__ and __name__ == '__main__':
     class PODtest(POD):
     class PODtest(POD):
         DataSet = {
         DataSet = {
             'foo': dict,
             'foo': dict,
@@ -2139,7 +2141,7 @@ def pivotScalar(scalar, pivot):
     # reflect scalar about pivot; see tests below
     # reflect scalar about pivot; see tests below
     return pivot + (pivot - scalar)
     return pivot + (pivot - scalar)
 
 
-if __debug__:
+if __debug__ and __name__ == '__main__':
     assert pivotScalar(1, 0) == -1
     assert pivotScalar(1, 0) == -1
     assert pivotScalar(-1, 0) == 1
     assert pivotScalar(-1, 0) == 1
     assert pivotScalar(3, 5) == 7
     assert pivotScalar(3, 5) == 7
@@ -3596,9 +3598,9 @@ def recordCreationStackStr(cls):
         self._creationStackTraceStrLst = StackTrace(start=1).compact().split(',')
         self._creationStackTraceStrLst = StackTrace(start=1).compact().split(',')
         return self.__moved_init__(*args, **kArgs)
         return self.__moved_init__(*args, **kArgs)
     def getCreationStackTraceCompactStr(self):
     def getCreationStackTraceCompactStr(self):
-        return string.join(self._creationStackTraceStrLst, ',')
+        return ','.join(self._creationStackTraceStrLst)
     def printCreationStackTrace(self):
     def printCreationStackTrace(self):
-        print string.join(self._creationStackTraceStrLst, ',')
+        print ','.join(self._creationStackTraceStrLst)
     cls.__init__ = __recordCreationStackStr_init__
     cls.__init__ = __recordCreationStackStr_init__
     cls.getCreationStackTraceCompactStr = getCreationStackTraceCompactStr
     cls.getCreationStackTraceCompactStr = getCreationStackTraceCompactStr
     cls.printCreationStackTrace = printCreationStackTrace
     cls.printCreationStackTrace = printCreationStackTrace
@@ -3750,7 +3752,7 @@ def flywheel(*args, **kArgs):
         pass
         pass
     return flywheel
     return flywheel
 
 
-if __debug__:
+if __debug__ and __name__ == '__main__':
     f = flywheel(['a','b','c','d'], countList=[11,20,3,4])
     f = flywheel(['a','b','c','d'], countList=[11,20,3,4])
     obj2count = {}
     obj2count = {}
     for obj in f:
     for obj in f:
@@ -3944,7 +3946,7 @@ def formatTimeCompact(seconds):
     result += '%ss' % seconds
     result += '%ss' % seconds
     return result
     return result
 
 
-if __debug__:
+if __debug__ and __name__ == '__main__':
     ftc = formatTimeCompact
     ftc = formatTimeCompact
     assert ftc(0) == '0s'
     assert ftc(0) == '0s'
     assert ftc(1) == '1s'
     assert ftc(1) == '1s'
@@ -3980,7 +3982,7 @@ def formatTimeExact(seconds):
         result += '%ss' % seconds
         result += '%ss' % seconds
     return result
     return result
 
 
-if __debug__:
+if __debug__ and __name__ == '__main__':
     fte = formatTimeExact
     fte = formatTimeExact
     assert fte(0) == '0s'
     assert fte(0) == '0s'
     assert fte(1) == '1s'
     assert fte(1) == '1s'
@@ -4019,7 +4021,7 @@ class AlphabetCounter:
                 break
                 break
         return result
         return result
 
 
-if __debug__:
+if __debug__ and __name__ == '__main__':
     def testAlphabetCounter():
     def testAlphabetCounter():
         tempList = []
         tempList = []
         ac = AlphabetCounter()
         ac = AlphabetCounter()
@@ -4195,7 +4197,7 @@ def unescapeHtmlString(s):
         result += char
         result += char
     return result
     return result
 
 
-if __debug__:
+if __debug__ and __name__ == '__main__':
     assert unescapeHtmlString('asdf') == 'asdf'
     assert unescapeHtmlString('asdf') == 'asdf'
     assert unescapeHtmlString('as+df') == 'as df'
     assert unescapeHtmlString('as+df') == 'as df'
     assert unescapeHtmlString('as%32df') == 'as2df'
     assert unescapeHtmlString('as%32df') == 'as2df'
@@ -4252,7 +4254,7 @@ class HTMLStringToElements(HTMLParser):
 def str2elements(str):
 def str2elements(str):
     return HTMLStringToElements(str).getElements()
     return HTMLStringToElements(str).getElements()
 
 
-if __debug__:
+if __debug__ and __name__ == '__main__':
     s = ScratchPad()
     s = ScratchPad()
     assert len(str2elements('')) == 0
     assert len(str2elements('')) == 0
     s.br = str2elements('<br>')
     s.br = str2elements('<br>')
@@ -4292,7 +4294,7 @@ def repeatableRepr(obj):
         return repeatableRepr(l)
         return repeatableRepr(l)
     return repr(obj)
     return repr(obj)
 
 
-if __debug__:
+if __debug__ and __name__ == '__main__':
     assert repeatableRepr({1: 'a', 2: 'b'}) == repeatableRepr({2: 'b', 1: 'a'})
     assert repeatableRepr({1: 'a', 2: 'b'}) == repeatableRepr({2: 'b', 1: 'a'})
     assert repeatableRepr(set([1,2,3])) == repeatableRepr(set([3,2,1]))
     assert repeatableRepr(set([1,2,3])) == repeatableRepr(set([3,2,1]))
 
 
@@ -4349,7 +4351,7 @@ class PriorityCallbacks:
         for priority, callback in self._callbacks:
         for priority, callback in self._callbacks:
             callback()
             callback()
 
 
-if __debug__:
+if __debug__ and __name__ == '__main__':
     l = []
     l = []
     def a(l=l):
     def a(l=l):
         l.append('a')
         l.append('a')

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

@@ -312,7 +312,7 @@ class ShowBase(DirectObject.DirectObject):
                 TrueClock.getGlobalPtr().setCpuAffinity(1 << (affinity % 32))
                 TrueClock.getGlobalPtr().setCpuAffinity(1 << (affinity % 32))
 
 
         # Make sure we're not making more than one ShowBase.
         # Make sure we're not making more than one ShowBase.
-        if hasattr(__builtin__, 'base'):
+        if 'base' in __builtin__.__dict__:
             raise StandardError, "Attempt to spawn multiple ShowBase instances!"
             raise StandardError, "Attempt to spawn multiple ShowBase instances!"
         
         
         __builtin__.base = self
         __builtin__.base = self