From d394dc834d53be99cede1155cfe45a7bf0a2e5f7 Mon Sep 17 00:00:00 2001 From: "mhammond%skippinet.com.au" Date: Fri, 20 Jan 2006 05:50:28 +0000 Subject: [PATCH] Merge extensions/python/xpcom changes from DOM_AGNOSTIC2_BRANCH into the trunk. git-svn-id: svn://10.0.0.236/trunk@187878 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/extensions/python/xpcom/Makefile.in | 9 +- mozilla/extensions/python/xpcom/__init__.py | 96 ++++- .../python/xpcom/client/__init__.py | 172 ++++++--- mozilla/extensions/python/xpcom/file.py | 27 +- mozilla/extensions/python/xpcom/nsError.py | 7 +- mozilla/extensions/python/xpcom/primitives.py | 39 ++ .../extensions/python/xpcom/server/factory.py | 14 +- .../extensions/python/xpcom/server/loader.py | 4 +- .../extensions/python/xpcom/server/policy.py | 49 ++- .../python/xpcom/src/ErrorUtils.cpp | 204 ++++++++--- .../extensions/python/xpcom/src/Makefile.in | 32 +- .../extensions/python/xpcom/src/PyGBase.cpp | 42 ++- .../extensions/python/xpcom/src/PyGModule.cpp | 12 +- .../extensions/python/xpcom/src/PyGStub.cpp | 3 +- .../python/xpcom/src/PyIClassInfo.cpp | 6 +- .../python/xpcom/src/PyIComponentManager.cpp | 12 +- .../python/xpcom/src/PyIEnumerator.cpp | 7 +- mozilla/extensions/python/xpcom/src/PyIID.cpp | 2 +- .../python/xpcom/src/PyIInterfaceInfo.cpp | 12 +- .../xpcom/src/PyIInterfaceInfoManager.cpp | 18 +- .../python/xpcom/src/PyISimpleEnumerator.cpp | 7 +- .../python/xpcom/src/PyISupports.cpp | 99 ++--- .../python/xpcom/src/PyIVariant.cpp | 39 +- mozilla/extensions/python/xpcom/src/PyXPCOM.h | 176 +++++---- .../extensions/python/xpcom/src/PyXPCOM_std.h | 23 -- .../python/xpcom/src/Pyxpt_info.cpp | 4 +- .../python/xpcom/src/TypeObject.cpp | 28 +- .../python/xpcom/src/VariantUtils.cpp | 247 +++++++------ .../extensions/python/xpcom/src/dllmain.cpp | 96 +++++ .../python/xpcom/src/loader/Makefile.in | 10 +- .../python/xpcom/src/loader/pyloader.cpp | 103 ++++-- .../python/xpcom/src/module/Makefile.in | 94 +++++ .../src/{xpcom.cpp => module/_xpcom.cpp} | 341 +++++++----------- .../extensions/python/xpcom/test/Makefile.in | 52 +++ .../xpcom/test/output/test_com_exceptions | 8 - .../python/xpcom/test/output/test_comfile | 7 - .../python/xpcom/test/output/test_components | 4 - .../test/output/test_isupports_primitives | 2 - .../python/xpcom/test/output/test_streams | 1 - .../xpcom/test/output/test_test_component | 4 - .../xpcom/test/output/test_weakreferences | 2 - .../python/xpcom/test/pyxpcom_test_tools.py | 56 ++- .../extensions/python/xpcom/test/regrtest.py | 60 ++- .../python/xpcom/test/test_com_exceptions.py | 71 ++-- .../python/xpcom/test/test_comfile.py | 12 +- .../test/test_component/py_test_component.idl | 1 + .../test/test_component/py_test_component.py | 8 + .../python/xpcom/test/test_components.py | 19 +- .../xpcom/test/test_isupports_primitives.py | 169 ++++++--- .../extensions/python/xpcom/test/test_misc.py | 16 +- .../python/xpcom/test/test_streams.py | 3 +- .../python/xpcom/test/test_test_component.js | 4 + .../python/xpcom/test/test_test_component.py | 79 ++-- .../python/xpcom/test/test_weakreferences.py | 14 +- .../extensions/python/xpcom/tools/regxpcom.py | 29 +- mozilla/extensions/python/xpcom/xpt.py | 13 +- 56 files changed, 1710 insertions(+), 958 deletions(-) create mode 100644 mozilla/extensions/python/xpcom/primitives.py create mode 100644 mozilla/extensions/python/xpcom/src/module/Makefile.in rename mozilla/extensions/python/xpcom/src/{xpcom.cpp => module/_xpcom.cpp} (63%) create mode 100644 mozilla/extensions/python/xpcom/test/Makefile.in delete mode 100644 mozilla/extensions/python/xpcom/test/output/test_com_exceptions delete mode 100644 mozilla/extensions/python/xpcom/test/output/test_comfile delete mode 100644 mozilla/extensions/python/xpcom/test/output/test_components delete mode 100644 mozilla/extensions/python/xpcom/test/output/test_isupports_primitives delete mode 100644 mozilla/extensions/python/xpcom/test/output/test_streams delete mode 100644 mozilla/extensions/python/xpcom/test/output/test_test_component delete mode 100644 mozilla/extensions/python/xpcom/test/output/test_weakreferences diff --git a/mozilla/extensions/python/xpcom/Makefile.in b/mozilla/extensions/python/xpcom/Makefile.in index c8fade7c7ea..bbf5ac5cc65 100644 --- a/mozilla/extensions/python/xpcom/Makefile.in +++ b/mozilla/extensions/python/xpcom/Makefile.in @@ -38,11 +38,16 @@ DEPTH =../../.. +include $(DEPTH)/config/autoconf.mk + DIRS = \ src \ - test/test_component \ $(NULL) +ifdef ENABLE_TESTS + DIRS += test $(NULL) +endif + topsrcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ @@ -53,7 +58,7 @@ PYSRCS_XPCOM = \ components.py \ file.py \ nsError.py \ - register.py \ + primitives.py \ shutdown.py \ xpcom_consts.py \ xpt.py \ diff --git a/mozilla/extensions/python/xpcom/__init__.py b/mozilla/extensions/python/xpcom/__init__.py index eac59f4aae3..cbfd59e61ed 100644 --- a/mozilla/extensions/python/xpcom/__init__.py +++ b/mozilla/extensions/python/xpcom/__init__.py @@ -39,18 +39,10 @@ # The XPCOM (Cross Platform COM) package. import exceptions - -import sys -#sys.stdout = open("pystdout.log", "w") -if sys.version_info >= (2, 3): - # sick off the new hex() warnings, and no time to digest what the - # impact will be! - import warnings - warnings.filterwarnings("ignore", category=FutureWarning, append=1) - # A global "verbose" flag - currently used by the # server package to print trace messages verbose = 0 +# Map of nsresult -> constant_name. hr_map = {} # The standard XPCOM exception object. @@ -72,10 +64,10 @@ class Exception(exceptions.Exception): message = hr_map.get(self.errno) if message is None: message = "" - return "0x%x (%s)" % (self.errno, message) + return "%d (%s)" % (self.errno, message) # An alias for Exception - allows code to say "from xpcom import COMException" -# rather than "Exception" - thereby preventing clashes. +# rather than "Exception", preventing clashes with the builtin Exception COMException = Exception # Exceptions thrown by servers. It can be good for diagnostics to @@ -83,7 +75,7 @@ COMException = Exception # and a normal exception which may simply be propagating down. # (When ServerException objects are thrown across the XPConnect # gateway they will be converted back to normal client exceptions if -# subsequently re-caught by Python +# subsequently re-caught by Python) class ServerException(Exception): def __init__(self, errno=None, *args, **kw): if errno is None: @@ -91,4 +83,82 @@ class ServerException(Exception): errno = nsError.NS_ERROR_FAILURE Exception.__init__(self, errno, *args, **kw) -# Some global functions. +# Logging support - setup the 'xpcom' logger to write to the Mozilla +# console service, and also to sys.stderr, or optionally a file. +# Environment variables supports: +# PYXPCOM_LOG_FILE=filename - if set, used instead of sys.stderr. +# PYXPCOM_LOG_LEVEL=level - level may be a number or a logging level +# constant (eg, 'debug', 'error') +# Later it may make sense to allow a different log level to be set for +# the file than for the console service. +import logging +class ConsoleServiceStream: + # enough of a stream to keep logging happy + def flush(self): + pass + def write(self, msg): + import _xpcom + _xpcom.LogConsoleMessage(msg) + def close(self): + pass + +def setupLogging(): + import sys, os, threading, thread + hdlr = logging.StreamHandler(ConsoleServiceStream()) + fmt = logging.Formatter(logging.BASIC_FORMAT) + hdlr.setFormatter(fmt) + # There is a bug in 2.3 and 2.4.x logging module in that it doesn't + # use an RLock, leading to deadlocks in some cases (specifically, + # logger.warning("ob is %r", ob), and where repr(ob) itself tries to log) + # Later versions of logging use an RLock, so we detect an "old" style + # handler and update its lock + if type(hdlr.lock) == thread.LockType: + hdlr.lock = threading.RLock() + + logger.addHandler(hdlr) + # The console handler in mozilla does not go to the console!? + # Add a handler to print to stderr, or optionally a file + # PYXPCOM_LOG_FILE can specify a filename + filename = os.environ.get("PYXPCOM_LOG_FILE") + stream = sys.stderr # this is what logging uses as default + if filename: + try: + # open without buffering so never pending output + stream = open(filename, "wU", 0) + except IOError, why: + print >> sys.stderr, "pyxpcom failed to open log file '%s': %s" \ + % (filename, why) + # stream remains default + + hdlr = logging.StreamHandler(stream) + # see above - fix a deadlock problem on this handler too. + if type(hdlr.lock) == thread.LockType: + hdlr.lock = threading.RLock() + + fmt = logging.Formatter(logging.BASIC_FORMAT) + hdlr.setFormatter(fmt) + logger.addHandler(hdlr) + # Allow PYXPCOM_LOG_LEVEL to set the level + level = os.environ.get("PYXPCOM_LOG_LEVEL") + if level: + try: + level = int(level) + except ValueError: + try: + # might be a symbolic name - all are upper-case + level = int(getattr(logging, level.upper())) + except (AttributeError, ValueError): + logger.warning("The PYXPCOM_LOG_LEVEL variable specifies an " + "invalid level") + level = None + if level: + logger.setLevel(level) + +logger = logging.getLogger('xpcom') +# If someone else has already setup this logger, leave things alone. +if len(logger.handlers) == 0: + setupLogging() + +# Cleanup namespace - but leave 'logger' there for people to use, so they +# don't need to know the exact name of the logger. +del ConsoleServiceStream, logging, setupLogging diff --git a/mozilla/extensions/python/xpcom/client/__init__.py b/mozilla/extensions/python/xpcom/client/__init__.py index 6230d8ec66a..58238150cc2 100644 --- a/mozilla/extensions/python/xpcom/client/__init__.py +++ b/mozilla/extensions/python/xpcom/client/__init__.py @@ -37,15 +37,18 @@ import os import new -from xpcom import xpt, COMException, nsError +import logging +from xpcom import xpt, COMException, nsError, logger # Suck in stuff from _xpcom we use regularly to prevent a module lookup -from xpcom._xpcom import IID_nsISupports, IID_nsIClassInfo, IID_nsISupportsCString, IID_nsISupportsWeakReference, \ - IID_nsIWeakReference, XPTI_GetInterfaceInfoManager, GetComponentManager, XPTC_InvokeByIndex +from xpcom._xpcom import IID_nsISupports, IID_nsIClassInfo, \ + IID_nsISupportsCString, IID_nsISupportsString, \ + IID_nsISupportsWeakReference, IID_nsIWeakReference, \ + XPTI_GetInterfaceInfoManager, GetComponentManager, XPTC_InvokeByIndex # Attribute names we may be __getattr__'d for, but know we don't want to delegate # Could maybe just look for startswith("__") but this may screw things for some objects. -_special_getattr_names = ["__del__", "__len__", "__nonzero__"] +_special_getattr_names = ["__del__", "__len__", "__nonzero__", "__eq__", "__neq__"] _just_int_interfaces = ["nsISupportsPRInt32", "nsISupportsPRInt16", "nsISupportsPRUint32", "nsISupportsPRUint16", "nsISupportsPRUint8", "nsISupportsPRBool"] _just_long_interfaces = ["nsISupportsPRInt64", "nsISupportsPRUint64"] @@ -176,6 +179,21 @@ class _XPCOMBase: def __hash__(self): return hash(self._comobj_) + # The basic rich compare ops for equality + def __eq__(self, other): + try: + other = other._comobj_ + except AttributeError: + pass + return self._comobj_ == other + + def __neq__(self, other): + try: + other = other._comobj_ + except AttributeError: + pass + return self._comobj_ != other + # See if the object support strings. def __str__(self): try: @@ -184,6 +202,13 @@ class _XPCOMBase: except COMException: return self.__repr__() + def __unicode__(self): + try: + prin = self._comobj_.QueryInterface(IID_nsISupportsString) + except COMException: + return unicode(str(self)) + return prin.data + # Try the numeric support. def _do_conversion(self, interface_names, cvt): iim = XPTI_GetInterfaceInfoManager() @@ -206,7 +231,7 @@ class _XPCOMBase: return self._do_conversion(_float_interfaces, float) class Component(_XPCOMBase): - def __init__(self, ob, iid): + def __init__(self, ob, iid = IID_nsISupports): assert not hasattr(ob, "_comobj_"), "Should be a raw nsIWhatever, not a wrapped one" ob_name = None if not hasattr(ob, "IID"): @@ -220,7 +245,7 @@ class Component(_XPCOMBase): self.__dict__['_interfaces_'] = {} # keyed by IID self.__dict__['_interface_names_'] = {} # keyed by IID name self.__dict__['_interface_infos_'] = {} # keyed by IID - self.__dict__['_name_to_interface_name_'] = {} + self.__dict__['_name_to_interface_iid_'] = {} self.__dict__['_tried_classinfo_'] = 0 if ob_name is None: @@ -256,10 +281,11 @@ class Component(_XPCOMBase): for nominated_iid in interface_infos: # Interface may appear twice in the class info list, so check this here. if not self.__dict__['_interface_infos_'].has_key(nominated_iid): - self._remember_interface_info(nominated_iid) + # Just invoke our QI on the object + self.queryInterface(nominated_iid) if real_cid is not None: contractid_info = {} - contractid_info['_name_to_interface_name_'] = self.__dict__['_name_to_interface_name_'] + contractid_info['_name_to_interface_iid_'] = self.__dict__['_name_to_interface_iid_'] contractid_info['_interface_infos_'] = self.__dict__['_interface_infos_'] contractid_info_cache[real_cid] = contractid_info else: @@ -269,26 +295,28 @@ class Component(_XPCOMBase): self.__dict__['_com_classinfo_'] = classinfo def _remember_interface_info(self, iid): - method_infos, getters, setters, constants = BuildInterfaceInfo(iid) - # Remember all the names so we can delegate - assert not self.__dict__['_interface_infos_'].has_key(iid), "Already remembered this interface!" - self.__dict__['_interface_infos_'][iid] = method_infos, getters, setters, constants - interface_name = iid.name - names = self.__dict__['_name_to_interface_name_'] - for name in method_infos.keys(): names[name] = interface_name - for name in getters.keys(): names[name] = interface_name - for name in setters.keys(): names[name] = interface_name - for name in constants.keys(): names[name] = interface_name + # XXX - there is no good reason to cache this only in each instance + # It should be cached at the module level, so we don't need to + # rebuild the world for each new object. + iis = self.__dict__['_interface_infos_'] + assert not iis.has_key(iid), "Already remembered this interface!" + try: + method_infos, getters, setters, constants = BuildInterfaceInfo(iid) + except COMException, why: + # Failing to build an interface info generally isn't a real + # problem - its probably just that the interface is non-scriptable. + logger.info("Failed to build interface info for %s: %s", iid, why) + # Remember the fact we failed. + iis[iid] = None + return - def _make_interface_info(self, ob, iid): - interface_infos = self._interface_infos_ - assert not self._interfaces_.has_key(iid), "Already have made this interface" - method_infos, getters, setters, constants = interface_infos[iid] - new_interface = _Interface(ob, iid, method_infos, getters, setters, constants) - self._interfaces_[iid] = new_interface - self._interface_names_[iid.name] = new_interface - # No point remembering these. - del interface_infos[iid] + # Remember all the names so we can delegate + iis[iid] = method_infos, getters, setters, constants + names = self.__dict__['_name_to_interface_iid_'] + for name in method_infos.keys(): names[name] = iid + for name in getters.keys(): names[name] = iid + for name in setters.keys(): names[name] = iid + for name in constants.keys(): names[name] = iid def QueryInterface(self, iid): if self._interfaces_.has_key(iid): @@ -297,10 +325,24 @@ class Component(_XPCOMBase): # Haven't seen this before - do a real QI. if not self._interface_infos_.has_key(iid): self._remember_interface_info(iid) - ret = self._comobj_.QueryInterface(iid, 0) -# print "Component QI for", iid, "yielded", ret - self._make_interface_info(ret, iid) - assert self._interfaces_.has_key(iid) and self._interface_names_.has_key(iid.name), "Making the interface didn't update the maps" + iface_info = self._interface_infos_[iid] + if iface_info is None: + # We have tried, but failed, to get this interface info. Its + # unlikely to work later either - its probably non-scriptable. + # That means our component wrappers are useless - so just return a + # raw nsISupports object with no wrapper. + return self._comobj_.QueryInterface(iid, 0) + + raw_iface = self._comobj_.QueryInterface(iid, 0) + + method_infos, getters, setters, constants = iface_info + new_interface = _Interface(raw_iface, iid, method_infos, + getters, setters, constants) + self._interfaces_[iid] = new_interface + self._interface_names_[iid.name] = new_interface + # As we 'flatten' objects when possible, a QI on an object just + # returns ourself - all the methods etc on this interface are + # available. return self queryInterface = QueryInterface # Alternate name. @@ -312,47 +354,51 @@ class Component(_XPCOMBase): interface = self.__dict__['_interface_names_'].get(attr, None) if interface is not None: return interface - interface_name = self.__dict__['_name_to_interface_name_'].get(attr, None) + # See if we know the IID of an interface providing this attribute + iid = self.__dict__['_name_to_interface_iid_'].get(attr, None) # This may be first time trying this interface - get the nsIClassInfo - if interface_name is None and not self._tried_classinfo_: + if iid is None and not self._tried_classinfo_: self._build_all_supported_interfaces_() - interface_name = self.__dict__['_name_to_interface_name_'].get(attr, None) - - if interface_name is not None: - interface = self.__dict__['_interface_names_'].get(interface_name, None) + iid = self.__dict__['_name_to_interface_iid_'].get(attr, None) + # If the request is for an interface name, it may now be + # available. + interface = self.__dict__['_interface_names_'].get(attr, None) + if interface is not None: + return interface + + if iid is not None: + interface = self.__dict__['_interfaces_'].get(iid, None) if interface is None: - iid = XPTI_GetInterfaceInfoManager().GetInfoForName(interface_name).GetIID() self.QueryInterface(iid) - interface = self.__dict__['_interface_names_'][interface_name] + interface = self.__dict__['_interfaces_'][iid] return getattr(interface, attr) # Some interfaces may provide this name via "native" support. # Loop over all interfaces, and if found, cache it for next time. for interface in self.__dict__['_interfaces_'].values(): try: ret = getattr(interface, attr) - self.__dict__['_name_to_interface_name_'][attr] = interface._iid_.name + self.__dict__['_name_to_interface_iid_'][attr] = interface._iid_ return ret except AttributeError: pass raise AttributeError, "XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr) def __setattr__(self, attr, val): - interface_name = self._name_to_interface_name_.get(attr, None) + iid = self._name_to_interface_iid_.get(attr, None) # This may be first time trying this interface - get the nsIClassInfo - if interface_name is None and not self._tried_classinfo_: + if iid is None and not self._tried_classinfo_: self._build_all_supported_interfaces_() - interface_name = self.__dict__['_name_to_interface_name_'].get(attr, None) - if interface_name is not None: - interface = self._interface_names_.get(interface_name, None) + iid = self.__dict__['_name_to_interface_iid_'].get(attr, None) + if iid is not None: + interface = self._interfaces_.get(iid, None) if interface is None: - iid = XPTI_GetInterfaceInfoManager().GetInfoForName(interface_name).GetIID() self.QueryInterface(iid) - interface = self.__dict__['_interface_names_'][interface_name] + interface = self.__dict__['_interfaces_'][iid] setattr(interface, attr, val) return raise AttributeError, "XPCOM component '%s' has no attribute '%s'" % (self._object_name_, attr) - def __repr__(self): - # We can advantage from nsIClassInfo - use it. + + def _get_classinfo_repr_(self): try: if not self._tried_classinfo_: self._build_all_supported_interfaces_() @@ -362,13 +408,21 @@ class Component(_XPCOMBase): # we are flagged as *not* having built, so the error is seen # by the first caller who actually *needs* this to work. self.__dict__['_tried_classinfo_'] = 0 - infos = self.__dict__['_interface_infos_'] - if infos: - iface_names = ",".join([iid.name for iid in infos.keys()]) - iface_desc = " (implementing %s)" % (iface_names,) - else: - iface_desc = " (with no class info)" - return "" % (self._object_name_,iface_desc) + + iface_names = self.__dict__['_interface_names_'].keys() + try: + iface_names.remove("nsISupports") + except ValueError: + pass + iface_names.sort() + + iface_desc = "implementing %s" % (",".join(iface_names),) + return iface_desc + + def __repr__(self): + # We can advantage from nsIClassInfo - use it. + iface_desc = self._get_classinfo_repr_() + return "" % (self._object_name_,iface_desc) class _Interface(_XPCOMBase): def __init__(self, comobj, iid, method_infos, getters, setters, constants): @@ -403,7 +457,7 @@ class _Interface(_XPCOMBase): if len(param_infos)!=1: # Only expecting a retval raise RuntimeError, "Can't get properties with this many args!" args = ( param_infos, () ) - return XPTC_InvokeByIndex(self, method_index, args) + return XPTC_InvokeByIndex(self._comobj_, method_index, args) # See if we have a method info waiting to be turned into a method. # Do this last as it is a one-off hit. @@ -431,7 +485,7 @@ class _Interface(_XPCOMBase): if len(param_infos)!=1: # Only expecting a single input val raise RuntimeError, "Can't set properties with this many args!" real_param_infos = ( param_infos, (val,) ) - return XPTC_InvokeByIndex(self, method_index, real_param_infos) + return XPTC_InvokeByIndex(self._comobj_, method_index, real_param_infos) def __repr__(self): return "" % (self._object_name_,) @@ -453,7 +507,7 @@ class WeakReference: >>> some_ob = components.classes['...'] >>> weak_ref = WeakReference(some_ob) >>> new_ob = weak_ref() # new_ob is effectively "some_ob" at this point - >>> # EXCEPT: new_ob may be None of some_ob has already died - a + >>> # EXCEPT: new_ob may be None if some_ob has already died - a >>> # weak reference does not keep the object alive (that is the point) You should never hold onto this resulting strong object for a long time, diff --git a/mozilla/extensions/python/xpcom/file.py b/mozilla/extensions/python/xpcom/file.py index 06aee843640..d84a1925adc 100644 --- a/mozilla/extensions/python/xpcom/file.py +++ b/mozilla/extensions/python/xpcom/file.py @@ -251,24 +251,17 @@ def _TestLocalFile(): test_file.close() # Make sure Python can read it OK. f = open(fname, "r") - if f.read() != data: - print "Eeek - Python could not read the data back correctly!" + assert f.read() == data, "Eeek - Python could not read the data back correctly!" f.close() # For the sake of the test, try a re-init. test_file.init(fname, "r") got = str(test_file.read()) - if got != data: - print "Read the wrong data back - %r" % (got,) - else: - print "Read the correct data." + assert got == data, got test_file.close() # Try reading in chunks. test_file = LocalFile(fname, "r") got = test_file.read(10) + test_file.read() - if got != data: - print "Chunks the wrong data back - %r" % (got,) - else: - print "Chunks read the correct data." + assert got == data, got test_file.close() # Open the same file again for writing - this should delete the old one. if not os.path.isfile(fname): @@ -278,16 +271,12 @@ def _TestLocalFile(): test_file.close() # Make sure Python can read it OK. f = open(fname, "r") - if f.read() != data: - print "Eeek - Python could not read the data back correctly after recreating an existing file!" + assert f.read() == data, "Eeek - Python could not read the data back correctly after recreating an existing file!" f.close() # XXX - todo - test "a" mode! finally: - try: - os.unlink(fname) - except OSError, details: - print "Error removing temp test file:", details + os.unlink(fname) def _TestAll(): # A mini test suite. @@ -302,17 +291,13 @@ def _TestAll(): url = LocalFileToURL(fname) # First try passing a URL as a string. _DoTestRead( URIFile( url.spec), expected) - print "Open as string test worked." # Now with a URL object. _DoTestRead( URIFile( url ), expected) - print "Open as URL test worked." _DoTestBufferRead( URIFile( url ), expected) - print "File test using buffers worked." # For the sake of testing, do our pointless, demo object! _DoTestRead( LocalFile(fname), expected ) - print "Local file read test worked." # Now do the full test of our pointless, demo object! _TestLocalFile() @@ -330,4 +315,4 @@ if __name__=='__main__': print "No URL specified on command line - performing self-test" _TestAll() else: - _TestURI(sys.argv[1]) + _TestURI(sys.argv[1]) diff --git a/mozilla/extensions/python/xpcom/nsError.py b/mozilla/extensions/python/xpcom/nsError.py index 83f9587db8b..a34c7a5429f 100644 --- a/mozilla/extensions/python/xpcom/nsError.py +++ b/mozilla/extensions/python/xpcom/nsError.py @@ -98,10 +98,13 @@ NS_ERROR_PROXY_INVALID_OUT_PARAMETER = ( -2147418095) ##### END OF GENERATED CODE ##### def NS_ERROR_GENERATE_FAILURE(module,code): - return (NS_ERROR_SEVERITY_ERROR<<31) | ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code) + # slightly optimized, and avoids 2.3->2.4 long/int changes + # return (NS_ERROR_SEVERITY_ERROR<<31) | ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code) + return -2147483648 | ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code) def NS_ERROR_GENERATE_SUCCESS(module,code): - return (NS_ERROR_SEVERITY_SUCCESS<<31) | ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code) + #return (NS_ERROR_SEVERITY_SUCCESS<<31) | ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code) + return ((module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | (code) NS_BASE_STREAM_CLOSED = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 2) NS_BASE_STREAM_OSERROR = NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 3) diff --git a/mozilla/extensions/python/xpcom/primitives.py b/mozilla/extensions/python/xpcom/primitives.py new file mode 100644 index 00000000000..b9ebe1eb3cd --- /dev/null +++ b/mozilla/extensions/python/xpcom/primitives.py @@ -0,0 +1,39 @@ +# Various utilities for working with nsISupportsPrimitive +from xpcom import components + +_primitives_map = {} + +def _build_map(): + ifaces = components.interfaces + iface = ifaces.nsISupportsPrimitive + m = _primitives_map + + m[iface.TYPE_ID] = ifaces.nsISupportsID + m[iface.TYPE_CSTRING] = ifaces.nsISupportsCString + m[iface.TYPE_STRING] = ifaces.nsISupportsString + m[iface.TYPE_PRBOOL] = ifaces.nsISupportsPRBool + m[iface.TYPE_PRUINT8] = ifaces.nsISupportsPRUint8 + m[iface.TYPE_PRUINT16] = ifaces.nsISupportsPRUint16 + m[iface.TYPE_PRUINT32] = ifaces.nsISupportsPRUint32 + m[iface.TYPE_PRUINT64] = ifaces.nsISupportsPRUint64 + m[iface.TYPE_PRINT16] = ifaces.nsISupportsPRInt16 + m[iface.TYPE_PRINT32] = ifaces.nsISupportsPRInt32 + m[iface.TYPE_PRINT64] = ifaces.nsISupportsPRInt64 + m[iface.TYPE_PRTIME] = ifaces.nsISupportsPRTime + m[iface.TYPE_CHAR] = ifaces.nsISupportsChar + m[iface.TYPE_FLOAT] = ifaces.nsISupportsFloat + m[iface.TYPE_DOUBLE] = ifaces.nsISupportsDouble + # Do interface pointer specially - it provides the IID. + #m[iface.TYPE_INTERFACE_POINTER] = ifaces.nsISupportsDouble + +def GetPrimitive(ob): + if len(_primitives_map)==0: + _build_map() + + prin = ob.QueryInterface(components.interfaces.nsISupportsPrimitive) + try: + better = _primitives_map[prin.type] + except KeyError: + raise ValueError, "This primitive type (%d) is not supported" % (prin.type,) + prin = prin.QueryInterface(better) + return prin.data diff --git a/mozilla/extensions/python/xpcom/server/factory.py b/mozilla/extensions/python/xpcom/server/factory.py index e22bc340a46..b65483dd2db 100644 --- a/mozilla/extensions/python/xpcom/server/factory.py +++ b/mozilla/extensions/python/xpcom/server/factory.py @@ -39,8 +39,7 @@ # # Hardly worth its own source file! import xpcom -from xpcom import components, nsError, _xpcom - +from xpcom import components, nsError, _xpcom, logger class Factory: _com_interfaces_ = components.interfaces.nsIFactory @@ -53,18 +52,17 @@ class Factory: if outer is not None: raise xpcom.ServerException(nsError.NS_ERROR_NO_AGGREGATION) - if xpcom.verbose: - print "Python Factory creating", self.klass.__name__ + logger.debug("Python Factory creating %s", self.klass.__name__) try: return self.klass() except: # An exception here may not be obvious to the user - none # of their code has been called yet. It can be handy on # failure to tell the user what class failed! - _xpcom.LogWarning("Creation of class '%r' failed!\nException details follow\n" % (self.klass,)) + logger.error("Creation of class '%r' failed!\nException details follow\n", + self.klass) + # The framework itself will also report the error. raise def lockServer(self, lock): - if xpcom.verbose: - print "Python Factory LockServer called -", lock - + logger.debug("Python Factory LockServer called '%s'", lock) diff --git a/mozilla/extensions/python/xpcom/server/loader.py b/mozilla/extensions/python/xpcom/server/loader.py index bb7c1ccac2c..ae6904bab34 100644 --- a/mozilla/extensions/python/xpcom/server/loader.py +++ b/mozilla/extensions/python/xpcom/server/loader.py @@ -36,7 +36,7 @@ # ***** END LICENSE BLOCK ***** import xpcom -from xpcom import components +from xpcom import components, nsError import xpcom.shutdown import module @@ -93,6 +93,8 @@ class ModuleLoader: def _getCOMModuleForLocation(self, componentFile): fqn = componentFile.path + if not fqn.endswith(".py"): + raise xpcom.ServerException(nsError.NS_ERROR_INVALID_ARG) mod = self.com_modules.get(fqn) if mod is not None: return mod diff --git a/mozilla/extensions/python/xpcom/server/policy.py b/mozilla/extensions/python/xpcom/server/policy.py index 3f6c6319cf5..11a7fe542d5 100644 --- a/mozilla/extensions/python/xpcom/server/policy.py +++ b/mozilla/extensions/python/xpcom/server/policy.py @@ -35,12 +35,14 @@ # # ***** END LICENSE BLOCK ***** -from xpcom import xpcom_consts, _xpcom, client, nsError, ServerException, COMException +from xpcom import xpcom_consts, _xpcom, client, nsError, logger +from xpcom import ServerException, COMException import xpcom -import traceback import xpcom.server import operator import types +import logging + IID_nsISupports = _xpcom.IID_nsISupports IID_nsIVariant = _xpcom.IID_nsIVariant @@ -237,12 +239,11 @@ class DefaultPolicy: if dt == xpcom_consts.VTYPE_ID: return interface.getAsID() # all else fails... - print "Warning: nsIVariant type %d not supported - returning a string" % (dt,) + logger.warning("Warning: nsIVariant type %d not supported - returning a string", dt) try: return interface.getAsString() except COMException: - print "Error: failed to get Variant as a string - returning variant object" - traceback.print_exc() + logger.exception("Error: failed to get Variant as a string - returning variant object") return interface return client.Component(interface, iid) @@ -278,17 +279,27 @@ class DefaultPolicy: exc_val = exc_info[1] is_server_exception = isinstance(exc_val, ServerException) if is_server_exception: - if xpcom.verbose: - print "** Information: '%s' raised COM Exception %s" % (func_name, exc_val) - traceback.print_exception(exc_info[0], exc_val, exc_info[2]) - print "** Returning nsresult from existing exception", exc_val - return exc_val.errno - # Unhandled exception - always print a warning. - print "** Unhandled exception calling '%s'" % (func_name,) - traceback.print_exception(exc_info[0], exc_val, exc_info[2]) - print "** Returning nsresult of NS_ERROR_FAILURE" - return nsError.NS_ERROR_FAILURE + # When a component raised an explicit COM exception, it is + # considered 'normal' - however, we still write a debug log + # record to help track these otherwise silent exceptions. + # Note that Python 2.3 does not allow an explicit exc_info tuple + # and passing 'True' will not work as there is no exception pending. + # Trick things! + if logger.isEnabledFor(logging.DEBUG): + try: + raise exc_info[0], exc_info[1], exc_info[2] + except: + logger.debug("'%s' raised COM Exception %s", + func_name, exc_val, exc_info = 1) + return exc_val.errno + # Unhandled exception - always print a warning and the traceback. + # As above, trick the logging module to handle Python 2.3 + try: + raise exc_info[0], exc_info[1], exc_info[2] + except: + logger.exception("Unhandled exception calling '%s'", func_name) + return nsError.NS_ERROR_FAILURE # Called whenever an unhandled Python exception is detected as a result # of _CallMethod_ - this exception may have been raised during the _CallMethod_ @@ -306,8 +317,12 @@ class DefaultPolicy: import xpcom.xpt m = xpcom.xpt.Method(info, index, None) func_repr = m.Describe().lstrip() - except: + except COMException: func_repr = "%s(%r)" % (name, param_descs) + except: + # any other errors are evil!? Log it + self._doHandleException("", sys.exc_info()) + # And fall through to logging the original error. return self._doHandleException(func_repr, exc_info) # Called whenever a gateway fails due to anything other than _CallMethod_. @@ -318,7 +333,7 @@ class DefaultPolicy: _supports_primitives_data_ = [ ("nsISupportsCString", "__str__", str), - ("nsISupportsString", "__str__", str), + ("nsISupportsString", "__unicode__", unicode), ("nsISupportsPRUint64", "__long__", long), ("nsISupportsPRInt64", "__long__", long), ("nsISupportsPRUint32", "__int__", int), diff --git a/mozilla/extensions/python/xpcom/src/ErrorUtils.cpp b/mozilla/extensions/python/xpcom/src/ErrorUtils.cpp index 52b9bcfebaf..f285b8033e0 100644 --- a/mozilla/extensions/python/xpcom/src/ErrorUtils.cpp +++ b/mozilla/extensions/python/xpcom/src/ErrorUtils.cpp @@ -55,81 +55,179 @@ static char *PyTraceback_AsString(PyObject *exc_tb); // The internal helper that actually moves the // formatted string to the target! -void LogMessage(const char *prefix, const char *pszMessageText) +// Only used in really bad situations! +static void _PanicErrorWrite(const char *msg) { nsCOMPtr consoleService = do_GetService(NS_CONSOLESERVICE_CONTRACTID); - NS_ABORT_IF_FALSE(consoleService, "Where is the console service?"); if (consoleService) - consoleService->LogStringMessage(NS_ConvertASCIItoUCS2(pszMessageText).get()); - else - PR_fprintf(PR_STDERR,"%s\n", pszMessageText); + consoleService->LogStringMessage(NS_ConvertASCIItoUCS2(msg).get()); + PR_fprintf(PR_STDERR,"%s\n", msg); } -void LogMessage(const char *prefix, nsACString &text) +// Called when our "normal" error logger fails. +static void HandleLogError(const char *pszMessageText) +{ + nsCAutoString streamout; + + _PanicErrorWrite("Failed to log an error record"); + if (PyXPCOM_FormatCurrentException(streamout)) + _PanicErrorWrite(streamout.get()); + _PanicErrorWrite("Original error follows:"); + _PanicErrorWrite(pszMessageText); +} + +static const char *LOGGER_WARNING = "warning"; +static const char *LOGGER_ERROR = "error"; +static const char *LOGGER_DEBUG = "debug"; + +// Our "normal" error logger - calls back to the logging module. +void DoLogMessage(const char *methodName, const char *pszMessageText) +{ + // We use the logging module now. Originally this code called + // the logging module directly by way of the C API's + // PyImport_ImportModule/PyObject_CallMethod etc. However, this + // causes problems when there is no Python caller on the stack - + // the logging module's findCaller method fails with a None frame. + // We now work around this by calling PyRun_SimpleString - this + // causes a new frame to be created for executing the compiled + // string, and the logging module no longer fails. + // XXX - this implementation is less than ideal - findCaller now + // returns ("", 2). Ideally we would compile with a + // filename something similar to "". + + // But this also means we need a clear error state... + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch(&exc_typ, &exc_val, &exc_tb); +// We will execute: +// import logging +// logging.getLogger('xpcom').{warning/error/etc}("%s", {msg_text}) + nsCAutoString c("import logging\nlogging.getLogger('xpcom')."); + c += methodName; + c += "('%s', "; + // Pull a trick to ensure a valid string - use Python repr! + PyObject *obMessage = PyString_FromString(pszMessageText); + if (obMessage) { + PyObject *repr = PyObject_Repr(obMessage); + if (repr) { + c += PyString_AsString(repr); + Py_DECREF(repr); + } + Py_DECREF(obMessage); + } + c += ")\n"; + if (PyRun_SimpleString(c.get()) != 0) { + HandleLogError(pszMessageText); + } + PyErr_Restore(exc_typ, exc_val, exc_tb); +} + +void LogMessage(const char *methodName, const char *pszMessageText) +{ + // Be careful to save and restore the Python exception state + // before calling back to Python, or we lose the original error. + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch( &exc_typ, &exc_val, &exc_tb); + DoLogMessage(methodName, pszMessageText); + PyErr_Restore(exc_typ, exc_val, exc_tb); +} + + +void LogMessage(const char *methodName, nsACString &text) { char *c = ToNewCString(text); - LogMessage(prefix, c); + LogMessage(methodName, c); nsCRT::free(c); } // A helper for the various logging routines. -static void VLogF(const char *prefix, const char *fmt, va_list argptr) +static void VLogF(const char *methodName, const char *fmt, va_list argptr) { char buff[512]; + // Use safer NS_ functions. + PR_vsnprintf(buff, sizeof(buff), fmt, argptr); - vsprintf(buff, fmt, argptr); + LogMessage(methodName, buff); +} - LogMessage(prefix, buff); +PRBool PyXPCOM_FormatCurrentException(nsCString &streamout) +{ + PRBool ok = PR_FALSE; + PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; + PyErr_Fetch( &exc_typ, &exc_val, &exc_tb); + PyErr_NormalizeException( &exc_typ, &exc_val, &exc_tb); + if (exc_typ) { + ok = PyXPCOM_FormatGivenException(streamout, exc_typ, exc_val, + exc_tb); + } + PyErr_Restore(exc_typ, exc_val, exc_tb); + return ok; +} + +PRBool PyXPCOM_FormatGivenException(nsCString &streamout, + PyObject *exc_typ, PyObject *exc_val, + PyObject *exc_tb) +{ + if (!exc_typ) + return PR_FALSE; + streamout += "\n"; + + if (exc_tb) { + const char *szTraceback = PyTraceback_AsString(exc_tb); + if (szTraceback == NULL) + streamout += "Can't get the traceback info!"; + else { + streamout += "Traceback (most recent call last):\n"; + streamout += szTraceback; + PyMem_Free((void *)szTraceback); + } + } + PyObject *temp = PyObject_Str(exc_typ); + if (temp) { + streamout += PyString_AsString(temp); + Py_DECREF(temp); + } else + streamout += "Can't convert exception to a string!"; + streamout += ": "; + if (exc_val != NULL) { + temp = PyObject_Str(exc_val); + if (temp) { + streamout += PyString_AsString(temp); + Py_DECREF(temp); + } else + streamout += "Can't convert exception value to a string!"; + } + return PR_TRUE; } void PyXPCOM_LogError(const char *fmt, ...) { va_list marker; va_start(marker, fmt); - VLogF("PyXPCOM Error: ", fmt, marker); + // NOTE: It is tricky to use logger.exception here - the exception + // state when called back from the C code is clear. Only Python 2.4 + // and later allows an explicit exc_info tuple(). + + // Don't use VLogF here, instead arrange for exception info and + // traceback to be in the same buffer. + char buff[512]; + PR_vsnprintf(buff, sizeof(buff), fmt, marker); // If we have a Python exception, also log that: - PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL; - PyErr_Fetch( &exc_typ, &exc_val, &exc_tb); - if (exc_typ) { - PyErr_NormalizeException( &exc_typ, &exc_val, &exc_tb); - nsCAutoString streamout; - - if (exc_tb) { - const char *szTraceback = PyTraceback_AsString(exc_tb); - if (szTraceback == NULL) - streamout += "Can't get the traceback info!"; - else { - streamout += "Traceback (most recent call last):\n"; - streamout += szTraceback; - PyMem_Free((void *)szTraceback); - } - } - PyObject *temp = PyObject_Str(exc_typ); - if (temp) { - streamout += PyString_AsString(temp); - Py_DECREF(temp); - } else - streamout += "Can't convert exception to a string!"; - streamout += ": "; - if (exc_val != NULL) { - temp = PyObject_Str(exc_val); - if (temp) { - streamout += PyString_AsString(temp); - Py_DECREF(temp); - } else - streamout += "Can't convert exception value to a string!"; - } - streamout += "\n"; - LogMessage("PyXPCOM Exception:", streamout); + nsCAutoString streamout(buff); + if (PyXPCOM_FormatCurrentException(streamout)) { + LogMessage(LOGGER_ERROR, streamout); } - PyErr_Restore(exc_typ, exc_val, exc_tb); } void PyXPCOM_LogWarning(const char *fmt, ...) { va_list marker; va_start(marker, fmt); - VLogF("PyXPCOM Warning: ", fmt, marker); + VLogF(LOGGER_WARNING, fmt, marker); +} + +void PyXPCOM_Log(const char *level, const nsCString &msg) +{ + DoLogMessage(level, msg.get()); } #ifdef DEBUG @@ -137,7 +235,7 @@ void PyXPCOM_LogDebug(const char *fmt, ...) { va_list marker; va_start(marker, fmt); - VLogF("PyXPCOM Debug: ", fmt, marker); + VLogF(LOGGER_DEBUG, fmt, marker); } #endif @@ -156,7 +254,17 @@ nsresult PyXPCOM_SetCOMErrorFromPyException() if (!PyErr_Occurred()) // No error occurred return NS_OK; - return NS_ERROR_FAILURE; + nsresult rv = NS_ERROR_FAILURE; + if (PyErr_ExceptionMatches(PyExc_MemoryError)) + rv = NS_ERROR_OUT_OF_MEMORY; + // todo: + // * Set an exception using the exception service. + + // Once we have returned to the xpcom caller, we don't want to leave a + // Python exception pending - it may get noticed when the next call + // is made on the same thread. + PyErr_Clear(); + return rv; } /* Obtains a string from a Python traceback. diff --git a/mozilla/extensions/python/xpcom/src/Makefile.in b/mozilla/extensions/python/xpcom/src/Makefile.in index 78eac19c07f..e41d08c929f 100644 --- a/mozilla/extensions/python/xpcom/src/Makefile.in +++ b/mozilla/extensions/python/xpcom/src/Makefile.in @@ -43,22 +43,23 @@ srcdir = @srcdir@ VPATH = @srcdir@ pyexecdir = @libdir@/python$(PYTHON_VER_DOTTED)/site-packages -DIRS = loader $(NULL) +DIRS = module loader $(NULL) include $(DEPTH)/config/autoconf.mk MODULE = pyxpcom -LIBRARY_NAME = _xpcom$(PYTHON_DEBUG_SUFFIX) +LIBRARY_NAME = pyxpcom #MODULE_NAME = REQUIRES = xpcom string $(NULL) MOZILLA_INTERNAL_API = 1 FORCE_SHARED_LIB = 1 FORCE_USE_PIC = 1 -DLL_SUFFIX=$(PYTHON_DLL_SUFFIX) LOCAL_INCLUDES = $(PYTHON_INCLUDES) EXTRA_LIBS += $(PYTHON_LIBS) +EXPORTS = PyXPCOM.h + CPPSRCS= \ ErrorUtils.cpp \ PyGBase.cpp \ @@ -80,33 +81,18 @@ CPPSRCS= \ TypeObject.cpp \ VariantUtils.cpp \ dllmain.cpp \ - xpcom.cpp \ $(NULL) include $(topsrcdir)/config/config.mk include $(topsrcdir)/config/rules.mk -EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) -IMPORT_LIBRARY := $(SHARED_LIBRARY:.pyd=.lib) - -# Install into our Python directory -# default build installs into bin and lib - remove them -libs:: -ifeq ($(OS_ARCH),WINNT) - $(INSTALL) -m 555 $(SHARED_LIBRARY) $(DIST)/bin/python/xpcom +ifeq ($(OS_ARCH),Darwin) +# Don't use the EXTRA_DSO_LDOPTS from rules.mk, it breaks the python module + EXTRA_DSO_LDOPTS = -bundle $(MOZ_COMPONENT_LIBS) else - $(INSTALL) -m 555 $(SHARED_LIBRARY) $(DIST)/bin/python/xpcom - mv $(DIST)/bin/python/xpcom/$(SHARED_LIBRARY) $(DIST)/bin/python/xpcom/_xpcom.so -endif - rm -f $(DIST)/bin/$(SHARED_LIBRARY) - rm -f $(DIST)/lib/$(IMPORT_LIBRARY) - -install:: -ifneq ($(OS_ARCH),WINNT) - $(SYSINSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(DISTDIR)$(pyexecdir)/xpcom - mv $(DISTDIR)$(pyexecdir)/xpcom/$(SHARED_LIBRARY) $(DISTDIR)$(pyexecdir)/xpcom/_xpcom$(PYTHON_DLL_SUFFIX) + EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) endif clobber:: - rm -f *.ilk *.pdb + rm -f *.ilk *.pdb *.exp *.lib *.pyd diff --git a/mozilla/extensions/python/xpcom/src/PyGBase.cpp b/mozilla/extensions/python/xpcom/src/PyGBase.cpp index 7cc69fd4f0f..035c2c1ebc7 100644 --- a/mozilla/extensions/python/xpcom/src/PyGBase.cpp +++ b/mozilla/extensions/python/xpcom/src/PyGBase.cpp @@ -271,8 +271,18 @@ PyG_Base::MakeInterfaceParam(nsISupports *pis, PyObject *result = NULL; // get the basic interface first, as if we fail, we can try and use this. - nsIID iid_check = piid ? *piid : NS_GET_IID(nsISupports); - obISupports = Py_nsISupports::PyObjectFromInterface(pis, iid_check, PR_TRUE, PR_FALSE); + // If we don't know the IID, we must explicitly query for nsISupports. + nsCOMPtr piswrap; + nsIID iid_check; + if (piid) { + iid_check = *piid; + piswrap = pis; + } else { + iid_check = NS_GET_IID(nsISupports); + pis->QueryInterface(iid_check, getter_AddRefs(piswrap)); + } + + obISupports = Py_nsISupports::PyObjectFromInterface(piswrap, iid_check, PR_FALSE); if (!obISupports) goto done; if (piid==NULL) { @@ -346,7 +356,11 @@ PyG_Base::QueryInterface(REFNSIID iid, void** ppv) CEnterLeavePython celp; PyObject * ob = Py_nsIID::PyObjectFromIID(iid); - PyObject * this_interface_ob = Py_nsISupports::PyObjectFromInterface((nsIInternalPython *)this, NS_GET_IID(nsISupports), PR_TRUE, PR_FALSE); + // must say this is an 'internal' call, else we recurse QI into + // oblivion. + PyObject * this_interface_ob = Py_nsISupports::PyObjectFromInterface( + (nsXPTCStubBase *)this, + iid, PR_FALSE, PR_TRUE); if ( !ob || !this_interface_ob) { Py_XDECREF(ob); Py_XDECREF(this_interface_ob); @@ -355,7 +369,7 @@ PyG_Base::QueryInterface(REFNSIID iid, void** ppv) PyObject *result = PyObject_CallMethod(m_pPyObject, "_QueryInterface_", "OO", - this_interface_ob, ob); + this_interface_ob, ob); Py_DECREF(ob); Py_DECREF(this_interface_ob); @@ -426,6 +440,7 @@ PyG_Base::GetWeakReference(nsIWeakReference **ret) if (ret==nsnull) return NS_ERROR_INVALID_POINTER; if (!m_pWeakRef) { // First query for a weak reference - create it. + // XXX - this looks like it needs thread safety!? m_pWeakRef = new PyXPCOM_GatewayWeakReference(this); NS_ABORT_IF_FALSE(m_pWeakRef, "Shouldn't be able to fail creating a weak reference!"); if (!m_pWeakRef) @@ -444,17 +459,17 @@ nsresult PyG_Base::HandleNativeGatewayError(const char *szMethodName) // good error reporting is critical for users to know WTF // is going on - especially with TypeErrors etc in their // return values (ie, after the Python code has successfully - // existed, but we encountered errors unpacking their + // exited, but we encountered errors unpacking their // result values for the COM caller - there is literally no // way to catch these exceptions from Python code, as their - // is no Python function on the call-stack) + // is no Python function directly on the call-stack) // First line of attack in an error is to call-back on the policy. // If the callback of the error handler succeeds and returns an // integer (for the nsresult), we take no further action. - // If this callback fails, we log _2_ exceptions - the error handler - // error, and the original error. + // If this callback fails, we log _2_ exceptions - the error + // handler error, and the original error. PRBool bProcessMainError = PR_TRUE; // set to false if our exception handler does its thing! PyObject *exc_typ, *exc_val, *exc_tb; @@ -696,10 +711,10 @@ PyObject *PyG_Base::UnwrapPythonObject(void) Some special support to help with object identity. - In the simplest case, assume a Python COM object is + In the simplest case, assume a Python XPCOM object is supporting a function "nsIWhatever GetWhatever()", so implements it as: - return this + return self it is almost certain they intend returning the same COM OBJECT to the caller! Thus, if a user of this COM object does: @@ -709,7 +724,7 @@ PyObject *PyG_Base::UnwrapPythonObject(void) We almost certainly expect p1==p2==foo. - We previously _did_ have special support for the "this" + We previously _did_ have special support for the "self" example above, but this implements a generic scheme that works for _all_ objects. @@ -803,12 +818,11 @@ void AddDefaultGateway(PyObject *instance, nsISupports *gateway) NS_ABORT_IF_FALSE(swr, "Our gateway failed with a weak reference query"); // Create the new default gateway - get a weak reference for our gateway. if (swr) { - nsIWeakReference *pWeakReference = NULL; - swr->GetWeakReference( &pWeakReference ); + nsCOMPtr pWeakReference; + swr->GetWeakReference( getter_AddRefs(pWeakReference) ); if (pWeakReference) { PyObject *ob_new_weak = Py_nsISupports::PyObjectFromInterface(pWeakReference, NS_GET_IID(nsIWeakReference), - PR_FALSE, /* bAddRef */ PR_FALSE ); /* bMakeNicePyObject */ // pWeakReference reference consumed. if (ob_new_weak) { diff --git a/mozilla/extensions/python/xpcom/src/PyGModule.cpp b/mozilla/extensions/python/xpcom/src/PyGModule.cpp index 5cc638c1644..ee1249ff55f 100644 --- a/mozilla/extensions/python/xpcom/src/PyGModule.cpp +++ b/mozilla/extensions/python/xpcom/src/PyGModule.cpp @@ -80,7 +80,7 @@ PyG_nsIModule::GetClassObject(nsIComponentManager *aCompMgr, NS_PRECONDITION(r_classObj, "null pointer"); *r_classObj = nsnull; CEnterLeavePython _celp; - PyObject *cm = Py_nsISupports::PyObjectFromInterface(aCompMgr, NS_GET_IID(nsIComponentManager), PR_TRUE); + PyObject *cm = PyObject_FromNSInterface(aCompMgr, NS_GET_IID(nsIComponentManager)); PyObject *iid = Py_nsIID::PyObjectFromIID(aIID); PyObject *clsid = Py_nsIID::PyObjectFromIID(aClass); const char *methodName = "getClassObject"; @@ -110,8 +110,8 @@ PyG_nsIModule::RegisterSelf(nsIComponentManager *aCompMgr, NS_PRECONDITION(aCompMgr, "null pointer"); NS_PRECONDITION(aPath, "null pointer"); CEnterLeavePython _celp; - PyObject *cm = Py_nsISupports::PyObjectFromInterface(aCompMgr, NS_GET_IID(nsIComponentManager), PR_TRUE); - PyObject *path = Py_nsISupports::PyObjectFromInterface(aPath, NS_GET_IID(nsIFile), PR_TRUE); + PyObject *cm = PyObject_FromNSInterface(aCompMgr, NS_GET_IID(nsIComponentManager)); + PyObject *path = PyObject_FromNSInterface(aPath, NS_GET_IID(nsIFile)); const char *methodName = "registerSelf"; nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "OOzz", cm, path, registryLocation, componentType); Py_XDECREF(cm); @@ -127,8 +127,8 @@ PyG_nsIModule::UnregisterSelf(nsIComponentManager* aCompMgr, NS_PRECONDITION(aCompMgr, "null pointer"); NS_PRECONDITION(aPath, "null pointer"); CEnterLeavePython _celp; - PyObject *cm = Py_nsISupports::PyObjectFromInterface(aCompMgr, NS_GET_IID(nsIComponentManager), PR_TRUE); - PyObject *path = Py_nsISupports::PyObjectFromInterface(aPath, NS_GET_IID(nsIFile), PR_TRUE); + PyObject *cm = PyObject_FromNSInterface(aCompMgr, NS_GET_IID(nsIComponentManager)); + PyObject *path = PyObject_FromNSInterface(aPath, NS_GET_IID(nsIFile)); const char *methodName = "unregisterSelf"; nsresult nr = InvokeNativeViaPolicy(methodName, NULL, "OOz", cm, path, registryLocation); Py_XDECREF(cm); @@ -143,7 +143,7 @@ PyG_nsIModule::CanUnload(nsIComponentManager *aCompMgr, PRBool *okToUnload) NS_PRECONDITION(okToUnload, "null pointer"); CEnterLeavePython _celp; // we are shutting down - don't ask for a nice wrapped object. - PyObject *cm = Py_nsISupports::PyObjectFromInterface(aCompMgr, NS_GET_IID(nsIComponentManager), PR_TRUE, PR_FALSE); + PyObject *cm = PyObject_FromNSInterface(aCompMgr, NS_GET_IID(nsIComponentManager), PR_FALSE); const char *methodName = "canUnload"; PyObject *ret = NULL; nsresult nr = InvokeNativeViaPolicy(methodName, &ret, "O", cm); diff --git a/mozilla/extensions/python/xpcom/src/PyGStub.cpp b/mozilla/extensions/python/xpcom/src/PyGStub.cpp index c454ade23e9..2e542f74531 100644 --- a/mozilla/extensions/python/xpcom/src/PyGStub.cpp +++ b/mozilla/extensions/python/xpcom/src/PyGStub.cpp @@ -96,7 +96,8 @@ PyXPCOM_XPTStub::CallMethod(PRUint16 methodIndex, if (obMI==NULL) goto done; // base object is passed raw. - obThisObject = Py_nsISupports::PyObjectFromInterface((nsIInternalPython*)this, NS_GET_IID(nsISupports), PR_TRUE, PR_FALSE); + obThisObject = PyObject_FromNSInterface((nsXPTCStubBase *)this, + m_iid, PR_FALSE); obParams = arg_helper.MakePyArgs(); if (obParams==NULL) goto done; diff --git a/mozilla/extensions/python/xpcom/src/PyIClassInfo.cpp b/mozilla/extensions/python/xpcom/src/PyIClassInfo.cpp index 6e033723d94..2cb19ff77b8 100644 --- a/mozilla/extensions/python/xpcom/src/PyIClassInfo.cpp +++ b/mozilla/extensions/python/xpcom/src/PyIClassInfo.cpp @@ -93,14 +93,14 @@ static PyObject *PyGetHelperForLanguage(PyObject *self, PyObject *args) return NULL; nsresult r; - nsISupports *pi; + nsCOMPtr pi; Py_BEGIN_ALLOW_THREADS; - r = pI->GetHelperForLanguage(language, &pi); + r = pI->GetHelperForLanguage(language, getter_AddRefs(pi)); Py_END_ALLOW_THREADS; if ( NS_FAILED(r) ) return PyXPCOM_BuildPyException(r); - return Py_nsISupports::PyObjectFromInterface(pi, NS_GET_IID(nsISupports), PR_FALSE); + return Py_nsISupports::PyObjectFromInterface(pi, NS_GET_IID(nsISupports)); } static PyObject *MakeStringOrNone(char *v) diff --git a/mozilla/extensions/python/xpcom/src/PyIComponentManager.cpp b/mozilla/extensions/python/xpcom/src/PyIComponentManager.cpp index d076c029067..c3b891120d4 100644 --- a/mozilla/extensions/python/xpcom/src/PyIComponentManager.cpp +++ b/mozilla/extensions/python/xpcom/src/PyIComponentManager.cpp @@ -81,16 +81,16 @@ static PyObject *PyCreateInstanceByContractID(PyObject *self, PyObject *args) if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) return NULL; - nsISupports *pis; + nsCOMPtr pis; nsresult r; Py_BEGIN_ALLOW_THREADS; - r = pI->CreateInstanceByContractID(pid, NULL, iid, (void **)&pis); + r = pI->CreateInstanceByContractID(pid, NULL, iid, getter_AddRefs(pis)); Py_END_ALLOW_THREADS; if ( NS_FAILED(r) ) return PyXPCOM_BuildPyException(r); /* Return a type based on the IID (with no extra ref) */ - return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE, PR_FALSE); + return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE); } static PyObject *PyCreateInstance(PyObject *self, PyObject *args) @@ -117,16 +117,16 @@ static PyObject *PyCreateInstance(PyObject *self, PyObject *args) if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) return NULL; - nsISupports *pis; + nsCOMPtr pis; nsresult r; Py_BEGIN_ALLOW_THREADS; - r = pI->CreateInstance(classID, NULL, iid, (void **)&pis); + r = pI->CreateInstance(classID, NULL, iid, getter_AddRefs(pis)); Py_END_ALLOW_THREADS; if ( NS_FAILED(r) ) return PyXPCOM_BuildPyException(r); /* Return a type based on the IID (with no extra ref) */ - return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE, PR_FALSE); + return Py_nsISupports::PyObjectFromInterface(pis, iid, PR_FALSE); } struct PyMethodDef diff --git a/mozilla/extensions/python/xpcom/src/PyIEnumerator.cpp b/mozilla/extensions/python/xpcom/src/PyIEnumerator.cpp index ff1a62c2f36..b196d956e16 100644 --- a/mozilla/extensions/python/xpcom/src/PyIEnumerator.cpp +++ b/mozilla/extensions/python/xpcom/src/PyIEnumerator.cpp @@ -121,7 +121,9 @@ static PyObject *PyCurrentItem(PyObject *self, PyObject *args) } pRet = temp; } - return Py_nsISupports::PyObjectFromInterface(pRet, iid, PR_FALSE); + PyObject *ret = Py_nsISupports::PyObjectFromInterface(pRet, iid); + NS_IF_RELEASE(pRet); + return ret; } // A method added for Python performance if you really need @@ -179,7 +181,8 @@ static PyObject *PyFetchBlock(PyObject *self, PyObject *args) ret = PyList_New(n_fetched); if (ret) for (int i=0;i|xpcom|IID|Creates a new IID object -PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args) +PYXPCOM_EXPORT PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args) { PyObject *obIID; PyObject *obBuf; diff --git a/mozilla/extensions/python/xpcom/src/PyIInterfaceInfo.cpp b/mozilla/extensions/python/xpcom/src/PyIInterfaceInfo.cpp index 807afcd2427..0c8b9723c4f 100644 --- a/mozilla/extensions/python/xpcom/src/PyIInterfaceInfo.cpp +++ b/mozilla/extensions/python/xpcom/src/PyIInterfaceInfo.cpp @@ -128,14 +128,14 @@ static PyObject *PyGetParent(PyObject *self, PyObject *args) if (pI==NULL) return NULL; - nsIInterfaceInfo *pRet; + nsCOMPtr pRet; nsresult r; Py_BEGIN_ALLOW_THREADS; - r = pI->GetParent(&pRet); + r = pI->GetParent(getter_AddRefs(pRet)); Py_END_ALLOW_THREADS; if ( NS_FAILED(r) ) return PyXPCOM_BuildPyException(r); - return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIInterfaceInfo), PR_FALSE, PR_FALSE); + return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIInterfaceInfo), PR_FALSE); } static PyObject *PyGetMethodCount(PyObject *self, PyObject *args) @@ -288,11 +288,11 @@ static PyObject *PyGetInfoForParam(PyObject *self, PyObject *args) if (!__GetMethodInfoHelper(pii, mi, pi, &pmi)) return NULL; const nsXPTParamInfo& param_info = pmi->GetParam((PRUint8)pi); - nsIInterfaceInfo *pnewii = nsnull; - nsresult n = pii->GetInfoForParam(mi, ¶m_info, &pnewii); + nsCOMPtr pnewii; + nsresult n = pii->GetInfoForParam(mi, ¶m_info, getter_AddRefs(pnewii)); if (NS_FAILED(n)) return PyXPCOM_BuildPyException(n); - return Py_nsISupports::PyObjectFromInterface(pnewii, NS_GET_IID(nsIInterfaceInfo), PR_FALSE); + return Py_nsISupports::PyObjectFromInterface(pnewii, NS_GET_IID(nsIInterfaceInfo)); } static PyObject *PyGetIIDForParam(PyObject *self, PyObject *args) diff --git a/mozilla/extensions/python/xpcom/src/PyIInterfaceInfoManager.cpp b/mozilla/extensions/python/xpcom/src/PyIInterfaceInfoManager.cpp index 773e172678f..54e58241f63 100644 --- a/mozilla/extensions/python/xpcom/src/PyIInterfaceInfoManager.cpp +++ b/mozilla/extensions/python/xpcom/src/PyIInterfaceInfoManager.cpp @@ -73,10 +73,10 @@ static PyObject *PyGetInfoForIID(PyObject *self, PyObject *args) if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) return NULL; - nsIInterfaceInfo *pi; + nsCOMPtr pi; nsresult r; Py_BEGIN_ALLOW_THREADS; - r = pI->GetInfoForIID(&iid, &pi); + r = pI->GetInfoForIID(&iid, getter_AddRefs(pi)); Py_END_ALLOW_THREADS; if ( NS_FAILED(r) ) return PyXPCOM_BuildPyException(r); @@ -85,7 +85,7 @@ static PyObject *PyGetInfoForIID(PyObject *self, PyObject *args) nsIID new_iid = NS_GET_IID(nsIInterfaceInfo); // Can not auto-wrap the interface info manager as it is critical to // building the support we need for autowrap. - return Py_nsISupports::PyObjectFromInterface(pi, new_iid, PR_FALSE, PR_FALSE); + return Py_nsISupports::PyObjectFromInterface(pi, new_iid, PR_FALSE); } static PyObject *PyGetInfoForName(PyObject *self, PyObject *args) @@ -98,10 +98,10 @@ static PyObject *PyGetInfoForName(PyObject *self, PyObject *args) if (pI==NULL) return NULL; - nsIInterfaceInfo *pi; + nsCOMPtr pi; nsresult r; Py_BEGIN_ALLOW_THREADS; - r = pI->GetInfoForName(name, &pi); + r = pI->GetInfoForName(name, getter_AddRefs(pi)); Py_END_ALLOW_THREADS; if ( NS_FAILED(r) ) return PyXPCOM_BuildPyException(r); @@ -109,7 +109,7 @@ static PyObject *PyGetInfoForName(PyObject *self, PyObject *args) /* Return a type based on the IID (with no extra ref) */ // Can not auto-wrap the interface info manager as it is critical to // building the support we need for autowrap. - return Py_nsISupports::PyObjectFromInterface(pi, NS_GET_IID(nsIInterfaceInfo), PR_FALSE, PR_FALSE); + return Py_nsISupports::PyObjectFromInterface(pi, NS_GET_IID(nsIInterfaceInfo), PR_FALSE); } static PyObject *PyGetNameForIID(PyObject *self, PyObject *args) @@ -171,15 +171,15 @@ static PyObject *PyEnumerateInterfaces(PyObject *self, PyObject *args) if (pI==NULL) return NULL; - nsIEnumerator *pRet; + nsCOMPtr pRet; nsresult r; Py_BEGIN_ALLOW_THREADS; - r = pI->EnumerateInterfaces(&pRet); + r = pI->EnumerateInterfaces(getter_AddRefs(pRet)); Py_END_ALLOW_THREADS; if ( NS_FAILED(r) ) return PyXPCOM_BuildPyException(r); - return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIEnumerator), PR_FALSE); + return Py_nsISupports::PyObjectFromInterface(pRet, NS_GET_IID(nsIEnumerator)); } // TODO: diff --git a/mozilla/extensions/python/xpcom/src/PyISimpleEnumerator.cpp b/mozilla/extensions/python/xpcom/src/PyISimpleEnumerator.cpp index 6295bc1ddee..b94d8eb2866 100644 --- a/mozilla/extensions/python/xpcom/src/PyISimpleEnumerator.cpp +++ b/mozilla/extensions/python/xpcom/src/PyISimpleEnumerator.cpp @@ -109,7 +109,9 @@ static PyObject *PyGetNext(PyObject *self, PyObject *args) } pRet = temp; } - return Py_nsISupports::PyObjectFromInterface(pRet, iid, PR_FALSE); + PyObject *ret = Py_nsISupports::PyObjectFromInterface(pRet, iid); + NS_IF_RELEASE(pRet); + return ret; } // A method added for Python performance if you really need @@ -169,7 +171,8 @@ static PyObject *PyFetchBlock(PyObject *self, PyObject *args) ret = PyList_New(n_fetched); if (ret) for (int i=0;im_obj) { - long rcnt; Py_BEGIN_ALLOW_THREADS; - rcnt = ob->m_obj->Release(); + ob->m_obj = nsnull; Py_END_ALLOW_THREADS; - -#ifdef _DEBUG_LIFETIMES - LogF(buf, " SafeRelease(%ld) -> %s at 0x%0lx, nsISupports at 0x%0lx - Release() returned %ld",GetCurrentThreadId(), ob->ob_type->tp_name,ob, ob->m_obj,rcnt); -#endif - ob->m_obj = NULL; } } @@ -117,6 +120,23 @@ Py_nsISupports::getattr(const char *name) if (strcmp(name, "IID")==0) return Py_nsIID::PyObjectFromIID( m_iid ); + // Support for __unicode__ until we get a tp_unicode slot. + if (strcmp(name, "__unicode__")==0) { + nsresult rv; + PRUnichar *val = NULL; + Py_BEGIN_ALLOW_THREADS; + { // scope to kill pointer while thread-lock released. + nsCOMPtr ss( do_QueryInterface(m_obj, &rv )); + if (NS_SUCCEEDED(rv)) + rv = ss->ToString(&val); + } // end-scope + Py_END_ALLOW_THREADS; + PyObject *ret = NS_FAILED(rv) ? + PyXPCOM_BuildPyException(rv) : + PyObject_FromNSString(val); + if (val) nsMemory::Free(val); + return ret; + } PyXPCOM_TypeObject *this_type = (PyXPCOM_TypeObject *)ob_type; return Py_FindMethodInChain(&this_type->chain, this, (char *)name); } @@ -231,8 +251,13 @@ Py_nsISupports::InterfaceFromPyObject(PyObject *ob, Py_DECREF(sub_ob); } } - *ppv = PyObject_AsVariant(ob); - return *ppv != NULL; + nsresult nr = PyObject_AsVariant(ob, (nsIVariant **)ppv); + if (NS_FAILED(nr)) { + PyXPCOM_BuildPyException(nr); + return PR_FALSE; + } + NS_ASSERTION(ppv != nsnull, "PyObject_AsVariant worked but gave null!"); + return PR_TRUE; } // end of variant support. @@ -273,33 +298,11 @@ Py_nsISupports::RegisterInterface( const nsIID &iid, PyTypeObject *t) } } -/*static */PyObject * -Py_nsISupports::PyObjectFromInterfaceOrVariant(nsISupports *pis, - const nsIID &riid, - PRBool bAddRef, - PRBool bMakeNicePyObject /* = PR_TRUE */) -{ - // Quick exit. - if (pis==NULL) { - Py_INCREF(Py_None); - return Py_None; - } - if (riid.Equals(NS_GET_IID(nsIVariant))) { - PyObject *ret = PyObject_FromVariant((nsIVariant *)pis); - // If we were asked not to add a reference, then there - // will be a spare reference on pis() - remove it. - if (!bAddRef) - pis->Release(); - return ret; - } - return PyObjectFromInterface(pis, riid, bAddRef, bMakeNicePyObject); -} - /*static */PyObject * Py_nsISupports::PyObjectFromInterface(nsISupports *pis, const nsIID &riid, - PRBool bAddRef, - PRBool bMakeNicePyObject /* = PR_TRUE */) + PRBool bMakeNicePyObject, /* = PR_TRUE */ + PRBool bIsInternalCall /* = PR_FALSE */) { // Quick exit. if (pis==NULL) { @@ -307,9 +310,15 @@ Py_nsISupports::PyObjectFromInterface(nsISupports *pis, return Py_None; } - // FIXME: if !bAddRef, in all error cases, do NS_RELEASE(pis) before return - // since that means we have a spare reference - + if (!bIsInternalCall) { +#ifdef NS_DEBUG + nsISupports *queryResult = nsnull; + pis->QueryInterface(riid, (void **)&queryResult); + NS_ASSERTION(queryResult == pis, "QueryInterface needed"); + NS_IF_RELEASE(queryResult); +#endif + } + PyTypeObject *createType = NULL; // If the IID is for nsISupports, don't bother with // a map lookup as we know the type! @@ -341,16 +350,15 @@ Py_nsISupports::PyObjectFromInterface(nsISupports *pis, PyXPCOM_LogF("XPCOM Object created at 0x%0xld, nsISupports at 0x%0xld", ret, ret->m_obj); #endif - if (ret && bAddRef && pis) pis->AddRef(); if (ret && bMakeNicePyObject) - return MakeInterfaceResult(ret, riid); + return MakeDefaultWrapper(ret, riid); return ret; } // Call back into Python, passing a raw nsIInterface object, getting back // the object to actually pass to Python. PyObject * -Py_nsISupports::MakeInterfaceResult(PyObject *pyis, +Py_nsISupports::MakeDefaultWrapper(PyObject *pyis, const nsIID &iid) { NS_PRECONDITION(pyis, "NULL pyobject!"); @@ -411,10 +419,17 @@ Py_nsISupports::QueryInterface(PyObject *self, PyObject *args) nsISupports *pMyIS = GetI(self); if (pMyIS==NULL) return NULL; - nsISupports *pis; + // Optimization, If we already wrap the IID, just return + // ourself. + if (!bWrap && iid.Equals(((Py_nsISupports *)self)->m_iid)) { + Py_INCREF(self); + return self; + } + + nsCOMPtr pis; nsresult r; Py_BEGIN_ALLOW_THREADS; - r = pMyIS->QueryInterface(iid, (void **)&pis); + r = pMyIS->QueryInterface(iid, getter_AddRefs(pis)); Py_END_ALLOW_THREADS; /* Note that this failure may include E_NOINTERFACE */ @@ -422,7 +437,7 @@ Py_nsISupports::QueryInterface(PyObject *self, PyObject *args) return PyXPCOM_BuildPyException(r); /* Return a type based on the IID (with no extra ref) */ - return PyObjectFromInterface(pis, iid, PR_FALSE, (PRBool)bWrap); + return ((Py_nsISupports *)self)->MakeInterfaceResult(pis, iid, (PRBool)bWrap); } diff --git a/mozilla/extensions/python/xpcom/src/PyIVariant.cpp b/mozilla/extensions/python/xpcom/src/PyIVariant.cpp index 61632a2eb0c..8d1f0dcd4dd 100644 --- a/mozilla/extensions/python/xpcom/src/PyIVariant.cpp +++ b/mozilla/extensions/python/xpcom/src/PyIVariant.cpp @@ -64,13 +64,10 @@ static PyObject *MyChar( char c) { return PyString_FromStringAndSize(&c, 1); } static PyObject *MyUChar( PRUnichar c) { - return PyUnicode_FromPRUnichar(&c, 1); + return PyObject_FromNSString( &c, 1); } static PyObject *MyUnicode( PRUnichar *p) { - return PyUnicode_FromPRUnichar(p, nsCRT::strlen(p)); -} -static PyObject *MyISupports( nsISupports *p) { - return Py_nsISupports::PyObjectFromInterface(p, NS_GET_IID(nsISupports), PR_FALSE); + return PyObject_FromNSString(p); } #define GET_SIMPLE(Type, FuncGet, FuncConvert) \ @@ -123,32 +120,49 @@ GET_SIMPLE(double, GetAsDouble, PyFloat_FromDouble) GET_SIMPLE(PRBool, GetAsBool, MyBool) GET_SIMPLE(char, GetAsChar, MyChar) GET_SIMPLE(PRUnichar, GetAsWChar, MyUChar) -GET_SIMPLE(nsISupports *, GetAsISupports, MyISupports) GET_SIMPLE(nsIID, GetAsID, Py_nsIID::PyObjectFromIID) GET_ALLOCATED(char *, GetAsString, PyString_FromString, nsMemory::Free) GET_ALLOCATED(PRUnichar *, GetAsWString, MyUnicode, nsMemory::Free) GET_ALLOCATED_SIZE(char *, GetAsStringWithSize, PyString_FromStringAndSize, nsMemory::Free) -GET_ALLOCATED_SIZE(PRUnichar *, GetAsWStringWithSize, PyUnicode_FromPRUnichar, nsMemory::Free) +GET_ALLOCATED_SIZE(PRUnichar *, GetAsWStringWithSize, PyObject_FromNSString, nsMemory::Free) static PyObject *GetAsInterface(PyObject *self, PyObject *args) { nsIVariant *pI = GetI(self); if (pI==NULL) return NULL; if (!PyArg_ParseTuple(args, ":GetAsInterface")) return NULL; - nsISupports *p; + nsCOMPtr p; nsIID *iid; - nsresult nr = pI->GetAsInterface(&iid, (void **)&p); + nsresult nr = pI->GetAsInterface(&iid, getter_AddRefs(p)); if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); - return Py_nsISupports::PyObjectFromInterface(p, *iid, PR_FALSE); + return Py_nsISupports::PyObjectFromInterface(p, *iid); } -extern PyObject *PyObject_FromVariantArray( nsIVariant *v); +static PyObject *GetAsISupports(PyObject *self, PyObject *args) { + nsIVariant *pI = GetI(self); + if (pI==NULL) return NULL; + if (!PyArg_ParseTuple(args, ":GetAsInterface")) return NULL; + nsCOMPtr p; + nsIID *iid; + nsresult nr = pI->GetAsInterface(&iid, getter_AddRefs(p)); + if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); + return Py_nsISupports::PyObjectFromInterface(p, *iid); +} + +extern PyObject *PyObject_FromVariantArray( Py_nsISupports*, nsIVariant *v); static PyObject *GetAsArray(PyObject *self, PyObject *args) { nsIVariant *pI = GetI(self); if (pI==NULL) return NULL; if (!PyArg_ParseTuple(args, ":GetAsArray")) return NULL; - return PyObject_FromVariantArray(pI); + return PyObject_FromVariantArray((Py_nsISupports *)self, pI); +} + +static PyObject *Get(PyObject *self, PyObject *args) { + nsIVariant *pI = GetI(self); + if (pI==NULL) return NULL; + if (!PyArg_ParseTuple(args, ":Get")) return NULL; + return PyObject_FromVariant((Py_nsISupports *)self, pI); } struct PyMethodDef @@ -175,6 +189,7 @@ PyMethods_IVariant[] = { "getAsInterface", GetAsInterface, 1}, { "getAsArray", GetAsArray, 1}, { "getAsID", GetAsID, 1}, + { "get", Get, 1}, {NULL} }; diff --git a/mozilla/extensions/python/xpcom/src/PyXPCOM.h b/mozilla/extensions/python/xpcom/src/PyXPCOM.h index fc853689c4e..e4399e697f5 100644 --- a/mozilla/extensions/python/xpcom/src/PyXPCOM.h +++ b/mozilla/extensions/python/xpcom/src/PyXPCOM.h @@ -49,26 +49,46 @@ #ifndef __PYXPCOM_H__ #define __PYXPCOM_H__ -#ifdef XP_WIN -# ifdef BUILD_PYXPCOM - /* We are building the main dll */ -# define PYXPCOM_EXPORT __declspec(dllexport) -# else - /* This module uses the dll */ -# define PYXPCOM_EXPORT __declspec(dllimport) -# endif // BUILD_PYXPCOM +#include "nsIAllocator.h" +#include "nsIWeakReference.h" +#include "nsIInterfaceInfoManager.h" +#include "nsIClassInfo.h" +#include "nsIComponentManager.h" +#include "nsIComponentManagerObsolete.h" +#include "nsIServiceManager.h" +#include "nsIInputStream.h" +#include "nsIVariant.h" +#include "nsIModule.h" - // We need these libs! -# pragma comment(lib, "xpcom.lib") -# pragma comment(lib, "nspr4.lib") +#include "nsXPIDLString.h" +#include "nsCRT.h" +#include "xptcall.h" +#include "xpt_xdr.h" -#else // XP_WIN -# define PYXPCOM_EXPORT -#endif // XP_WIN +#ifdef HAVE_LONG_LONG + // Mozilla also defines this - we undefine it to + // prevent a compiler warning. +# undef HAVE_LONG_LONG +#endif // HAVE_LONG_LONG +#ifdef _POSIX_C_SOURCE // Ditto here +# undef _POSIX_C_SOURCE +#endif // _POSIX_C_SOURCE + +#include + +#ifdef BUILD_PYXPCOM + /* We are building the main dll */ +# define PYXPCOM_EXPORT NS_EXPORT +#else + /* This module uses the dll */ +# define PYXPCOM_EXPORT NS_IMPORT +#endif // BUILD_PYXPCOM // An IID we treat as NULL when passing as a reference. -extern nsIID Py_nsIID_NULL; +extern PYXPCOM_EXPORT nsIID Py_nsIID_NULL; + +class Py_nsISupports; /************************************************************************* ************************************************************************** @@ -94,6 +114,13 @@ PYXPCOM_EXPORT PyObject *PyXPCOM_BuildPyException(nsresult res); // NOTE: this function assumes it is operating within the Python context PYXPCOM_EXPORT nsresult PyXPCOM_SetCOMErrorFromPyException(); +// Write current exception and traceback to a string. +PYXPCOM_EXPORT PRBool PyXPCOM_FormatCurrentException(nsCString &streamout); +// Write specified exception and traceback to a string. +PYXPCOM_EXPORT PRBool PyXPCOM_FormatGivenException(nsCString &streamout, + PyObject *exc_typ, PyObject *exc_val, + PyObject *exc_tb); + // A couple of logging/error functions. These probably end up // being written to the console service. @@ -108,6 +135,9 @@ PYXPCOM_EXPORT void PyXPCOM_LogWarning(const char *fmt, ...); // As it's designed for user error/warning, it exists in non-debug builds. PYXPCOM_EXPORT void PyXPCOM_LogError(const char *fmt, ...); +// The raw one +PYXPCOM_EXPORT void PyXPCOM_Log(const char *level, const nsCString &msg); + #ifdef DEBUG // Mainly designed for developers of the XPCOM package. // Only enabled in debug builds. @@ -117,9 +147,27 @@ PYXPCOM_EXPORT void PyXPCOM_LogDebug(const char *fmt, ...); #define PYXPCOM_LOG_DEBUG() #endif // DEBUG -// Create a Unicode Object from the PRUnichar buffer src of the given size -#define PyUnicode_FromPRUnichar(src, size) \ - PyUnicode_DecodeUTF16((char*)(src),sizeof(PRUnichar)*(size),NULL,NULL) +// Some utility converters +// moz strings to PyObject. +PYXPCOM_EXPORT PyObject *PyObject_FromNSString( const nsACString &s, + PRBool bAssumeUTF8 = PR_FALSE ); +PYXPCOM_EXPORT PyObject *PyObject_FromNSString( const nsAString &s ); +PYXPCOM_EXPORT PyObject *PyObject_FromNSString( const PRUnichar *s, + PRUint32 len = (PRUint32)-1); + +// PyObjects to moz strings. As per the moz string guide, we pass a reference +// to an abstract string +PYXPCOM_EXPORT PRBool PyObject_AsNSString( PyObject *ob, nsAString &aStr); + +// Variants. +PYXPCOM_EXPORT nsresult PyObject_AsVariant( PyObject *ob, nsIVariant **aRet); +PYXPCOM_EXPORT PyObject *PyObject_FromVariant( Py_nsISupports *parent, + nsIVariant *v); + +// Interfaces - these are the "official" functions +PYXPCOM_EXPORT PyObject *PyObject_FromNSInterface( nsISupports *aInterface, + const nsIID &iid, + PRBool bMakeNicePyObject = PR_TRUE); /************************************************************************* ************************************************************************** @@ -129,8 +177,6 @@ PYXPCOM_EXPORT void PyXPCOM_LogDebug(const char *fmt, ...); ************************************************************************** *************************************************************************/ -class Py_nsISupports; - typedef Py_nsISupports* (* PyXPCOM_I_CTOR)(nsISupports *, const nsIID &); ////////////////////////////////////////////////////////////////////////// @@ -174,6 +220,9 @@ public: class PYXPCOM_EXPORT Py_nsISupports : public PyObject { public: + // Check if a Python object can safely be cast to an Py_nsISupports, + // and optionally check that the object is wrapping the specified + // interface. static PRBool Check( PyObject *ob, const nsIID &checkIID = Py_nsIID_NULL) { Py_nsISupports *self = static_cast(ob); if (ob==NULL || !PyXPCOM_TypeObject::IsType(ob->ob_type )) @@ -184,31 +233,24 @@ public: } // Get the nsISupports interface from the PyObject WITH NO REF COUNT ADDED static nsISupports *GetI(PyObject *self, nsIID *ret_iid = NULL); - nsISupports *m_obj; + nsCOMPtr m_obj; nsIID m_iid; // Given an nsISupports and an Interface ID, create and return an object // Does not QI the object - the caller must ensure the nsISupports object - // is really a pointer to an object identified by the IID. - // PRBool bAddRef indicates if a COM reference count should be added to the interface. - // This depends purely on the context in which it is called. If the interface is obtained - // from a function that creates a new ref (eg, ???) then you should use - // FALSE. If you receive the pointer as (eg) a param to a gateway function, then - // you normally need to pass TRUE, as this is truly a new reference. - // *** ALWAYS take the time to get this right. *** + // is really a pointer to an object identified by the IID (although + // debug builds should check this) // PRBool bMakeNicePyObject indicates if we should call back into // Python to wrap the object. This allows Python code to // see the correct xpcom.client.Interface object even when calling - // xpcom function directly. + // xpcom functions directly from C++. + // NOTE: There used to be a bAddRef param to this as an internal + // optimization, but since removed. This function *always* takes a + // reference to the nsISupports. static PyObject *PyObjectFromInterface(nsISupports *ps, const nsIID &iid, - PRBool bAddRef, - PRBool bMakeNicePyObject = PR_TRUE); - - static PyObject *PyObjectFromInterfaceOrVariant(nsISupports *ps, - const nsIID &iid, - PRBool bAddRef, - PRBool bMakeNicePyObject = PR_TRUE); + PRBool bMakeNicePyObject = PR_TRUE, + PRBool bIsInternalCall = PR_FALSE); // Given a Python object that is a registered COM type, return a given // interface pointer on its underlying object, with a NEW REFERENCE ADDED. @@ -238,8 +280,8 @@ public: static PyObject *QueryInterface(PyObject *self, PyObject *args); // Internal (sort-of) objects. - static PyXPCOM_TypeObject *type; - static PyMethodDef methods[]; + static NS_EXPORT_STATIC_MEMBER_(PyXPCOM_TypeObject) *type; + static NS_EXPORT_STATIC_MEMBER_(PyMethodDef) methods[]; static PyObject *mapIIDToType; static void SafeRelease(Py_nsISupports *ob); static void RegisterInterface( const nsIID &iid, PyTypeObject *t); @@ -248,6 +290,14 @@ public: virtual ~Py_nsISupports(); virtual PyObject *getattr(const char *name); virtual int setattr(const char *name, PyObject *val); + // A virtual function to sub-classes can customize the way + // nsISupports objects are returned from their methods. + // ps is a new object just obtained from some operation performed on us + virtual PyObject *MakeInterfaceResult(nsISupports *ps, const nsIID &iid, + PRBool bMakeNicePyObject = PR_TRUE) { + return PyObjectFromInterface(ps, iid, bMakeNicePyObject); + } + protected: // ctor is protected - must create objects via // PyObjectFromInterface() @@ -255,7 +305,9 @@ protected: const nsIID &iid, PyTypeObject *type); - static PyObject *MakeInterfaceResult(PyObject *pyis, const nsIID &iid); + // Make a default wrapper for an ISupports (which is an + // xpcom.client.Component instance) + static PyObject *MakeDefaultWrapper(PyObject *pyis, const nsIID &iid); }; @@ -296,8 +348,8 @@ public: static long PyTypeMethod_hash(PyObject *self); static PyObject *PyTypeMethod_str(PyObject *self); static void PyTypeMethod_dealloc(PyObject *self); - static PyTypeObject type; - static PyMethodDef methods[]; + static NS_EXPORT_STATIC_MEMBER_(PyTypeObject) type; + static NS_EXPORT_STATIC_MEMBER_(PyMethodDef) methods[]; }; /////////////////////////////////////////////////////// @@ -307,7 +359,7 @@ class PythonTypeDescriptor; // Forward declare. class PYXPCOM_EXPORT PyXPCOM_InterfaceVariantHelper { public: - PyXPCOM_InterfaceVariantHelper(); + PyXPCOM_InterfaceVariantHelper(Py_nsISupports *parent); ~PyXPCOM_InterfaceVariantHelper(); PRBool Init(PyObject *obParams); PRBool FillArray(); @@ -327,6 +379,7 @@ protected: PyObject *m_typedescs; // desc of _all_ params, including hidden. PythonTypeDescriptor *m_python_type_desc_array; void **m_buffer_array; + Py_nsISupports *m_parent; }; @@ -457,6 +510,11 @@ private: return GATEWAY_BASE::ThisAsIID(iid); \ } \ +extern PYXPCOM_EXPORT void AddDefaultGateway(PyObject *instance, nsISupports *gateway); + +extern PYXPCOM_EXPORT PRInt32 _PyXPCOM_GetGatewayCount(void); +extern PYXPCOM_EXPORT PRInt32 _PyXPCOM_GetInterfaceCount(void); + // Weak Reference class. This is a true COM object, representing // a weak reference to a Python object. For each Python XPCOM object, @@ -496,7 +554,7 @@ private: nsresult BackFillVariant( PyObject *ob, int index); PyObject *MakeSingleParam(int index, PythonTypeDescriptor &td); PRBool GetIIDForINTERFACE_ID(int index, const nsIID **ppret); - nsresult GetArrayType(PRUint8 index, PRUint8 *ret); + nsresult GetArrayType(PRUint8 index, PRUint8 *ret, nsIID **ppiid); PRUint32 GetSizeIs( int var_index, PRBool is_arg1); PRBool SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size); PRBool CanSetSizeIs( int var_index, PRBool is_arg1 ); @@ -520,9 +578,6 @@ PyObject *PyObject_FromXPTParamDescriptor( const XPTParamDescriptor *d); PyObject *PyObject_FromXPTMethodDescriptor( const XPTMethodDescriptor *d); PyObject *PyObject_FromXPTConstant( const XPTConstDescriptor *d); -nsIVariant *PyObject_AsVariant( PyObject *ob); -PyObject *PyObject_FromVariant( nsIVariant *v); - // DLL reference counting functions. // Although we maintain the count, we never actually // finalize Python when it hits zero! @@ -579,8 +634,8 @@ public: // NEVER new one of these objects - only use on the stack! -extern PYXPCOM_EXPORT void PyXPCOM_MakePendingCalls(); -extern PYXPCOM_EXPORT PRBool PyXPCOM_Globals_Ensure(); +PYXPCOM_EXPORT void PyXPCOM_MakePendingCalls(); +PYXPCOM_EXPORT PRBool PyXPCOM_Globals_Ensure(); // For 2.3, use the PyGILState_ calls #if (PY_VERSION_HEX >= 0x02030000) @@ -605,12 +660,12 @@ public: }; #else -extern PYXPCOM_EXPORT PyInterpreterState *PyXPCOM_InterpreterState; -extern PYXPCOM_EXPORT PRBool PyXPCOM_ThreadState_Ensure(); -extern PYXPCOM_EXPORT void PyXPCOM_ThreadState_Free(); -extern PYXPCOM_EXPORT void PyXPCOM_ThreadState_Clear(); -extern PYXPCOM_EXPORT void PyXPCOM_InterpreterLock_Acquire(); -extern PYXPCOM_EXPORT void PyXPCOM_InterpreterLock_Release(); +PYXPCOM_EXPORT PyInterpreterState *PyXPCOM_InterpreterState; +PYXPCOM_EXPORT PRBool PyXPCOM_ThreadState_Ensure(); +PYXPCOM_EXPORT void PyXPCOM_ThreadState_Free(); +PYXPCOM_EXPORT void PyXPCOM_ThreadState_Clear(); +PYXPCOM_EXPORT void PyXPCOM_InterpreterLock_Acquire(); +PYXPCOM_EXPORT void PyXPCOM_InterpreterLock_Release(); // Pre 2.3 thread-state dances. class CEnterLeavePython { @@ -662,11 +717,11 @@ extern struct PyMethodDef Methods[]; \ class ClassName : public Py_nsISupports \ { \ public: \ - static PyXPCOM_TypeObject *type; \ + static PYXPCOM_EXPORT PyXPCOM_TypeObject *type; \ static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \ return new ClassName(pInitObj, iid); \ } \ - static void InitType(PyObject *iidNameDict) { \ + static void InitType() { \ type = new PyXPCOM_TypeObject( \ #InterfaceName, \ Py_nsISupports::type, \ @@ -675,9 +730,6 @@ public: \ Constructor); \ const nsIID &iid = NS_GET_IID(InterfaceName); \ RegisterInterface(iid, type); \ - PyObject *iid_ob = Py_nsIID::PyObjectFromIID(iid); \ - PyDict_SetItemString(iidNameDict, "IID_"#InterfaceName, iid_ob); \ - Py_DECREF(iid_ob); \ } \ protected: \ ClassName(nsISupports *p, const nsIID &iid) : \ @@ -700,7 +752,7 @@ public: \ static Py_nsISupports *Constructor(nsISupports *pInitObj, const nsIID &iid) { \ return new ClassName(pInitObj, iid); \ } \ - static void InitType(PyObject *iidNameDict) { \ + static void InitType() { \ type = new PyXPCOM_TypeObject( \ #InterfaceName, \ Py_nsISupports::type, \ @@ -709,9 +761,6 @@ public: \ Constructor); \ const nsIID &iid = NS_GET_IID(InterfaceName); \ RegisterInterface(iid, type); \ - PyObject *iid_ob = Py_nsIID::PyObjectFromIID(iid); \ - PyDict_SetItemString(iidNameDict, "IID_"#InterfaceName, iid_ob); \ - Py_DECREF(iid_ob); \ } \ virtual PyObject *getattr(const char *name); \ virtual int setattr(const char *name, PyObject *val); \ @@ -740,5 +789,4 @@ PyXPCOM_ATTR_INTERFACE_DECLARE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassIn PyXPCOM_ATTR_INTERFACE_DECLARE(Py_nsIVariant, nsIVariant, PyMethods_IVariant) // deprecated, but retained for backward compatibility: PyXPCOM_INTERFACE_DECLARE(Py_nsIComponentManagerObsolete, nsIComponentManagerObsolete, PyMethods_IComponentManagerObsolete) - #endif // __PYXPCOM_H__ diff --git a/mozilla/extensions/python/xpcom/src/PyXPCOM_std.h b/mozilla/extensions/python/xpcom/src/PyXPCOM_std.h index a244ab99658..b7b7ff8c312 100644 --- a/mozilla/extensions/python/xpcom/src/PyXPCOM_std.h +++ b/mozilla/extensions/python/xpcom/src/PyXPCOM_std.h @@ -49,29 +49,6 @@ // // (c) 2000, ActiveState corp. -#include - -#ifdef HAVE_LONG_LONG - // Mozilla also defines this - we undefine it to - // prevent a compiler warning. -# undef HAVE_LONG_LONG -#endif // HAVE_LONG_LONG - -#include "nsIAllocator.h" -#include "nsIWeakReference.h" -#include "nsIInterfaceInfoManager.h" -#include "nsIClassInfo.h" -#include "nsIComponentManager.h" -#include "nsIComponentManagerObsolete.h" -#include "nsIServiceManager.h" -#include "nsIInputStream.h" -#include "nsIVariant.h" - -#include "nsXPIDLString.h" -#include "nsCRT.h" -#include "xptcall.h" -#include "xpt_xdr.h" - // This header is considered internal - hence // we can use it to trigger "exports" #define BUILD_PYXPCOM diff --git a/mozilla/extensions/python/xpcom/src/Pyxpt_info.cpp b/mozilla/extensions/python/xpcom/src/Pyxpt_info.cpp index a39fbd004ab..30fe48f2b13 100644 --- a/mozilla/extensions/python/xpcom/src/Pyxpt_info.cpp +++ b/mozilla/extensions/python/xpcom/src/Pyxpt_info.cpp @@ -152,7 +152,7 @@ PyObject *PyObject_FromXPTConstant( const XPTConstDescriptor *c) v = PyString_FromStringAndSize(&c->value.ch, 1); break; case TD_WCHAR: - v = PyUnicode_FromPRUnichar((PRUnichar *)&c->value.wch, 1); + v = PyObject_FromNSString((PRUnichar *)&c->value.wch, 1); break; // TD_VOID = 13, case TD_PNSIID: @@ -163,7 +163,7 @@ PyObject *PyObject_FromXPTConstant( const XPTConstDescriptor *c) v = PyString_FromString(c->value.str); break; case TD_PWSTRING: - v = PyUnicode_FromPRUnichar((PRUnichar *)c->value.wstr, nsCRT::strlen((PRUnichar *)c->value.wstr)); + v = PyObject_FromNSString((PRUnichar *)c->value.wstr, nsCRT::strlen((PRUnichar *)c->value.wstr)); break; // TD_INTERFACE_TYPE = 18, // TD_INTERFACE_IS_TYPE = 19, diff --git a/mozilla/extensions/python/xpcom/src/TypeObject.cpp b/mozilla/extensions/python/xpcom/src/TypeObject.cpp index a20276791d8..a8981bf66a3 100644 --- a/mozilla/extensions/python/xpcom/src/TypeObject.cpp +++ b/mozilla/extensions/python/xpcom/src/TypeObject.cpp @@ -69,10 +69,10 @@ static PyTypeObject PyInterfaceType_Type = { 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ - 0, /*tp_xxx1*/ - 0, /*tp_xxx2*/ - 0, /*tp_xxx3*/ - 0, /*tp_xxx4*/ + 0, /* tp_getattro */ + 0, /*tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ "Define the behavior of a PythonCOM Interface type.", }; @@ -149,7 +149,8 @@ PyXPCOM_TypeObject::Py_repr(PyObject *self) iid_repr = pis->m_iid.ToString(); // XXX - need some sort of buffer overflow. char buf[512]; - sprintf(buf, "", iid_repr, self, pis->m_obj); + sprintf(buf, "", + iid_repr, (void *)self, (void *)pis->m_obj.get()); nsMemory::Free(iid_repr); return PyString_FromString(buf); } @@ -199,9 +200,24 @@ PyXPCOM_TypeObject::PyXPCOM_TypeObject( const char *name, PyXPCOM_TypeObject *pB 0, /* tp_as_number*/ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ - Py_hash, /* tp_hash */ + Py_hash, /* tp_hash */ 0, /* tp_call */ Py_str, /* tp_str */ + 0, /* tp_getattro */ + 0, /*tp_setattro */ + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ }; *((PyTypeObject *)this) = type_template; diff --git a/mozilla/extensions/python/xpcom/src/VariantUtils.cpp b/mozilla/extensions/python/xpcom/src/VariantUtils.cpp index 0b5be5ee7ca..1a8949f9a2d 100644 --- a/mozilla/extensions/python/xpcom/src/VariantUtils.cpp +++ b/mozilla/extensions/python/xpcom/src/VariantUtils.cpp @@ -72,6 +72,9 @@ IsNullDOMString( const nsACString& aString ) return PR_FALSE; } +#define PyUnicode_FromPRUnichar(src, size) \ + PyUnicode_DecodeUTF16((char*)(src),sizeof(PRUnichar)*(size),NULL,NULL) + // Create a zero-terminated PRUnichar buffer from a Python unicode. // On success, returns 0. On failure, returns -1 and sets an exception. // dest_out must not be null. size_out may be null. @@ -104,7 +107,7 @@ PyUnicode_AsPRUnichar(PyObject *obj, PRUnichar **dest_out, PRUint32 *size_out) return 0; } -PyObject *PyObject_FromNSString( const nsACString &s, PRBool bAssumeUTF8 = PR_FALSE ) +PyObject *PyObject_FromNSString( const nsACString &s, PRBool bAssumeUTF8 /*= PR_FALSE */) { PyObject *ret; if (IsNullDOMString(s)) { @@ -134,12 +137,51 @@ PyObject *PyObject_FromNSString( const nsAString &s ) ret = Py_None; Py_INCREF(Py_None); } else { - const nsPromiseFlatString& temp = PromiseFlatString(s); - ret = PyUnicode_FromPRUnichar(temp.get(), temp.Length()); + const nsPromiseFlatString& temp = PromiseFlatString(s); + ret = PyUnicode_FromPRUnichar(temp.get(), temp.Length()); } return ret; } +PyObject *PyObject_FromNSString( const PRUnichar *s, + PRUint32 len /* = (PRUint32)-1*/) +{ + return PyUnicode_FromPRUnichar(s, + len==((PRUint32)-1)? nsCRT::strlen(s) : len); +} + +PRBool PyObject_AsNSString( PyObject *val, nsAString &aStr) +{ + if (val == Py_None) { + aStr.Truncate(); + return NS_OK; + } + PyObject *val_use = NULL; + PRBool ok = PR_TRUE; + if (!PyString_Check(val) && !PyUnicode_Check(val)) { + PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); + ok = PR_FALSE; + } + if (ok && (val_use = PyUnicode_FromObject(val))==NULL) + ok = PR_FALSE; + if (ok) { + if (PyUnicode_GET_SIZE(val_use) == 0) { + aStr.Truncate(); + } + else { + PRUint32 nch; + PRUnichar *tempo; + // can we do this without the copy? + if (PyUnicode_AsPRUnichar(val_use, &tempo, &nch) < 0) + return PR_FALSE; + aStr.Assign(tempo, nch); + nsMemory::Free(tempo); + } + } + Py_XDECREF(val_use); + return ok; +} + // Array utilities static PRUint32 GetArrayElementSize( PRUint8 t) { @@ -247,7 +289,8 @@ void FreeSingleArray(void *array_ptr, PRUint32 sequence_size, PRUint8 array_type #define BREAK_FALSE {rc=PR_FALSE;break;} -PRBool FillSingleArray(void *array_ptr, PyObject *sequence_ob, PRUint32 sequence_size, PRUint32 array_element_size, PRUint8 array_type) +PRBool FillSingleArray(void *array_ptr, PyObject *sequence_ob, PRUint32 sequence_size, + PRUint32 array_element_size, PRUint8 array_type, nsIID *pIID) { PRUint8 *pthis = (PRUint8 *)array_ptr; NS_ABORT_IF_FALSE(pthis, "Don't have a valid array to fill!"); @@ -441,7 +484,8 @@ PRBool FillSingleArray(void *array_ptr, PyObject *sequence_ob, PRUint32 sequence return rc; } -PyObject *UnpackSingleArray(void *array_ptr, PRUint32 sequence_size, PRUint8 array_type, nsIID *iid) +static PyObject *UnpackSingleArray(Py_nsISupports *parent, void *array_ptr, + PRUint32 sequence_size, PRUint8 array_type, nsIID *iid) { if (array_ptr==NULL) { Py_INCREF(Py_None); @@ -514,7 +558,17 @@ PyObject *UnpackSingleArray(void *array_ptr, PRUint32 sequence_size, PRUint8 arr case nsXPTType::T_INTERFACE_IS: case nsXPTType::T_INTERFACE: { nsISupports **pp = (nsISupports **)pthis; - val = Py_nsISupports::PyObjectFromInterface(*pp, iid ? *iid : NS_GET_IID(nsISupports), PR_TRUE); + // If we have an owning parent, let it create + // the object for us. + if (iid && iid->Equals(NS_GET_IID(nsIVariant))) + val = PyObject_FromVariant(parent, (nsIVariant *)*pp); + else if (parent) + val = parent->MakeInterfaceResult(*pp, iid ? *iid : NS_GET_IID(nsISupports)); + else + val = Py_nsISupports::PyObjectFromInterface( + *pp, + iid ? *iid : NS_GET_IID(nsISupports), + PR_TRUE); break; } default: { @@ -592,14 +646,11 @@ static PRUint16 BestVariantTypeForPyObject( PyObject *ob, BVFTResult *pdata = NU return (PRUint16)-1; } -nsIVariant *PyObject_AsVariant( PyObject *ob) +nsresult PyObject_AsVariant( PyObject *ob, nsIVariant **aRet) { - nsresult nr = NS_ERROR_UNEXPECTED; - nsCOMPtr v = do_CreateInstance("@mozilla.org/variant;1", &nr); - if (NS_FAILED(nr)) { - PyXPCOM_BuildPyException(nr); - return NULL; - } + nsresult nr = NS_OK; + nsCOMPtr v = do_CreateInstance("@mozilla.org/variant;1", &nr); + NS_ENSURE_SUCCESS(nr, nr); // *sigh* - I tried the abstract API (PyNumber_Check, etc) // but our COM instances too often qualify. BVFTResult cvt_result; @@ -628,6 +679,7 @@ nsIVariant *PyObject_AsVariant( PyObject *ob) PRUint32 nch; PRUnichar *p; if (PyUnicode_AsPRUnichar(ob, &p, &nch) < 0) { + PyXPCOM_LogWarning("Failed to convert object to unicode", ob->ob_type->tp_name); nr = NS_ERROR_UNEXPECTED; break; } @@ -665,12 +717,11 @@ nsIVariant *PyObject_AsVariant( PyObject *ob) int cb_buffer_pointer = seq_length * element_size; void *buffer_pointer; if ((buffer_pointer = (void *)nsMemory::Alloc(cb_buffer_pointer)) == nsnull) { - PyErr_NoMemory(); - nr = NS_ERROR_UNEXPECTED; + nr = NS_ERROR_OUT_OF_MEMORY; break; } memset(buffer_pointer, 0, cb_buffer_pointer); - if (FillSingleArray(buffer_pointer, ob, seq_length, element_size, array_type)) { + if (FillSingleArray(buffer_pointer, ob, seq_length, element_size, array_type, nsnull)) { nr = v->SetAsArray(array_type, &NS_GET_IID(nsISupports), seq_length, buffer_pointer); FreeSingleArray(buffer_pointer, seq_length, array_type); } else @@ -679,22 +730,22 @@ nsIVariant *PyObject_AsVariant( PyObject *ob) break; } case nsIDataType::VTYPE_EMPTY: - v->SetAsEmpty(); + nr = v->SetAsEmpty(); break; case nsIDataType::VTYPE_EMPTY_ARRAY: - v->SetAsEmptyArray(); + nr = v->SetAsEmptyArray(); break; case (PRUint16)-1: - PyErr_Format(PyExc_TypeError, "Objects of type '%s' can not be converted to an nsIVariant", ob->ob_type->tp_name); - return NULL; + PyXPCOM_LogWarning("Objects of type '%s' can not be converted to an nsIVariant", ob->ob_type->tp_name); + nr = NS_ERROR_UNEXPECTED; default: NS_ABORT_IF_FALSE(0, "BestVariantTypeForPyObject() returned a variant type not handled here!"); - PyErr_Format(PyExc_TypeError, "Objects of type '%s' can not be converted to an nsIVariant", ob->ob_type->tp_name); - return NULL; + PyXPCOM_LogWarning("Objects of type '%s' can not be converted to an nsIVariant", ob->ob_type->tp_name); + nr = NS_ERROR_UNEXPECTED; } - nsIVariant *ret; - v->QueryInterface(NS_GET_IID(nsIVariant), (void **)&ret); - return ret; + if (NS_FAILED(nr)) + return nr; + return v->QueryInterface(NS_GET_IID(nsIVariant), (void **)aRet); } static PyObject *MyBool_FromBool(PRBool v) @@ -703,10 +754,6 @@ static PyObject *MyBool_FromBool(PRBool v) Py_INCREF(ret); return ret; } -static PyObject *MyObject_FromInterface(nsISupports *p) -{ - return Py_nsISupports::PyObjectFromInterface(p, NS_GET_IID(nsISupports), PR_FALSE); -} #define GET_FROM_V(Type, FuncGet, FuncConvert) { \ Type t; \ @@ -715,7 +762,7 @@ static PyObject *MyObject_FromInterface(nsISupports *p) break; \ } -PyObject *PyObject_FromVariantArray( nsIVariant *v) +PyObject *PyObject_FromVariantArray( Py_nsISupports *parent, nsIVariant *v) { nsresult nr; NS_PRECONDITION(v, "NULL variant!"); @@ -732,13 +779,13 @@ PyObject *PyObject_FromVariantArray( nsIVariant *v) PRUint32 count; nr = v->GetAsArray(&type, &iid, &count, &p); if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr); - PyObject *ret = UnpackSingleArray(p, count, (PRUint8)type, &iid); + PyObject *ret = UnpackSingleArray(parent, p, count, (PRUint8)type, &iid); FreeSingleArray(p, count, (PRUint8)type); nsMemory::Free(p); return ret; } -PyObject *PyObject_FromVariant( nsIVariant *v) +PyObject *PyObject_FromVariant( Py_nsISupports *parent, nsIVariant *v) { if (!v) { Py_INCREF(Py_None); @@ -757,7 +804,7 @@ PyObject *PyObject_FromVariant( nsIVariant *v) Py_INCREF(Py_None); break; case nsIDataType::VTYPE_ARRAY: - ret = PyObject_FromVariantArray(v); + ret = PyObject_FromVariantArray(parent, v); break; case nsIDataType::VTYPE_INT8: case nsIDataType::VTYPE_INT16: @@ -799,13 +846,23 @@ PyObject *PyObject_FromVariant( nsIVariant *v) } case nsIDataType::VTYPE_ID: GET_FROM_V(nsIID, v->GetAsID, Py_nsIID::PyObjectFromIID); - case nsIDataType::VTYPE_INTERFACE: - GET_FROM_V(nsISupports *, v->GetAsISupports, MyObject_FromInterface); + case nsIDataType::VTYPE_INTERFACE: { + nsCOMPtr p; + if (NS_FAILED(nr=v->GetAsISupports(getter_AddRefs(p)))) goto done; + if (parent) + ret = parent->MakeInterfaceResult(p, NS_GET_IID(nsISupports)); + else + ret = Py_nsISupports::PyObjectFromInterface( + p, NS_GET_IID(nsISupports), PR_TRUE); + break; + } case nsIDataType::VTYPE_INTERFACE_IS: { - nsISupports *p; + nsCOMPtr p; nsIID *iid; - if (NS_FAILED(nr=v->GetAsInterface(&iid, (void **)&p))) goto done; - ret = Py_nsISupports::PyObjectFromInterface(p, *iid, PR_FALSE); + if (NS_FAILED(nr=v->GetAsInterface(&iid, getter_AddRefs(p)))) goto done; + // If the variant itself holds a variant, we should + // probably unpack that too? + ret = parent->MakeInterfaceResult(p, *iid); break; // case nsIDataType::VTYPE_WCHAR_STR // case nsIDataType::VTYPE_UTF8STRING @@ -899,16 +956,20 @@ Helpers when CALLING interfaces. ************************************************************************** *************************************************************************/ -PyXPCOM_InterfaceVariantHelper::PyXPCOM_InterfaceVariantHelper() +PyXPCOM_InterfaceVariantHelper::PyXPCOM_InterfaceVariantHelper(Py_nsISupports *parent) { m_var_array=nsnull; m_buffer_array=nsnull; m_pyparams=nsnull; m_num_array = 0; + // Parent should never die before we do, but let's not take the chance. + m_parent = parent; + Py_INCREF(parent); } PyXPCOM_InterfaceVariantHelper::~PyXPCOM_InterfaceVariantHelper() { + Py_DECREF(m_parent); Py_XDECREF(m_pyparams); for (int i=0;iMakeInterfaceResult(iret, iid); break; } case nsXPTType::T_INTERFACE_IS: { @@ -1674,15 +1720,18 @@ PyObject *PyXPCOM_InterfaceVariantHelper::MakeSinglePythonResult(int index) iid = NS_GET_IID(nsISupports); else iid = *piid; - } else + } else { // This is a pretty serious problem, but not Python's fault! // Just return an nsISupports and hope the caller does whatever // QI they need before using it. + NS_ERROR("Failed to get the IID for T_INTERFACE_IS!"); iid = NS_GET_IID(nsISupports); + } nsISupports *iret = *((nsISupports **)ns_v.ptr); - // We _do_ add a reference here, as our cleanup code will - // remove this reference should we own it. - ret = Py_nsISupports::PyObjectFromInterfaceOrVariant(iret, iid, PR_TRUE); + if (iid.Equals(NS_GET_IID(nsIVariant))) + ret = PyObject_FromVariant(m_parent, (nsIVariant *)iret); + else + ret = m_parent->MakeInterfaceResult(iret, iid); break; } case nsXPTType::T_ARRAY: { @@ -1696,7 +1745,7 @@ PyObject *PyXPCOM_InterfaceVariantHelper::MakeSinglePythonResult(int index) } PRUint8 array_type = (PRUint8)PyInt_AsLong(td.extra); PRUint32 seq_size = GetSizeIs(index, PR_FALSE); - ret = UnpackSingleArray(* ((void **)ns_v.ptr), seq_size, array_type&XPT_TDP_TAGMASK, NULL); + ret = UnpackSingleArray(m_parent, * ((void **)ns_v.ptr), seq_size, array_type&XPT_TDP_TAGMASK, NULL); break; } @@ -2032,17 +2081,20 @@ PyObject *PyXPCOM_GatewayVariantHelper::MakeSingleParam(int index, PythonTypeDes case nsXPTType::T_ARRAY: { void *t = DEREF_IN_OR_OUT(ns_v.val.p, void *); if (t==NULL) { - ret = Py_None; - Py_INCREF(Py_None); + // JS may send us a NULL here occasionally - as the + // type is array, we silently convert this to a zero + // length list, a-la JS. + ret = PyList_New(0); } else { PRUint8 array_type; - nsresult ns = GetArrayType(index, &array_type); + nsIID *piid; + nsresult ns = GetArrayType(index, &array_type, &piid); if (NS_FAILED(ns)) { PyXPCOM_BuildPyException(ns); break; } PRUint32 seq_size = GetSizeIs(index, PR_FALSE); - ret = UnpackSingleArray(t, seq_size, array_type&XPT_TDP_TAGMASK, NULL); + ret = UnpackSingleArray(NULL, t, seq_size, array_type&XPT_TDP_TAGMASK, piid); } break; } @@ -2081,7 +2133,7 @@ PyObject *PyXPCOM_GatewayVariantHelper::MakeSingleParam(int index, PythonTypeDes return ret; } -nsresult PyXPCOM_GatewayVariantHelper::GetArrayType(PRUint8 index, PRUint8 *ret) +nsresult PyXPCOM_GatewayVariantHelper::GetArrayType(PRUint8 index, PRUint8 *ret, nsIID **iid) { nsCOMPtr iim(do_GetService( NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); @@ -2098,6 +2150,13 @@ nsresult PyXPCOM_GatewayVariantHelper::GetArrayType(PRUint8 index, PRUint8 *ret) rc = ii->GetTypeForParam(m_method_index, ¶m_info, 1, &datumType); if (NS_FAILED(rc)) return rc; + if (iid) { + *iid = (nsIID *)&NS_GET_IID(nsISupports); + if (XPT_TDP_TAG(datumType)==nsXPTType::T_INTERFACE || + XPT_TDP_TAG(datumType)==nsXPTType::T_INTERFACE_IS || + XPT_TDP_TAG(datumType)==nsXPTType::T_ARRAY) + ii->GetIIDForParam(m_method_index, ¶m_info, iid); + } *ret = datumType.flags; return NS_OK; } @@ -2253,29 +2312,8 @@ nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index case nsXPTType::T_DOMSTRING: { nsAString *ws = (nsAString *)ns_v.val.p; NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??"); - if (val == Py_None) { - (*ws) = (PRUnichar *)nsnull; - } else { - if (!PyString_Check(val) && !PyUnicode_Check(val)) { - PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object"); - BREAK_FALSE; - } - val_use = PyUnicode_FromObject(val); - if (!val_use) - BREAK_FALSE; - NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didn't return a Unicode object!"); - if (PyUnicode_GET_SIZE(val_use) == 0) { - ws->Assign((PRUnichar*)NULL, 0); - } - else { - PRUint32 nch; - PRUnichar *sz; - if (PyUnicode_AsPRUnichar(val_use, &sz, &nch) < 0) - BREAK_FALSE; - ws->Assign(sz, nch); - nsMemory::Free(sz); - } - } + if (!PyObject_AsNSString(val, *ws)) + BREAK_FALSE; break; } case nsXPTType::T_CSTRING: { @@ -2389,8 +2427,6 @@ nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index break; } case nsXPTType::T_INTERFACE_IS: { - // We do allow NULL here, even tho doing so will no-doubt crash some objects. - // (but there will certainly be objects out there that will allow NULL :-( const nsIID *piid; if (!GetIIDForINTERFACE_ID(pi->type.argnum, &piid)) BREAK_FALSE; @@ -2521,7 +2557,8 @@ nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index // If it is an existing array of the correct size, keep it. PRUint32 sequence_size = 0; PRUint8 array_type; - nsresult ns = GetArrayType(index, &array_type); + nsIID *piid; + nsresult ns = GetArrayType(index, &array_type, &piid); if (NS_FAILED(ns)) return ns; PRUint32 element_size = GetArrayElementSize(array_type); @@ -2548,7 +2585,7 @@ nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index bBackFill = pi->IsIn(); } if (bBackFill) - rc = FillSingleArray(*(void **)ns_v.val.p, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK); + rc = FillSingleArray(*(void **)ns_v.val.p, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK, piid); else { // If it is an existing array, free it. void **pp = (void **)ns_v.val.p; @@ -2563,7 +2600,7 @@ nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index if (nbytes==0) nbytes = 1; // avoid assertion about 0 bytes *pp = (void *)nsMemory::Alloc(nbytes); memset(*pp, 0, nbytes); - rc = FillSingleArray(*pp, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK); + rc = FillSingleArray(*pp, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK, piid); if (!rc) break; if (bCanSetSizeIs) rc = SetSizeIs(index, PR_FALSE, sequence_size); diff --git a/mozilla/extensions/python/xpcom/src/dllmain.cpp b/mozilla/extensions/python/xpcom/src/dllmain.cpp index 282eacb0d8a..2205f55ca7d 100644 --- a/mozilla/extensions/python/xpcom/src/dllmain.cpp +++ b/mozilla/extensions/python/xpcom/src/dllmain.cpp @@ -47,6 +47,8 @@ #include "PyXPCOM_std.h" #include +#include "nsIThread.h" +#include "nsILocalFile.h" #ifdef XP_WIN #ifndef WIN32_LEAN_AND_MEAN @@ -58,6 +60,17 @@ static PRInt32 g_cLockCount = 0; static PRLock *g_lockMain = nsnull; +PYXPCOM_EXPORT PyObject *PyXPCOM_Error = NULL; + +PyXPCOM_INTERFACE_DEFINE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager) +PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager) +PyXPCOM_INTERFACE_DEFINE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator) +PyXPCOM_INTERFACE_DEFINE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator) +PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo) +PyXPCOM_INTERFACE_DEFINE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream) +PyXPCOM_INTERFACE_DEFINE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo) +PyXPCOM_INTERFACE_DEFINE(Py_nsIVariant, nsIVariant, PyMethods_IVariant) + #ifndef PYXPCOM_USE_PYGILSTATE //////////////////////////////////////////////////////////// @@ -245,3 +258,86 @@ struct DllInitializer { pyxpcom_destruct(); } } dll_initializer; + +//////////////////////////////////////////////////////////// +// Other helpers/global functions. +// +PRBool PyXPCOM_Globals_Ensure() +{ + PRBool rc = PR_TRUE; + +#ifndef PYXPCOM_USE_PYGILSTATE + PyXPCOM_InterpreterState_Ensure(); +#endif + + // The exception object - we load it from .py code! + if (PyXPCOM_Error == NULL) { + rc = PR_FALSE; + PyObject *mod = NULL; + + mod = PyImport_ImportModule("xpcom"); + if (mod!=NULL) { + PyXPCOM_Error = PyObject_GetAttrString(mod, "Exception"); + Py_DECREF(mod); + } + rc = (PyXPCOM_Error != NULL); + } + if (!rc) + return rc; + + static PRBool bHaveInitXPCOM = PR_FALSE; + if (!bHaveInitXPCOM) { + nsCOMPtr thread_check; + // xpcom appears to assert if already initialized + // Is there an official way to determine this? + if (NS_FAILED(nsIThread::GetMainThread(getter_AddRefs(thread_check)))) { + // not already initialized. +#ifdef XP_WIN + // On Windows, we need to locate the Mozilla bin + // directory. This by using locating a Moz DLL we depend + // on, and assume it lives in that bin dir. Different + // moz build types (eg, xulrunner, suite) package + // XPCOM itself differently - but all appear to require + // nspr4.dll - so this is what we use. + char landmark[MAX_PATH+1]; + HMODULE hmod = GetModuleHandle("nspr4.dll"); + if (hmod==NULL) { + PyErr_SetString(PyExc_RuntimeError, "We dont appear to be linked against nspr4.dll."); + return PR_FALSE; + } + GetModuleFileName(hmod, landmark, sizeof(landmark)/sizeof(landmark[0])); + char *end = landmark + (strlen(landmark)-1); + while (end > landmark && *end != '\\') + end--; + if (end > landmark) *end = '\0'; + + nsCOMPtr ns_bin_dir; + NS_ConvertASCIItoUCS2 strLandmark(landmark); + NS_NewLocalFile(strLandmark, PR_FALSE, getter_AddRefs(ns_bin_dir)); + nsresult rv = NS_InitXPCOM2(nsnull, ns_bin_dir, nsnull); +#else + // Elsewhere, Mozilla can find it itself (we hope!) + nsresult rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); +#endif // XP_WIN + if (NS_FAILED(rv)) { + PyErr_SetString(PyExc_RuntimeError, "The XPCOM subsystem could not be initialized"); + return PR_FALSE; + } + } + // Even if xpcom was already init, we want to flag it as init! + bHaveInitXPCOM = PR_TRUE; + // Register our custom interfaces. + + Py_nsISupports::InitType(); + Py_nsIComponentManager::InitType(); + Py_nsIInterfaceInfoManager::InitType(); + Py_nsIEnumerator::InitType(); + Py_nsISimpleEnumerator::InitType(); + Py_nsIInterfaceInfo::InitType(); + Py_nsIInputStream::InitType(); + Py_nsIClassInfo::InitType(); + Py_nsIVariant::InitType(); + } + return rc; +} + diff --git a/mozilla/extensions/python/xpcom/src/loader/Makefile.in b/mozilla/extensions/python/xpcom/src/loader/Makefile.in index 388a6e6addd..39227168b0f 100644 --- a/mozilla/extensions/python/xpcom/src/loader/Makefile.in +++ b/mozilla/extensions/python/xpcom/src/loader/Makefile.in @@ -46,14 +46,22 @@ include $(DEPTH)/config/autoconf.mk LIBRARY_NAME = pyloader IS_COMPONENT = 1 -REQUIRES = xpcom string xpcom_obsolete $(NULL) +REQUIRES = pyxpcom xpcom string xpcom_obsolete $(NULL) MOZILLA_INTERNAL_API = 1 FORCE_SHARED_LIB = 1 FORCE_USE_PIC = 1 LOCAL_INCLUDES = $(PYTHON_INCLUDES) + EXTRA_LIBS += $(PYTHON_LIBS) +ifeq ($(OS_ARCH), WINNT) +EXTRA_LIBS += $(DIST)/lib/pyxpcom.lib +else +EXTRA_LIBS += -lpyxpcom +endif + + CPPSRCS = \ pyloader.cpp \ $(NULL) diff --git a/mozilla/extensions/python/xpcom/src/loader/pyloader.cpp b/mozilla/extensions/python/xpcom/src/loader/pyloader.cpp index 64a18ef4672..7317e05b162 100644 --- a/mozilla/extensions/python/xpcom/src/loader/pyloader.cpp +++ b/mozilla/extensions/python/xpcom/src/loader/pyloader.cpp @@ -41,26 +41,13 @@ // // The main loader and registrar for Python. A thin DLL that is designed to live in // the xpcom "components" directory. Simply locates and loads the standard -// _xpcom support module and transfers control to that. +// pyxpcom core library and transfers control to that. -#include +#include -#ifdef HAVE_LONG_LONG -#undef HAVE_LONG_LONG -#endif - -#include "nsISupports.h" -#include "nsIModule.h" #include "nsDirectoryServiceDefs.h" #include "nsILocalFile.h" -#include "nsString.h" -#include "nsXPIDLString.h" -#include "nsString.h" -#include "stdlib.h" -#include "stdarg.h" -#include "nsReadableUtils.h" -#include "nsCRT.h" #include "nspr.h" // PR_fprintf #if (PY_VERSION_HEX >= 0x02030000) @@ -86,9 +73,6 @@ typedef nsresult (*pfnPyXPCOM_NSGetModule)(nsIComponentManager *servMgr, nsIModule** result); -pfnPyXPCOM_NSGetModule pfnEntryPoint = nsnull; - - static void LogError(const char *fmt, ...); static void LogDebug(const char *fmt, ...); @@ -133,6 +117,63 @@ void AddStandardPaths() } } +//////////////////////////////////////////////////////////// +// This is the main entry point that delegates into Python +nsresult PyXPCOM_NSGetModule(nsIComponentManager *servMgr, + nsIFile* location, + nsIModule** result) +{ + NS_PRECONDITION(result!=NULL, "null result pointer in PyXPCOM_NSGetModule!"); + NS_PRECONDITION(location!=NULL, "null nsIFile pointer in PyXPCOM_NSGetModule!"); + NS_PRECONDITION(servMgr!=NULL, "null servMgr pointer in PyXPCOM_NSGetModule!"); +#ifndef LOADER_LINKS_WITH_PYTHON + if (!Py_IsInitialized()) { + Py_Initialize(); + if (!Py_IsInitialized()) { + PyXPCOM_LogError("Python initialization failed!\n"); + return NS_ERROR_FAILURE; + } + PyEval_InitThreads(); +#ifndef PYXPCOM_USE_PYGILSTATE + PyXPCOM_InterpreterState_Ensure(); +#endif + PyEval_SaveThread(); + } +#endif // LOADER_LINKS_WITH_PYTHON + CEnterLeavePython _celp; + PyObject *func = NULL; + PyObject *obServMgr = NULL; + PyObject *obLocation = NULL; + PyObject *wrap_ret = NULL; + PyObject *args = NULL; + PyObject *mod = PyImport_ImportModule("xpcom.server"); + if (!mod) goto done; + func = PyObject_GetAttrString(mod, "NS_GetModule"); + if (func==NULL) goto done; + obServMgr = Py_nsISupports::PyObjectFromInterface(servMgr, NS_GET_IID(nsIComponentManager)); + if (obServMgr==NULL) goto done; + obLocation = Py_nsISupports::PyObjectFromInterface(location, NS_GET_IID(nsIFile)); + if (obLocation==NULL) goto done; + args = Py_BuildValue("OO", obServMgr, obLocation); + if (args==NULL) goto done; + wrap_ret = PyEval_CallObject(func, args); + if (wrap_ret==NULL) goto done; + Py_nsISupports::InterfaceFromPyObject(wrap_ret, NS_GET_IID(nsIModule), (nsISupports **)result, PR_FALSE, PR_FALSE); +done: + nsresult nr = NS_OK; + if (PyErr_Occurred()) { + PyXPCOM_LogError("Obtaining the module object from Python failed.\n"); + nr = PyXPCOM_SetCOMErrorFromPyException(); + } + Py_XDECREF(func); + Py_XDECREF(obServMgr); + Py_XDECREF(obLocation); + Py_XDECREF(wrap_ret); + Py_XDECREF(mod); + Py_XDECREF(args); + return nr; +} + extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, nsIFile* location, nsIModule** result) @@ -152,7 +193,6 @@ extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, #ifndef NS_DEBUG Py_OptimizeFlag = 1; #endif // NS_DEBUG - AddStandardPaths(); PyEval_InitThreads(); NS_TIMELINE_STOP_TIMER("PyXPCOM: Python initializing"); NS_TIMELINE_MARK_TIMER("PyXPCOM: Python initializing"); @@ -177,25 +217,6 @@ extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, #else PyGILState_STATE state = PyGILState_Ensure(); #endif // PYXPCOM_USE_PYGILSTATE - if (pfnEntryPoint == nsnull) { - PyObject *mod = PyImport_ImportModule("xpcom._xpcom"); - if (mod==NULL) { - LogError("Could not import the Python XPCOM extension\n"); - return NS_ERROR_FAILURE; - } - PyObject *obpfn = PyObject_GetAttrString(mod, "_NSGetModule_FuncPtr"); - void *pfn = NULL; - if (obpfn) { - NS_ABORT_IF_FALSE(PyLong_Check(obpfn)||PyInt_Check(obpfn), "xpcom._NSGetModule_FuncPtr is not a long!"); - pfn = PyLong_AsVoidPtr(obpfn); - } - pfnEntryPoint = (pfnPyXPCOM_NSGetModule)pfn; - } - if (pfnEntryPoint==NULL) { - LogError("Could not load main Python entry point\n"); - return NS_ERROR_FAILURE; - } - #ifdef MOZ_TIMELINE // If the timeline service is installed, see if we can install our hooks. if (NULL==PyImport_ImportModule("timeline_hook")) { @@ -204,6 +225,10 @@ extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, PyErr_Clear(); // but don't care if we can't. } #endif + // Add the standard paths always - we may not have been the first to + // init Python. + AddStandardPaths(); + #ifndef PYXPCOM_USE_PYGILSTATE // Abandon the thread-lock, as the first thing Python does // is re-establish the lock (the Python thread-state story SUCKS!!!) @@ -226,7 +251,7 @@ extern "C" NS_EXPORT nsresult NSGetModule(nsIComponentManager *servMgr, NS_TIMELINE_STOP_TIMER("PyXPCOM: Python threadstate setup"); NS_TIMELINE_MARK_TIMER("PyXPCOM: Python threadstate setup"); NS_TIMELINE_START_TIMER("PyXPCOM: PyXPCOM NSGetModule entry point"); - nsresult rc = (*pfnEntryPoint)(servMgr, location, result); + nsresult rc = PyXPCOM_NSGetModule(servMgr, location, result); NS_TIMELINE_STOP_TIMER("PyXPCOM: PyXPCOM NSGetModule entry point"); NS_TIMELINE_MARK_TIMER("PyXPCOM: PyXPCOM NSGetModule entry point"); return rc; diff --git a/mozilla/extensions/python/xpcom/src/module/Makefile.in b/mozilla/extensions/python/xpcom/src/module/Makefile.in new file mode 100644 index 00000000000..f39f742b511 --- /dev/null +++ b/mozilla/extensions/python/xpcom/src/module/Makefile.in @@ -0,0 +1,94 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is mozilla.org +# Portions created by the Initial Developer are Copyright (C) 2002 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond (original author) +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +# The xpcom._xpcom module + +DEPTH=../../../../.. + +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ +pyexecdir = @libdir@/python$(PYTHON_VER_DOTTED)/site-packages + +include $(DEPTH)/config/autoconf.mk + +LIBRARY_NAME = _xpcom$(PYTHON_DEBUG_SUFFIX) +REQUIRES = pyxpcom xpcom string $(NULL) +MOZILLA_INTERNAL_API = 1 +FORCE_SHARED_LIB = 1 +FORCE_USE_PIC = 1 + +DLL_SUFFIX=$(PYTHON_DLL_SUFFIX) +LOCAL_INCLUDES = $(PYTHON_INCLUDES) + +EXTRA_LIBS += $(PYTHON_LIBS) + +ifeq ($(OS_ARCH), WINNT) +EXTRA_LIBS += $(DIST)/lib/pyxpcom.lib +else +EXTRA_LIBS += -lpyxpcom +endif + +CPPSRCS= \ + _xpcom.cpp \ + $(NULL) + +include $(topsrcdir)/config/config.mk +include $(topsrcdir)/config/rules.mk + +EXTRA_DSO_LDOPTS += $(MOZ_COMPONENT_LIBS) +IMPORT_LIBRARY := $(SHARED_LIBRARY:.pyd=.lib) + +# Install into our Python directory +# default build installs into bin and lib - remove them +libs:: +ifeq ($(OS_ARCH),WINNT) + $(INSTALL) -m 555 $(SHARED_LIBRARY) $(DIST)/bin/python/xpcom +else + $(INSTALL) -m 555 $(SHARED_LIBRARY) $(DIST)/bin/python/xpcom + mv $(DIST)/bin/python/xpcom/$(SHARED_LIBRARY) $(DIST)/bin/python/xpcom/_xpcom.so +endif + rm -f $(DIST)/bin/$(SHARED_LIBRARY) + rm -f $(DIST)/lib/$(IMPORT_LIBRARY) + +install:: +ifneq ($(OS_ARCH),WINNT) + $(SYSINSTALL) $(IFLAGS2) $(SHARED_LIBRARY) $(DISTDIR)$(pyexecdir)/xpcom + mv $(DISTDIR)$(pyexecdir)/xpcom/$(SHARED_LIBRARY) $(DISTDIR)$(pyexecdir)/xpcom/_xpcom$(PYTHON_DLL_SUFFIX) +endif + +clobber:: + rm -f *.ilk *.pdb diff --git a/mozilla/extensions/python/xpcom/src/xpcom.cpp b/mozilla/extensions/python/xpcom/src/module/_xpcom.cpp similarity index 63% rename from mozilla/extensions/python/xpcom/src/xpcom.cpp rename to mozilla/extensions/python/xpcom/src/module/_xpcom.cpp index b21d3a4047f..89a0a1a4961 100644 --- a/mozilla/extensions/python/xpcom/src/xpcom.cpp +++ b/mozilla/extensions/python/xpcom/src/module/_xpcom.cpp @@ -45,14 +45,13 @@ // // (c) 2000, ActiveState corp. -#include "PyXPCOM_std.h" -#include "nsIThread.h" +#include "PyXPCOM.h" #include "nsXPCOM.h" #include "nsISupportsPrimitives.h" -#include "nsIModule.h" #include "nsIFile.h" -#include "nsILocalFile.h" #include "nsIComponentRegistrar.h" +#include "nsIConsoleService.h" +#include "nspr.h" // PR_fprintf #ifdef XP_WIN #ifndef WIN32_LEAN_AND_MEAN @@ -64,85 +63,12 @@ #include "nsIEventQueue.h" #include "nsIProxyObjectManager.h" -PYXPCOM_EXPORT PyObject *PyXPCOM_Error = NULL; -extern PRInt32 _PyXPCOM_GetGatewayCount(void); -extern PRInt32 _PyXPCOM_GetInterfaceCount(void); - -extern void AddDefaultGateway(PyObject *instance, nsISupports *gateway); - #define LOADER_LINKS_WITH_PYTHON #ifndef PYXPCOM_USE_PYGILSTATE -extern void PyXPCOM_InterpreterState_Ensure(); +extern PYXPCOM_EXPORT void PyXPCOM_InterpreterState_Ensure(); #endif -PyXPCOM_INTERFACE_DEFINE(Py_nsIComponentManager, nsIComponentManager, PyMethods_IComponentManager) -PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfoManager, nsIInterfaceInfoManager, PyMethods_IInterfaceInfoManager) -PyXPCOM_INTERFACE_DEFINE(Py_nsIEnumerator, nsIEnumerator, PyMethods_IEnumerator) -PyXPCOM_INTERFACE_DEFINE(Py_nsISimpleEnumerator, nsISimpleEnumerator, PyMethods_ISimpleEnumerator) -PyXPCOM_INTERFACE_DEFINE(Py_nsIInterfaceInfo, nsIInterfaceInfo, PyMethods_IInterfaceInfo) -PyXPCOM_INTERFACE_DEFINE(Py_nsIInputStream, nsIInputStream, PyMethods_IInputStream) -PyXPCOM_INTERFACE_DEFINE(Py_nsIClassInfo, nsIClassInfo, PyMethods_IClassInfo) -PyXPCOM_INTERFACE_DEFINE(Py_nsIVariant, nsIVariant, PyMethods_IVariant) - -//////////////////////////////////////////////////////////// -// This is the main entry point called by the Python component -// loader. -extern "C" NS_EXPORT nsresult PyXPCOM_NSGetModule(nsIComponentManager *servMgr, - nsIFile* location, - nsIModule** result) -{ - NS_PRECONDITION(result!=NULL, "null result pointer in PyXPCOM_NSGetModule!"); - NS_PRECONDITION(location!=NULL, "null nsIFile pointer in PyXPCOM_NSGetModule!"); - NS_PRECONDITION(servMgr!=NULL, "null servMgr pointer in PyXPCOM_NSGetModule!"); -#ifndef LOADER_LINKS_WITH_PYTHON - if (!Py_IsInitialized()) { - Py_Initialize(); - if (!Py_IsInitialized()) { - PyXPCOM_LogError("Python initialization failed!\n"); - return NS_ERROR_FAILURE; - } - PyEval_InitThreads(); -#ifndef PYXPCOM_USE_PYGILSTATE - PyXPCOM_InterpreterState_Ensure(); -#endif - PyEval_SaveThread(); - } -#endif // LOADER_LINKS_WITH_PYTHON - CEnterLeavePython _celp; - PyObject *func = NULL; - PyObject *obServMgr = NULL; - PyObject *obLocation = NULL; - PyObject *wrap_ret = NULL; - PyObject *args = NULL; - PyObject *mod = PyImport_ImportModule("xpcom.server"); - if (!mod) goto done; - func = PyObject_GetAttrString(mod, "NS_GetModule"); - if (func==NULL) goto done; - obServMgr = Py_nsISupports::PyObjectFromInterface(servMgr, NS_GET_IID(nsIComponentManager), PR_TRUE); - if (obServMgr==NULL) goto done; - obLocation = Py_nsISupports::PyObjectFromInterface(location, NS_GET_IID(nsIFile), PR_TRUE); - if (obLocation==NULL) goto done; - args = Py_BuildValue("OO", obServMgr, obLocation); - if (args==NULL) goto done; - wrap_ret = PyEval_CallObject(func, args); - if (wrap_ret==NULL) goto done; - Py_nsISupports::InterfaceFromPyObject(wrap_ret, NS_GET_IID(nsIModule), (nsISupports **)result, PR_FALSE, PR_FALSE); -done: - nsresult nr = NS_OK; - if (PyErr_Occurred()) { - PyXPCOM_LogError("Obtaining the module object from Python failed.\n"); - nr = PyXPCOM_SetCOMErrorFromPyException(); - } - Py_XDECREF(func); - Py_XDECREF(obServMgr); - Py_XDECREF(obLocation); - Py_XDECREF(wrap_ret); - Py_XDECREF(mod); - Py_XDECREF(args); - return nr; -} - // "boot-strap" methods - interfaces we need to get the base // interface support! @@ -151,15 +77,33 @@ PyXPCOMMethod_GetComponentManager(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; - nsIComponentManager* cm; + nsCOMPtr cm; nsresult rv; Py_BEGIN_ALLOW_THREADS; - rv = NS_GetComponentManager(&cm); + rv = NS_GetComponentManager(getter_AddRefs(cm)); Py_END_ALLOW_THREADS; if ( NS_FAILED(rv) ) return PyXPCOM_BuildPyException(rv); - return Py_nsISupports::PyObjectFromInterface(cm, NS_GET_IID(nsIComponentManager), PR_FALSE, PR_FALSE); + return Py_nsISupports::PyObjectFromInterface(cm, NS_GET_IID(nsIComponentManager), PR_FALSE); +} + +// No xpcom callable way to get at the registrar, even though the interface +// is scriptable. +static PyObject * +PyXPCOMMethod_GetComponentRegistrar(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + nsCOMPtr cm; + nsresult rv; + Py_BEGIN_ALLOW_THREADS; + rv = NS_GetComponentRegistrar(getter_AddRefs(cm)); + Py_END_ALLOW_THREADS; + if ( NS_FAILED(rv) ) + return PyXPCOM_BuildPyException(rv); + + return Py_nsISupports::PyObjectFromInterface(cm, NS_GET_IID(nsISupports), PR_FALSE); } static PyObject * @@ -167,16 +111,16 @@ PyXPCOMMethod_GetServiceManager(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; - nsIServiceManager* sm; + nsCOMPtr sm; nsresult rv; Py_BEGIN_ALLOW_THREADS; - rv = NS_GetServiceManager(&sm); + rv = NS_GetServiceManager(getter_AddRefs(sm)); Py_END_ALLOW_THREADS; if ( NS_FAILED(rv) ) return PyXPCOM_BuildPyException(rv); // Return a type based on the IID. - return Py_nsISupports::PyObjectFromInterface(sm, NS_GET_IID(nsIServiceManager), PR_FALSE); + return Py_nsISupports::PyObjectFromInterface(sm, NS_GET_IID(nsIServiceManager)); } static PyObject * @@ -192,7 +136,7 @@ PyXPCOMMethod_XPTI_GetInterfaceInfoManager(PyObject *self, PyObject *args) /* Return a type based on the IID (with no extra ref) */ // Can not auto-wrap the interface info manager as it is critical to // building the support we need for autowrap. - return Py_nsISupports::PyObjectFromInterface(im, NS_GET_IID(nsIInterfaceInfoManager), PR_TRUE, PR_FALSE); + return Py_nsISupports::PyObjectFromInterface(im, NS_GET_IID(nsIInterfaceInfoManager), PR_FALSE); } static PyObject * @@ -209,6 +153,11 @@ PyXPCOMMethod_XPTC_InvokeByIndex(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "OiO", &obIS, &index, &obParams)) return NULL; + if (!Py_nsISupports::Check(obIS)) { + return PyErr_Format(PyExc_TypeError, + "First param must be a native nsISupports wrapper (got %s)", + obIS->ob_type->tp_name); + } // Ack! We must ask for the "native" interface supported by // the object, not specifically nsISupports, else we may not // back the same pointer (eg, Python, following identity rules, @@ -220,7 +169,7 @@ PyXPCOMMethod_XPTC_InvokeByIndex(PyObject *self, PyObject *args) PR_FALSE)) return NULL; - PyXPCOM_InterfaceVariantHelper arg_helper; + PyXPCOM_InterfaceVariantHelper arg_helper((Py_nsISupports *)obIS); if (!arg_helper.Init(obParams)) return NULL; @@ -249,8 +198,8 @@ PyXPCOMMethod_WrapObject(PyObject *self, PyObject *args) if (!Py_nsIID::IIDFromPyObject(obIID, &iid)) return NULL; - nsISupports *ret = NULL; - nsresult r = PyXPCOM_XPTStub::CreateNew(ob, iid, (void **)&ret); + nsCOMPtr ret; + nsresult r = PyXPCOM_XPTStub::CreateNew(ob, iid, getter_AddRefs(ret)); if ( NS_FAILED(r) ) return PyXPCOM_BuildPyException(r); @@ -259,7 +208,7 @@ PyXPCOMMethod_WrapObject(PyObject *self, PyObject *args) AddDefaultGateway(ob, ret); // inject a weak reference to myself into the instance. // Now wrap it in an interface. - return Py_nsISupports::PyObjectFromInterface(ret, iid, PR_FALSE, bWrapClient); + return Py_nsISupports::PyObjectFromInterface(ret, iid, bWrapClient); } static PyObject * @@ -327,8 +276,8 @@ PyXPCOMMethod_NS_ShutdownXPCOM(PyObject *self, PyObject *args) nr = NS_ShutdownXPCOM(nsnull); Py_END_ALLOW_THREADS; - // Don't raise an exception - as we are probably shutting down - // and don't really care - just return the status + // Dont raise an exception - as we are probably shutting down + // and dont really case - just return the status return PyInt_FromLong(nr); } @@ -360,7 +309,7 @@ PyXPCOMMethod_GetProxyForObject(PyObject *self, PyObject *args) } nsresult rv_proxy; - nsISupports *presult = nsnull; + nsCOMPtr presult; Py_BEGIN_ALLOW_THREADS; nsCOMPtr proxyMgr = do_GetService(kProxyObjectManagerCID, &rv_proxy); @@ -370,7 +319,7 @@ PyXPCOMMethod_GetProxyForObject(PyObject *self, PyObject *args) iid, pob, flags, - (void **)&presult); + getter_AddRefs(presult)); } if (pQueueRelease) pQueueRelease->Release(); @@ -378,24 +327,69 @@ PyXPCOMMethod_GetProxyForObject(PyObject *self, PyObject *args) PyObject *result; if (NS_SUCCEEDED(rv_proxy) ) { - result = Py_nsISupports::PyObjectFromInterface(presult, iid, PR_FALSE); + result = Py_nsISupports::PyObjectFromInterface(presult, iid); } else { result = PyXPCOM_BuildPyException(rv_proxy); } return result; } +static PyObject * +PyXPCOMMethod_MakeVariant(PyObject *self, PyObject *args) +{ + PyObject *ob; + if (!PyArg_ParseTuple(args, "O:MakeVariant", &ob)) + return NULL; + nsCOMPtr pVar; + nsresult nr = PyObject_AsVariant(ob, getter_AddRefs(pVar)); + if (NS_FAILED(nr)) + return PyXPCOM_BuildPyException(nr); + if (pVar == nsnull) { + NS_ERROR("PyObject_AsVariant worked but returned a NULL ptr!"); + return PyXPCOM_BuildPyException(NS_ERROR_UNEXPECTED); + } + return Py_nsISupports::PyObjectFromInterface(pVar, NS_GET_IID(nsIVariant)); +} + +static PyObject * +PyXPCOMMethod_GetVariantValue(PyObject *self, PyObject *args) +{ + PyObject *ob, *obParent = NULL; + if (!PyArg_ParseTuple(args, "O|O:GetVariantValue", &ob, &obParent)) + return NULL; + + nsCOMPtr var; + if (!Py_nsISupports::InterfaceFromPyObject(ob, + NS_GET_IID(nsISupports), + getter_AddRefs(var), + PR_FALSE)) + return PyErr_Format(PyExc_ValueError, + "Object is not an nsIVariant (got %s)", + ob->ob_type->tp_name); + + Py_nsISupports *parent = nsnull; + if (obParent && obParent != Py_None) { + if (!Py_nsISupports::Check(obParent)) { + PyErr_SetString(PyExc_ValueError, + "Object not an nsISupports wrapper"); + return NULL; + } + parent = (Py_nsISupports *)obParent; + } + return PyObject_FromVariant(parent, var); +} + PyObject *PyGetSpecialDirectory(PyObject *self, PyObject *args) { char *dirname; if (!PyArg_ParseTuple(args, "s:GetSpecialDirectory", &dirname)) return NULL; - nsIFile *file = NULL; - nsresult r = NS_GetSpecialDirectory(dirname, &file); + nsCOMPtr file; + nsresult r = NS_GetSpecialDirectory(dirname, getter_AddRefs(file)); if ( NS_FAILED(r) ) return PyXPCOM_BuildPyException(r); // returned object swallows our reference. - return Py_nsISupports::PyObjectFromInterface(file, NS_GET_IID(nsIFile), PR_FALSE); + return Py_nsISupports::PyObjectFromInterface(file, NS_GET_IID(nsIFile)); } PyObject *AllocateBuffer(PyObject *self, PyObject *args) @@ -406,31 +400,38 @@ PyObject *AllocateBuffer(PyObject *self, PyObject *args) return PyBuffer_New(bufSize); } -PyObject *LogWarning(PyObject *self, PyObject *args) +// Writes a message to the console service. This could be done via pure +// Python code, but is useful when the logging code is actually the +// xpcom .py framework itself (ie, we don't want our logging framework to +// call back into the very code generating the log messages! +PyObject *LogConsoleMessage(PyObject *self, PyObject *args) { char *msg; if (!PyArg_ParseTuple(args, "s", &msg)) return NULL; - PyXPCOM_LogWarning("%s", msg); + + nsCOMPtr consoleService = do_GetService(NS_CONSOLESERVICE_CONTRACTID); + if (consoleService) + consoleService->LogStringMessage(NS_ConvertASCIItoUCS2(msg).get()); + else { + // This either means no such service, or in shutdown - hardly worth + // the warning, and not worth reporting an error to Python about - its + // log handler would just need to catch and ignore it. + // And as this is only called by this logging setup, any messages should + // still go to stderr or a logfile. + NS_WARNING("pyxpcom can't log console message."); + } + Py_INCREF(Py_None); return Py_None; } -PyObject *LogError(PyObject *self, PyObject *args) -{ - char *msg; - if (!PyArg_ParseTuple(args, "s", &msg)) - return NULL; - PyXPCOM_LogError("%s", msg); - Py_INCREF(Py_None); - return Py_None; -} - -extern PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args); +extern PYXPCOM_EXPORT PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args); static struct PyMethodDef xpcom_methods[]= { {"GetComponentManager", PyXPCOMMethod_GetComponentManager, 1}, + {"GetComponentRegistrar", PyXPCOMMethod_GetComponentRegistrar, 1}, {"XPTI_GetInterfaceInfoManager", PyXPCOMMethod_XPTI_GetInterfaceInfoManager, 1}, {"XPTC_InvokeByIndex", PyXPCOMMethod_XPTC_InvokeByIndex, 1}, {"GetServiceManager", PyXPCOMMethod_GetServiceManager, 1}, @@ -445,83 +446,13 @@ static struct PyMethodDef xpcom_methods[]= {"GetProxyForObject", PyXPCOMMethod_GetProxyForObject, 1}, {"GetSpecialDirectory", PyGetSpecialDirectory, 1}, {"AllocateBuffer", AllocateBuffer, 1}, - {"LogWarning", LogWarning, 1}, - {"LogError", LogError, 1}, + {"LogConsoleMessage", LogConsoleMessage, 1, "Write a message to the xpcom console service"}, + {"MakeVariant", PyXPCOMMethod_MakeVariant, 1}, + {"GetVariantValue", PyXPCOMMethod_GetVariantValue, 1}, + // These should no longer be used - just use the logging.getLogger('pyxpcom')... { NULL } }; -//////////////////////////////////////////////////////////// -// Other helpers/global functions. -// -PRBool PyXPCOM_Globals_Ensure() -{ - PRBool rc = PR_TRUE; - -#ifndef PYXPCOM_USE_PYGILSTATE - PyXPCOM_InterpreterState_Ensure(); -#endif - - // The exception object - we load it from .py code! - if (PyXPCOM_Error == NULL) { - rc = PR_FALSE; - PyObject *mod = NULL; - - mod = PyImport_ImportModule("xpcom"); - if (mod!=NULL) { - PyXPCOM_Error = PyObject_GetAttrString(mod, "Exception"); - Py_DECREF(mod); - } - rc = (PyXPCOM_Error != NULL); - } - if (!rc) - return rc; - - static PRBool bHaveInitXPCOM = PR_FALSE; - if (!bHaveInitXPCOM) { - nsCOMPtr thread_check; - // xpcom appears to assert if already initialized - // Is there an official way to determine this? - if (NS_FAILED(nsIThread::GetMainThread(getter_AddRefs(thread_check)))) { - // not already initialized. -#ifdef XP_WIN - // On Windows, we need to locate the Mozilla bin - // directory. This by using locating a Moz DLL we depend - // on, and assume it lives in that bin dir. Different - // moz build types (eg, xulrunner, suite) package - // XPCOM itself differently - but all appear to require - // nspr4.dll - so this is what we use. - char landmark[MAX_PATH+1]; - HMODULE hmod = GetModuleHandle("nspr4.dll"); - if (hmod==NULL) { - PyErr_SetString(PyExc_RuntimeError, "We dont appear to be linked against nspr4.dll."); - return PR_FALSE; - } - GetModuleFileName(hmod, landmark, sizeof(landmark)/sizeof(landmark[0])); - char *end = landmark + (strlen(landmark)-1); - while (end > landmark && *end != '\\') - end--; - if (end > landmark) *end = '\0'; - - nsCOMPtr ns_bin_dir; - NS_ConvertASCIItoUCS2 strLandmark(landmark); - NS_NewLocalFile(strLandmark, PR_FALSE, getter_AddRefs(ns_bin_dir)); - nsresult rv = NS_InitXPCOM2(nsnull, ns_bin_dir, nsnull); -#else - // Elsewhere, Mozilla can find it itself (we hope!) - nsresult rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); -#endif // XP_WIN - if (NS_FAILED(rv)) { - PyErr_SetString(PyExc_RuntimeError, "The XPCOM subsystem could not be initialized"); - return PR_FALSE; - } - } - // Even if xpcom was already init, we want to flag it as init! - bHaveInitXPCOM = PR_TRUE; - } - return rc; -} - - #define REGISTER_IID(t) { \ PyObject *iid_ob = Py_nsIID::PyObjectFromIID(NS_GET_IID(t)); \ PyDict_SetItemString(dict, "IID_"#t, iid_ob); \ @@ -562,16 +493,9 @@ init_xpcom() { } PyDict_SetItemString(dict, "IIDType", (PyObject *)&Py_nsIID::type); - // register our entry point. - PyObject *obFuncPtr = PyLong_FromVoidPtr((void *)&PyXPCOM_NSGetModule); - if (obFuncPtr) - PyDict_SetItemString(dict, - "_NSGetModule_FuncPtr", - obFuncPtr); - Py_XDECREF(obFuncPtr); - REGISTER_IID(nsISupports); REGISTER_IID(nsISupportsCString); + REGISTER_IID(nsISupportsString); REGISTER_IID(nsIModule); REGISTER_IID(nsIFactory); REGISTER_IID(nsIWeakReference); @@ -579,20 +503,33 @@ init_xpcom() { REGISTER_IID(nsIClassInfo); REGISTER_IID(nsIServiceManager); REGISTER_IID(nsIComponentRegistrar); + // Register our custom interfaces. + REGISTER_IID(nsIComponentManager); + REGISTER_IID(nsIInterfaceInfoManager); + REGISTER_IID(nsIEnumerator); + REGISTER_IID(nsISimpleEnumerator); + REGISTER_IID(nsIInterfaceInfo); + REGISTER_IID(nsIInputStream); + REGISTER_IID(nsIClassInfo); + REGISTER_IID(nsIVariant); + // for backward compatibility: + REGISTER_IID(nsIComponentManagerObsolete); - Py_nsISupports::InitType(); - Py_nsIComponentManager::InitType(dict); - Py_nsIInterfaceInfoManager::InitType(dict); - Py_nsIEnumerator::InitType(dict); - Py_nsISimpleEnumerator::InitType(dict); - Py_nsIInterfaceInfo::InitType(dict); - Py_nsIInputStream::InitType(dict); - Py_nsIClassInfo::InitType(dict); - Py_nsIVariant::InitType(dict); - + // No good reason not to expose this impl detail, and tests can use it + REGISTER_IID(nsIInternalPython); // We have special support for proxies - may as well add their constants! REGISTER_INT(PROXY_SYNC); REGISTER_INT(PROXY_ASYNC); REGISTER_INT(PROXY_ALWAYS); + // Build flags that may be useful. + PyObject *ob = PyBool_FromLong( +#ifdef NS_DEBUG + 1 +#else + 0 +#endif + ); + PyDict_SetItemString(dict, "NS_DEBUG", ob); + Py_DECREF(ob); } diff --git a/mozilla/extensions/python/xpcom/test/Makefile.in b/mozilla/extensions/python/xpcom/test/Makefile.in new file mode 100644 index 00000000000..ac666eec6df --- /dev/null +++ b/mozilla/extensions/python/xpcom/test/Makefile.in @@ -0,0 +1,52 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code +# +# The Initial Developer of the Original Code is mozilla.org. +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Hammond: author +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH =../../../.. + +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +DIRS = test_component $(NULL) + +include $(DEPTH)/config/autoconf.mk + + +include $(topsrcdir)/config/rules.mk + +check:: + @echo "Running Python XPCOM tests" + @$(PYTHON)$(PYTHON_DEBUG_SUFFIX) $(srcdir)/regrtest.py diff --git a/mozilla/extensions/python/xpcom/test/output/test_com_exceptions b/mozilla/extensions/python/xpcom/test/output/test_com_exceptions deleted file mode 100644 index 16e4bda15cf..00000000000 --- a/mozilla/extensions/python/xpcom/test/output/test_com_exceptions +++ /dev/null @@ -1,8 +0,0 @@ -test_com_exceptions -** Unhandled exception calling 'int8 do_short(in int16, inout int16, out int16, out retval int16);' -** Returning nsresult of NS_ERROR_FAILURE -** Unhandled exception calling 'int8 do_unsigned_short(in uint16, inout uint16, out uint16, out retval uint16);' -** Returning nsresult of NS_ERROR_FAILURE -** Unhandled exception calling 'int8 do_unsigned_long_long(in uint64, inout uint64, out uint64, out retval uint64);' -** Returning nsresult of NS_ERROR_FAILURE -The xpcom exception tests passed diff --git a/mozilla/extensions/python/xpcom/test/output/test_comfile b/mozilla/extensions/python/xpcom/test/output/test_comfile deleted file mode 100644 index 8de43addd96..00000000000 --- a/mozilla/extensions/python/xpcom/test/output/test_comfile +++ /dev/null @@ -1,7 +0,0 @@ -test_comfile -Open as string test worked. -Open as URL test worked. -File test using buffers worked. -Local file read test worked. -Read the correct data. -Chunks read the correct data. diff --git a/mozilla/extensions/python/xpcom/test/output/test_components b/mozilla/extensions/python/xpcom/test/output/test_components deleted file mode 100644 index 4a6386e75d8..00000000000 --- a/mozilla/extensions/python/xpcom/test/output/test_components +++ /dev/null @@ -1,4 +0,0 @@ -test_components -The interfaces object appeared to work! -The classes object appeared to work! -The ID function appeared to work! diff --git a/mozilla/extensions/python/xpcom/test/output/test_isupports_primitives b/mozilla/extensions/python/xpcom/test/output/test_isupports_primitives deleted file mode 100644 index 7765ac217f9..00000000000 --- a/mozilla/extensions/python/xpcom/test/output/test_isupports_primitives +++ /dev/null @@ -1,2 +0,0 @@ -test_isupports_primitives -The nsISupports primitive interface tests appeared to work diff --git a/mozilla/extensions/python/xpcom/test/output/test_streams b/mozilla/extensions/python/xpcom/test/output/test_streams deleted file mode 100644 index e81ef151a69..00000000000 --- a/mozilla/extensions/python/xpcom/test/output/test_streams +++ /dev/null @@ -1 +0,0 @@ -test_streams diff --git a/mozilla/extensions/python/xpcom/test/output/test_test_component b/mozilla/extensions/python/xpcom/test/output/test_test_component deleted file mode 100644 index c57c1325637..00000000000 --- a/mozilla/extensions/python/xpcom/test/output/test_test_component +++ /dev/null @@ -1,4 +0,0 @@ -test_test_component -Testing the Python.TestComponent component -The Python test component worked! -Javascript could successfully use the Python test component. diff --git a/mozilla/extensions/python/xpcom/test/output/test_weakreferences b/mozilla/extensions/python/xpcom/test/output/test_weakreferences deleted file mode 100644 index b337d26a5e9..00000000000 --- a/mozilla/extensions/python/xpcom/test/output/test_weakreferences +++ /dev/null @@ -1,2 +0,0 @@ -test_weakreferences -Weak-reference tests appear to have worked! diff --git a/mozilla/extensions/python/xpcom/test/pyxpcom_test_tools.py b/mozilla/extensions/python/xpcom/test/pyxpcom_test_tools.py index 765e08a9c14..447c544612a 100644 --- a/mozilla/extensions/python/xpcom/test/pyxpcom_test_tools.py +++ b/mozilla/extensions/python/xpcom/test/pyxpcom_test_tools.py @@ -1,4 +1,6 @@ -# test tools for the pyxpcom +# test tools for the pyxpcom bindings +from xpcom import _xpcom +import unittest # export a "getmemusage()" function that returns a useful "bytes used" count # for the current process. Growth in this when doing the same thing over and @@ -70,3 +72,55 @@ if have_pdh: else: def getmemusage(): return 0 + +# Test runner utilities, including some support for builtin leak tests. +class TestLoader(unittest.TestLoader): + def loadTestsFromTestCase(self, testCaseClass): + """Return a suite of all tests cases contained in testCaseClass""" + leak_tests = [] + for name in self.getTestCaseNames(testCaseClass): + real_test = testCaseClass(name) + leak_test = self._getTestWrapper(real_test) + leak_tests.append(leak_test) + return self.suiteClass(leak_tests) + def _getTestWrapper(self, test): + # later! see pywin32's win32/test/util.py + return test + def loadTestsFromModule(self, mod): + if hasattr(mod, "suite"): + ret = mod.suite() + else: + ret = unittest.TestLoader.loadTestsFromModule(self, mod) + assert ret.countTestCases() > 0, "No tests in %r" % (mod,) + return ret + def loadTestsFromName(self, name, module=None): + test = unittest.TestLoader.loadTestsFromName(self, name, module) + if isinstance(test, unittest.TestSuite): + pass # hmmm? print "Don't wrap suites yet!", test._tests + elif isinstance(test, unittest.TestCase): + test = self._getTestWrapper(test) + else: + print "XXX - what is", test + return test + +# A base class our tests should derive from (well, one day it will be) +TestCase = unittest.TestCase + +def suite_from_functions(*funcs): + suite = unittest.TestSuite() + for func in funcs: + suite.addTest(unittest.FunctionTestCase(func)) + return suite + +def testmain(*args, **kw): + new_kw = kw.copy() + if not new_kw.has_key('testLoader'): + new_kw['testLoader'] = TestLoader() + try: + unittest.main(*args, **new_kw) + finally: + _xpcom.NS_ShutdownXPCOM() + ni = _xpcom._GetInterfaceCount() + ng = _xpcom._GetGatewayCount() + if ni or ng: + print "********* WARNING - Leaving with %d/%d objects alive" % (ni,ng) diff --git a/mozilla/extensions/python/xpcom/test/regrtest.py b/mozilla/extensions/python/xpcom/test/regrtest.py index 3345c8fae63..90d07948c78 100644 --- a/mozilla/extensions/python/xpcom/test/regrtest.py +++ b/mozilla/extensions/python/xpcom/test/regrtest.py @@ -42,28 +42,50 @@ import os import sys import unittest -import test.regrtest # The standard Python test suite. -path = os.path.abspath(os.path.split(sys.argv[0])[0]) -# This sucks - python now uses "test." - so to worm around this, -# we append our test path to the test packages! -test.__path__.append(path) +# A little magic to create a single "test suite" from all test_ files +# in this dir. A single suite makes for prettier output test :) +def suite(): + # Loop over all test_*.py files here + try: + me = __file__ + except NameError: + me = sys.argv[0] + me = os.path.abspath(me) + files = os.listdir(os.path.dirname(me)) + suite = unittest.TestSuite() + # XXX - add the others here! + #suite.addTest(unittest.FunctionTestCase(import_all)) + for file in files: + base, ext = os.path.splitext(file) + if ext=='.py' and os.path.basename(base).startswith("test_"): + mod = __import__(base) + if hasattr(mod, "suite"): + test = mod.suite() + else: + test = unittest.defaultTestLoader.loadTestsFromModule(mod) + suite.addTest(test) + return suite + +class CustomLoader(unittest.TestLoader): + def loadTestsFromModule(self, module): + return suite() -tests = [] -for arg in sys.argv[1:]: - if arg[0] not in "-/": - tests.append(arg) -tests = tests or test.regrtest.findtests(path, []) try: - # unittest based tests first - hopefully soon this will be the default! - if not sys.argv[1:]: - for t in "test_misc test_streams".split(): - m = __import__(t) - try: - unittest.main(m) - except SystemExit: - pass - test.regrtest.main(tests, path) + unittest.TestProgram(testLoader=CustomLoader())(argv=sys.argv) finally: from xpcom import _xpcom _xpcom.NS_ShutdownXPCOM() # To get leak stats and otherwise ensure life is good. + ni = _xpcom._GetInterfaceCount() + ng = _xpcom._GetGatewayCount() + if ni or ng: + # The old 'regrtest' that was not based purely on unittest did not + # do this check at the end - it relied on each module doing it itself. + # Thus, these leaks are not new, just newly noticed :) Likely to be + # something silly like module globals. + if ni == 6 and ng == 1: + print "Sadly, there are 6/1 leaks, but these appear normal and benign" + else: + print "********* WARNING - Leaving with %d/%d objects alive" % (ni,ng) + else: + print "yay! Our leaks have all vanished!" diff --git a/mozilla/extensions/python/xpcom/test/test_com_exceptions.py b/mozilla/extensions/python/xpcom/test/test_com_exceptions.py index 732e9821ef0..7813bf980db 100644 --- a/mozilla/extensions/python/xpcom/test/test_com_exceptions.py +++ b/mozilla/extensions/python/xpcom/test/test_com_exceptions.py @@ -36,8 +36,12 @@ # Test pyxpcom exception. -from xpcom import components, nsError, ServerException, COMException +from xpcom import components, nsError, ServerException, COMException, logger from xpcom.server import WrapObject +from pyxpcom_test_tools import testmain + +import unittest +import logging class PythonFailingComponent: # Re-use the test interface for this test. @@ -75,29 +79,46 @@ class PythonFailingComponent: # Report of a crash in this case - test it! raise ServerException, "A bad exception param" -def _testit(expected_errno, func, *args): - try: - apply(func, args) - except COMException, what: - if what.errno != expected_errno: - raise +class TestHandler(logging.Handler): + def __init__(self, level=logging.ERROR): # only counting error records + logging.Handler.__init__(self, level) + self.records = [] + + def reset(self): + self.records = [] -def test(): - # For the benefit of the test suite, we print some reassuring messages. - import sys - sys.__stderr__.write("***** NOTE: Three tracebacks below this is normal\n") - ob = WrapObject( PythonFailingComponent(), components.interfaces.nsIPythonTestInterfaceExtra) - _testit(nsError.NS_ERROR_FAILURE, ob.do_boolean, 0, 0) - _testit(nsError.NS_ERROR_NOT_IMPLEMENTED, ob.do_octet, 0, 0) - _testit(nsError.NS_ERROR_FAILURE, ob.do_short, 0, 0) - _testit(nsError.NS_ERROR_FAILURE, ob.do_unsigned_short, 0, 0) - _testit(nsError.NS_ERROR_FAILURE, ob.do_long, 0, 0) - _testit(nsError.NS_ERROR_NOT_IMPLEMENTED, ob.do_unsigned_long, 0, 0) - _testit(nsError.NS_ERROR_NOT_IMPLEMENTED, ob.do_long_long, 0, 0) - _testit(nsError.NS_ERROR_FAILURE, ob.do_unsigned_long_long, 0, 0) - print "The xpcom exception tests passed" - # For the benefit of the test suite, some more reassuring messages. - sys.__stderr__.write("***** NOTE: Three tracebacks printed above this is normal\n") - sys.__stderr__.write("***** It is testing the Python XPCOM Exception semantics\n") + def handle(self, record): + self.records.append(record) -test() \ No newline at end of file +class ExceptionTests(unittest.TestCase): + + def _testit(self, expected_errno, num_tracebacks, func, *args): + + # Screw with the logger + old_handlers = logger.handlers + test_handler = TestHandler() + logger.handlers = [test_handler] + + try: + try: + apply(func, args) + except COMException, what: + if what.errno != expected_errno: + raise + finally: + logger.handlers = old_handlers + self.failUnlessEqual(num_tracebacks, len(test_handler.records)) + + def testEmAll(self): + ob = WrapObject( PythonFailingComponent(), components.interfaces.nsIPythonTestInterfaceExtra) + self._testit(nsError.NS_ERROR_FAILURE, 0, ob.do_boolean, 0, 0) + self._testit(nsError.NS_ERROR_NOT_IMPLEMENTED, 0, ob.do_octet, 0, 0) + self._testit(nsError.NS_ERROR_FAILURE, 1, ob.do_short, 0, 0) + self._testit(nsError.NS_ERROR_FAILURE, 1, ob.do_unsigned_short, 0, 0) + self._testit(nsError.NS_ERROR_FAILURE, 0, ob.do_long, 0, 0) + self._testit(nsError.NS_ERROR_NOT_IMPLEMENTED, 0, ob.do_unsigned_long, 0, 0) + self._testit(nsError.NS_ERROR_NOT_IMPLEMENTED, 0, ob.do_long_long, 0, 0) + self._testit(nsError.NS_ERROR_FAILURE, 1, ob.do_unsigned_long_long, 0, 0) + +if __name__=='__main__': + testmain() diff --git a/mozilla/extensions/python/xpcom/test/test_comfile.py b/mozilla/extensions/python/xpcom/test/test_comfile.py index 222e8734e9f..9ffebe3770f 100644 --- a/mozilla/extensions/python/xpcom/test/test_comfile.py +++ b/mozilla/extensions/python/xpcom/test/test_comfile.py @@ -36,6 +36,14 @@ # ***** END LICENSE BLOCK ***** """Test the xpcom.file module.""" -# Called "test_comfile" as Python has a standard test called test_file :-( +from pyxpcom_test_tools import suite_from_functions, testmain + import xpcom.file -xpcom.file._TestAll() + +# Make this test run under our std test suite +def suite(): + return suite_from_functions(xpcom.file._TestAll) + +if __name__=='__main__': + testmain() + diff --git a/mozilla/extensions/python/xpcom/test/test_component/py_test_component.idl b/mozilla/extensions/python/xpcom/test/test_component/py_test_component.idl index c10c4b8c09c..ee682f7bce6 100644 --- a/mozilla/extensions/python/xpcom/test/test_component/py_test_component.idl +++ b/mozilla/extensions/python/xpcom/test/test_component/py_test_component.idl @@ -212,6 +212,7 @@ interface nsIPythonTestInterfaceExtra : nsIPythonTestInterface void AppendArray(inout PRUint32 count, [array, size_is(count)]in PRInt32 array1, [array, size_is(count)]inout PRInt32 array2); void AppendVariant(in nsIVariant variant, inout nsIVariant result); nsIVariant CopyVariant(in nsIVariant variant); + nsIVariant SumVariants(in PRUint32 incount, [array, size_is(incount)]in nsIVariant variants); }; // DOM String support is a "recent" (01/2001) addition to XPCOM. These test diff --git a/mozilla/extensions/python/xpcom/test/test_component/py_test_component.py b/mozilla/extensions/python/xpcom/test/test_component/py_test_component.py index 2869e1ae5ab..1b48a06179b 100644 --- a/mozilla/extensions/python/xpcom/test/test_component/py_test_component.py +++ b/mozilla/extensions/python/xpcom/test/test_component/py_test_component.py @@ -365,6 +365,14 @@ class PythonTestComponent: def CopyVariant(self, invar): return invar + def SumVariants(self, variants): + if len(variants) == 0: + return None + result = variants[0] + for v in variants[1:]: + result += v + return result + # Some tests for the "new" (Feb-2001) DOMString type. def GetDOMStringResult( self, length ): # Result: DOMString & diff --git a/mozilla/extensions/python/xpcom/test/test_components.py b/mozilla/extensions/python/xpcom/test/test_components.py index 0efd1ba8cb6..f1483c60ec2 100644 --- a/mozilla/extensions/python/xpcom/test/test_components.py +++ b/mozilla/extensions/python/xpcom/test/test_components.py @@ -39,6 +39,7 @@ """ import xpcom.components +from pyxpcom_test_tools import suite_from_functions, testmain if not __debug__: raise RuntimeError, "This test uses assert, so must be run in debug mode" @@ -63,9 +64,7 @@ def test_interfaces(): assert len(xpcom.components.interfaces.keys()) == len(xpcom.components.interfaces.values()) == \ len(xpcom.components.interfaces.items()) == len(xpcom.components.interfaces) == \ num_fetched, "The collection lengths were wrong" - if num_nsisupports != 1: - print "Didn't find exactly 1 nsiSupports!" - print "The interfaces object appeared to work!" + assert num_nsisupports == 1, "Didn't find exactly 1 nsiSupports!" def test_classes(): # Need a well-known contractID here? @@ -81,8 +80,7 @@ def test_classes(): for name, klass in xpcom.components.classes.items(): num_fetched = num_fetched + 1 if name == prog_id: - if klass.clsid != clsid: - print "Eeek - didn't get the correct IID - got", klass.clsid + assert klass.clsid == clsid, "Eeek - didn't get the correct IID - got %s" %klass.clsid num_mine = num_mine + 1 # xpcom appears to add charset info to the contractid!? @@ -98,15 +96,14 @@ def test_classes(): raise RuntimeError, "Didn't get any classes!!!" if num_mine != 1: raise RuntimeError, "Didn't find exactly 1 of my contractid! (%d)" % (num_mine,) - print "The classes object appeared to work!" def test_id(): id = xpcom.components.ID(str(xpcom._xpcom.IID_nsISupports)) assert id == xpcom._xpcom.IID_nsISupports - print "The ID function appeared to work!" +# Make this test run under our std test suite +def suite(): + return suite_from_functions(test_interfaces, test_classes, test_id) -# regrtest doesn't like if __name__=='__main__' blocks - it fails when running as a test! -test_interfaces() -test_classes() -test_id() +if __name__=='__main__': + testmain() diff --git a/mozilla/extensions/python/xpcom/test/test_isupports_primitives.py b/mozilla/extensions/python/xpcom/test/test_isupports_primitives.py index 321dd0eaf6c..76c5a52caae 100644 --- a/mozilla/extensions/python/xpcom/test/test_isupports_primitives.py +++ b/mozilla/extensions/python/xpcom/test/test_isupports_primitives.py @@ -41,10 +41,13 @@ # only if our class doesn't provide explicit support. from xpcom import components +from xpcom import primitives +import xpcom.server, xpcom.client +from pyxpcom_test_tools import testmain +import unittest class NoSupportsString: _com_interfaces_ = [components.interfaces.nsISupports] - pass class ImplicitSupportsString: _com_interfaces_ = [components.interfaces.nsISupports] @@ -52,13 +55,36 @@ class ImplicitSupportsString: return "" class ExplicitSupportsString: - _com_interfaces_ = [components.interfaces.nsISupports, components.interfaces.nsISupportsCString] + _com_interfaces_ = [components.interfaces.nsISupportsPrimitive, + components.interfaces.nsISupportsCString] + type = components.interfaces.nsISupportsPrimitive.TYPE_CSTRING + test_data = "" # __str__ will be ignored by XPCOM, as we have _explicit_ support. def __str__(self): return "" - # This is the one that will be used. + # These are the ones that will be used. + def get_data(self): + return self.test_data def toString(self): - return "" + return self.test_data + +class ImplicitSupportsUnicode: + _com_interfaces_ = [components.interfaces.nsISupports] + test_data = u"Copyright \xa9 the initial developer" + def __unicode__(self): + # An extended character in unicode tests can't hurt! + return self.test_data + +class ExplicitSupportsUnicode: + _com_interfaces_ = [components.interfaces.nsISupportsPrimitive, + components.interfaces.nsISupportsString] + type = components.interfaces.nsISupportsPrimitive.TYPE_STRING + # __unicode__ will be ignored by XPCOM, as we have _explicit_ support. + test_data = u"Copyright \xa9 the initial developer" + def __unicode__(self): + return self.test_data + def get_data(self): + return self.test_data class ImplicitSupportsInt: _com_interfaces_ = [components.interfaces.nsISupports] @@ -66,7 +92,9 @@ class ImplicitSupportsInt: return 99 class ExplicitSupportsInt: - _com_interfaces_ = [components.interfaces.nsISupportsPRInt32] + _com_interfaces_ = [components.interfaces.nsISupportsPrimitive, + components.interfaces.nsISupportsPRInt32] + type = components.interfaces.nsISupportsPrimitive.TYPE_PRINT32 def get_data(self): return 99 @@ -76,12 +104,16 @@ class ImplicitSupportsLong: return 99L class ExplicitSupportsLong: - _com_interfaces_ = [components.interfaces.nsISupportsPRInt64] + _com_interfaces_ = [components.interfaces.nsISupportsPrimitive, + components.interfaces.nsISupportsPRInt64] + type = components.interfaces.nsISupportsPrimitive.TYPE_PRINT64 def get_data(self): return 99 class ExplicitSupportsFloat: - _com_interfaces_ = [components.interfaces.nsISupportsDouble] + _com_interfaces_ = [components.interfaces.nsISupportsPrimitive, + components.interfaces.nsISupportsDouble] + type = components.interfaces.nsISupportsPrimitive.TYPE_DOUBLE def get_data(self): return 99.99 @@ -90,61 +122,86 @@ class ImplicitSupportsFloat: def __float__(self): return 99.99 -def test(): - import xpcom.server, xpcom.client - ob = xpcom.server.WrapObject( NoSupportsString(), components.interfaces.nsISupports) - if not str(ob).startswith("") - ob = xpcom.server.WrapObject( ExplicitSupportsString(), components.interfaces.nsISupports) - if str(ob) != "": - raise RuntimeError, "Wrong str() value: %s" % (ob,) + def testExplicitString(self): + ob = xpcom.server.WrapObject( ExplicitSupportsString(), components.interfaces.nsISupports) + self.failUnlessEqual(str(ob), "") - # Try our conversions. - try: - int(ob) - raise RuntimeError, "Expected to get a ValueError converting this COM object to an int" - except ValueError: - pass - ob = xpcom.server.WrapObject( ExplicitSupportsInt(), components.interfaces.nsISupports) - if int(ob) != 99: - raise RuntimeError, "Bad value: %s" % (int(ob),) - if float(ob) != 99.0: - raise RuntimeError, "Bad value: %s" % (float(ob),) + def testImplicitUnicode(self): + ob = xpcom.server.WrapObject( ImplicitSupportsUnicode(), components.interfaces.nsISupports) + self.failUnlessEqual(unicode(ob), ImplicitSupportsUnicode.test_data) - ob = xpcom.server.WrapObject( ImplicitSupportsInt(), components.interfaces.nsISupports) - if int(ob) != 99: - raise RuntimeError, "Bad value: %s" % (int(ob),) - if float(ob) != 99.0: - raise RuntimeError, "Bad value: %s" % (float(ob),) + def testExplicitUnicode(self): + ob = xpcom.server.WrapObject( ExplicitSupportsUnicode(), components.interfaces.nsISupports) + self.failUnlessEqual(unicode(ob), ExplicitSupportsUnicode.test_data) - ob = xpcom.server.WrapObject( ExplicitSupportsLong(), components.interfaces.nsISupports) - if long(ob) != 99 or not repr(long(ob)).endswith("L"): - raise RuntimeError, "Bad value: %s" % (repr(long(ob)),) - if float(ob) != 99.0: - raise RuntimeError, "Bad value: %s" % (float(ob),) + def testConvertInt(self): + # Try our conversions. + ob = xpcom.server.WrapObject( ExplicitSupportsString(), components.interfaces.nsISupports) + self.failUnlessRaises( ValueError, int, ob) - ob = xpcom.server.WrapObject( ImplicitSupportsLong(), components.interfaces.nsISupports) - if long(ob) != 99 or not repr(long(ob)).endswith("L"): - raise RuntimeError, "Bad value: %s" % (repr(long(ob)),) - if float(ob) != 99.0: - raise RuntimeError, "Bad value: %s" % (float(ob),) + def testExplicitInt(self): + ob = xpcom.server.WrapObject( ExplicitSupportsInt(), components.interfaces.nsISupports) + self.failUnlessAlmostEqual(float(ob), 99.0) + self.failUnlessEqual(int(ob), 99) - ob = xpcom.server.WrapObject( ExplicitSupportsFloat(), components.interfaces.nsISupports) - if float(ob) != 99.99: - raise RuntimeError, "Bad value: %s" % (float(ob),) - if int(ob) != 99: - raise RuntimeError, "Bad value: %s" % (int(ob),) + def testImplicitInt(self): + ob = xpcom.server.WrapObject( ImplicitSupportsInt(), components.interfaces.nsISupports) + self.failUnlessAlmostEqual(float(ob), 99.0) + self.failUnlessEqual(int(ob), 99) - ob = xpcom.server.WrapObject( ImplicitSupportsFloat(), components.interfaces.nsISupports) - if float(ob) != 99.99: - raise RuntimeError, "Bad value: %s" % (float(ob),) - if int(ob) != 99: - raise RuntimeError, "Bad value: %s" % (int(ob),) + def testExplicitLong(self): + ob = xpcom.server.WrapObject( ExplicitSupportsLong(), components.interfaces.nsISupports) + if long(ob) != 99 or not repr(long(ob)).endswith("L"): + raise RuntimeError, "Bad value: %s" % (repr(long(ob)),) + self.failUnlessAlmostEqual(float(ob), 99.0) - print "The nsISupports primitive interface tests appeared to work" -test() + def testImplicitLong(self): + ob = xpcom.server.WrapObject( ImplicitSupportsLong(), components.interfaces.nsISupports) + if long(ob) != 99 or not repr(long(ob)).endswith("L"): + raise RuntimeError, "Bad value: %s" % (repr(long(ob)),) + self.failUnlessAlmostEqual(float(ob), 99.0) + + def testExplicitFloat(self): + ob = xpcom.server.WrapObject( ExplicitSupportsFloat(), components.interfaces.nsISupports) + self.failUnlessEqual(float(ob), 99.99) + self.failUnlessEqual(int(ob), 99) + + def testImplicitFloat(self): + ob = xpcom.server.WrapObject( ImplicitSupportsFloat(), components.interfaces.nsISupports) + self.failUnlessEqual(float(ob), 99.99) + self.failUnlessEqual(int(ob), 99) + +class PrimitivesModuleTestCase(unittest.TestCase): + def testExplicitString(self): + ob = xpcom.server.WrapObject( ExplicitSupportsString(), components.interfaces.nsISupports) + self.failUnlessEqual(primitives.GetPrimitive(ob), "") + + def testExplicitUnicode(self): + ob = xpcom.server.WrapObject( ExplicitSupportsUnicode(), components.interfaces.nsISupports) + self.failUnlessEqual(primitives.GetPrimitive(ob), ExplicitSupportsUnicode.test_data) + self.failUnlessEqual(type(primitives.GetPrimitive(ob)), unicode) + + def testExplicitInt(self): + ob = xpcom.server.WrapObject( ExplicitSupportsInt(), components.interfaces.nsISupports) + self.failUnlessEqual(primitives.GetPrimitive(ob), 99) + + def testExplicitLong(self): + ob = xpcom.server.WrapObject( ExplicitSupportsLong(), components.interfaces.nsISupports) + self.failUnlessEqual(primitives.GetPrimitive(ob), 99) + + def testExplicitFloat(self): + ob = xpcom.server.WrapObject( ExplicitSupportsFloat(), components.interfaces.nsISupports) + self.failUnlessEqual(primitives.GetPrimitive(ob), 99.99) + +if __name__=='__main__': + testmain() diff --git a/mozilla/extensions/python/xpcom/test/test_misc.py b/mozilla/extensions/python/xpcom/test/test_misc.py index 808e7583f05..6cf1b74e0e4 100644 --- a/mozilla/extensions/python/xpcom/test/test_misc.py +++ b/mozilla/extensions/python/xpcom/test/test_misc.py @@ -41,6 +41,7 @@ import xpcom.server import xpcom._xpcom import xpcom.components import string +from pyxpcom_test_tools import testmain import unittest @@ -223,10 +224,13 @@ class TestUnwrap(unittest.TestCase): return self.failUnlessRaises(ValueError, xpcom.server.UnwrapObject, ob) +class TestNonScriptable(unittest.TestCase): + def testQI(self): + # Test we can QI for a non-scriptable interface. We can't *do* much + # with it (other than pass it on), but we should still work and get + # a basic wrapper. + ob = xpcom.components.classes["Python.TestComponent"].createInstance() + ob = ob.queryInterface(xpcom._xpcom.IID_nsIInternalPython) + if __name__=='__main__': - unittest.main() - xpcom._xpcom.NS_ShutdownXPCOM() - ni = xpcom._xpcom._GetInterfaceCount() - ng = xpcom._xpcom._GetGatewayCount() - if ni or ng: - print "********* WARNING - Leaving with %d/%d objects alive" % (ni,ng) + testmain() diff --git a/mozilla/extensions/python/xpcom/test/test_streams.py b/mozilla/extensions/python/xpcom/test/test_streams.py index ac1bc4d8fa7..96ac6559d91 100644 --- a/mozilla/extensions/python/xpcom/test/test_streams.py +++ b/mozilla/extensions/python/xpcom/test/test_streams.py @@ -39,6 +39,7 @@ import xpcom from xpcom import _xpcom, components, COMException, ServerException, nsError from StringIO import StringIO import unittest +from pyxpcom_test_tools import testmain test_data = "abcdefeghijklmnopqrstuvwxyz" @@ -92,4 +93,4 @@ class StreamTests(unittest.TestCase): # stream observer mechanism has changed - we should test that. if __name__=='__main__': - unittest.main() + testmain() diff --git a/mozilla/extensions/python/xpcom/test/test_test_component.js b/mozilla/extensions/python/xpcom/test/test_test_component.js index ec628be541f..db8b006d54d 100644 --- a/mozilla/extensions/python/xpcom/test/test_test_component.js +++ b/mozilla/extensions/python/xpcom/test/test_test_component.js @@ -130,5 +130,9 @@ v2[3] = 6; if (c.SumArrays(v.length, v, v2) != 21) throw("Could not sum an array of integers!"); +var count = new Object(); +count.value = 0; +var out = []; +c.DoubleStringArray(count, out); print("javascript successfully tested the Python test component."); diff --git a/mozilla/extensions/python/xpcom/test/test_test_component.py b/mozilla/extensions/python/xpcom/test/test_test_component.py index 7ef8759e1e7..0066e285c8f 100644 --- a/mozilla/extensions/python/xpcom/test/test_test_component.py +++ b/mozilla/extensions/python/xpcom/test/test_test_component.py @@ -40,6 +40,8 @@ import xpcom.components import xpcom._xpcom import xpcom.nsError +MakeVariant = xpcom._xpcom.MakeVariant + try: import gc except ImportError: @@ -406,11 +408,19 @@ def test_derived_interface(c, test_flat = 0): test_method(c.CopyVariant, (("foo","bar"),), ["foo", "bar"]) test_method(c.CopyVariant, ((component_iid,component_iid),), [component_iid,component_iid]) test_method(c.CopyVariant, ((c,c),), [c,c]) + sup = c.queryInterface(xpcom.components.interfaces.nsISupports)._comobj_ + test_method(c.CopyVariant, ((sup, sup),), [sup,sup]) test_method(c.AppendVariant, (1,2), 3) test_method(c.AppendVariant, ((1,2),(3,4)), 10) test_method(c.AppendVariant, ("bar", "foo"), "foobar") test_method(c.AppendVariant, (None, None), None) + test_method(c.SumVariants, ([],), None) + # Array's dont expose their interface, so we are unable to auto-wrap + # variant arrays, as they aren't aware if the IID of the array + test_method(c.SumVariants, ([MakeVariant(1),MakeVariant(2),MakeVariant(3)],), 6) + test_method(c.SumVariants, ([MakeVariant('foo'), MakeVariant('bar')],), 'foobar') + if not test_flat: c = c.queryInterface(xpcom.components.interfaces.nsIPythonTestInterfaceDOMStrings) # NULL DOM strings don't work yet. @@ -491,29 +501,20 @@ def test_from_js(): raise RuntimeError, "Can not find '%s'" % (fname,) # Note we _dont_ pump the test output out, as debug "xpcshell" spews # extra debug info that will cause our output comparison to fail. - try: - data = os.popen('xpcshell "' + fname + '"').readlines() - good = 0 - for line in data: - if line.strip() == "javascript successfully tested the Python test component.": - good = 1 - if good: - print "Javascript could successfully use the Python test component." - else: - print "** The javascript test appeared to fail! Test output follows **" - print "".join(data) - print "** End of javascript test output **" - - except os.error, why: - print "Error executing the javascript test program:", why - + data = os.popen('xpcshell "' + fname + '"').readlines() + good = 0 + for line in data: + if line.strip() == "javascript successfully tested the Python test component.": + good = 1 + if not good: + print "** The javascript test appeared to fail! Test output follows **" + print "".join(data) + print "** End of javascript test output **" + raise RuntimeError, "test failed" def doit(num_loops = -1): - if "-v" in sys.argv: # Hack the verbose flag for the server - xpcom.verbose = 1 # Do the test lots of times - can help shake-out ref-count bugs. - print "Testing the Python.TestComponent component" - if num_loops == -1: num_loops = 10 + if num_loops == -1: num_loops = 5 for i in xrange(num_loops): test_all() @@ -535,38 +536,40 @@ def doit(num_loops = -1): # Sometimes we get spurious counts off by 1 or 2. # This can't indicate a real leak, as we have looped # more than twice! - if abs(lost)>2: + if abs(lost)>3: # 2 or 3 :) print "*** Lost %d references" % (lost,) # sleep to allow the OS to recover time.sleep(1) mem_lost = getmemusage() - mem_usage # working set size is fickle, and when we were leaking strings, this test - # would report a leak of 100MB. So we allow a 2MB buffer - but even this + # would report a leak of 100MB. So we allow a 3MB buffer - but even this # may still occasionally report spurious warnings. If you are really # worried, bump the counter to a huge value, and if there is a leak it will # show. - if mem_lost > 2000000: + if mem_lost > 3000000: print "*** Lost %.6f MB of memory" % (mem_lost/1000000.0,) - if num_errors: - print "There were", num_errors, "errors testing the Python component :-(" - else: - print "The Python test component worked!" + assert num_errors==0, "There were %d errors testing the Python component" % (num_errors,) -# regrtest doesn't like if __name__=='__main__' blocks - it fails when running as a test! -num_iters = -1 -if __name__=='__main__' and len(sys.argv) > 1: - num_iters = int(sys.argv[1]) - -doit(num_iters) -test_from_js() +def suite(): + from pyxpcom_test_tools import suite_from_functions + return suite_from_functions(doit, test_from_js) if __name__=='__main__': - # But we can only do this if _not_ testing - otherwise we - # screw up any tests that want to run later. + num_iters = 10 # times times is *lots* - we do a fair bit of work! + if __name__=='__main__' and len(sys.argv) > 1: + num_iters = int(sys.argv[1]) + + if "-v" in sys.argv: # Hack the verbose flag for the server + xpcom.verbose = 1 + + print "Testing the Python.TestComponent component" + doit(num_iters) + print "The Python test component worked." + test_from_js() + print "JS successfully used our Python test component." xpcom._xpcom.NS_ShutdownXPCOM() ni = xpcom._xpcom._GetInterfaceCount() ng = xpcom._xpcom._GetGatewayCount() - if ni or ng: - print "********* WARNING - Leaving with %d/%d objects alive" % (ni,ng) + print "test completed with %d interfaces and %d objects." % (ni, ng) diff --git a/mozilla/extensions/python/xpcom/test/test_weakreferences.py b/mozilla/extensions/python/xpcom/test/test_weakreferences.py index 88bd3a7927e..9bfb3fbc4f9 100644 --- a/mozilla/extensions/python/xpcom/test/test_weakreferences.py +++ b/mozilla/extensions/python/xpcom/test/test_weakreferences.py @@ -38,6 +38,7 @@ # test_weakreferences.py - Test our weak reference implementation. from xpcom import components, _xpcom import xpcom.server, xpcom.client +from pyxpcom_test_tools import suite_from_functions, testmain try: from sys import gettotalrefcount @@ -104,13 +105,10 @@ def test_refcount(num_loops=-1): # more than twice! if abs(lost)>2: print "*** Lost %d references" % (lost,) - -test_refcount() -print "Weak-reference tests appear to have worked!" +# Make this test run under our std test suite +def suite(): + return suite_from_functions(test_refcount) + if __name__=='__main__': - _xpcom.NS_ShutdownXPCOM() - ni = xpcom._xpcom._GetInterfaceCount() - ng = xpcom._xpcom._GetGatewayCount() - if ni or ng: - print "********* WARNING - Leaving with %d/%d objects alive" % (ni,ng) + testmain() diff --git a/mozilla/extensions/python/xpcom/tools/regxpcom.py b/mozilla/extensions/python/xpcom/tools/regxpcom.py index c5c70a1a93f..2b7ea6a4e11 100644 --- a/mozilla/extensions/python/xpcom/tools/regxpcom.py +++ b/mozilla/extensions/python/xpcom/tools/regxpcom.py @@ -36,32 +36,33 @@ # ***** END LICENSE BLOCK ***** # regxpcom.py - basically the standard regxpcom.cpp ported to Python. +# In general, you should use regxpcom.exe instead of this. from xpcom import components, _xpcom +from xpcom.client import Component import sys import os +registrar = Component(_xpcom.GetComponentRegistrar(), + components.interfaces.nsIComponentRegistrar) + def ProcessArgs(args): + unregister = 0 for arg in args: + spec = components.classes['@mozilla.org/file/local;1'].createInstance() + spec = spec.QueryInterface(components.interfaces.nsILocalFile) + spec.initWithPath(os.path.abspath(arg)) if arg == "-u": - unregister = 1 + registrar.autoUnregister(spec) + print "Successfully unregistered", spec.path else: - spec = components.classes['@mozilla.org/file/local;1'].createInstance() - spec = spec.QueryInterface(components.interfaces.nsILocalFile) - spec.initWithPath(os.path.abspath(arg)) - if unregister: - components.manager.autoUnregisterComponent( components.manager.NS_Startup, spec) - print "Successfully unregistered", spec.path - else: - components.manager.autoRegisterComponent( components.manager.NS_Startup, spec) - print "Successfully registered", spec.path - unregister = 0 + registrar.autoRegister(spec) + print "Successfully registered", spec.path -import xpcom if len(sys.argv) < 2: - components.manager.autoRegister( components.manager.NS_Startup, None) + registrar.autoRegister( None) else: ProcessArgs(sys.argv[1:]) -_xpcom.NS_ShutdownXPCOM() \ No newline at end of file +#_xpcom.NS_ShutdownXPCOM() diff --git a/mozilla/extensions/python/xpcom/xpt.py b/mozilla/extensions/python/xpcom/xpt.py index 1ffbd18771b..d0eafb4d21e 100644 --- a/mozilla/extensions/python/xpcom/xpt.py +++ b/mozilla/extensions/python/xpcom/xpt.py @@ -76,15 +76,10 @@ from xpcom_consts import * class Interface: def __init__(self, iid): iim = xpcom._xpcom.XPTI_GetInterfaceInfoManager() - try: - if hasattr(iid, "upper"): # Is it a stringy thing. - item = iim.GetInfoForName(iid) - else: - item = iim.GetInfoForIID(iid) - except xpcom.COMException: - name = getattr(iid, "name", str(iid)) - print "Failed to get info for IID '%s'" % (name,) - raise + if hasattr(iid, "upper"): # Is it a stringy thing. + item = iim.GetInfoForName(iid) + else: + item = iim.GetInfoForIID(iid) self.interface_info = item self.namespace = "" # where does this come from? self.methods = Methods(item)