diff options
author | David Bolen <db3l.net@gmail.com> | 2013-07-29 12:44:26 +0200 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2013-07-29 12:49:02 +0200 |
commit | acc7484b0fd1d5df2a709399bcdf03ec81943e71 (patch) | |
tree | 67dc19b25fed2c538fea3d2db9909a9a258bd4fa | |
parent | b9b452a570bea90f27082e5b70aedf9b8f9d421e (diff) |
fdo#66025: Improve accuracy of ImportError traceback and message
The ImportError raised on an import failure with the uno module loaded
now includes a complete traceback and the original Python exception
message text, combined with the most relevant (nearest to failure if
imports are nested) uno lookup that also failed.
Cherry-picked from 948b6ea02ea9de7fb4e1e2baf95ecae3ba1cd54e plus previous
patches leading up to that, 7fd81244c21ad54a8b9766902fd7c34e8055b165 "fdo#66025:
Improve ImportError raised from _uno_import,"
329125abb63061214897e4f215d41cfa4b13b4b0 "fdo#66025: Minor clean-up of previous
patch," and fbe28de6fbfdce41544e4e93168d32661add8285 "fdo#66025: Simplify new
ImportError logic."
Change-Id: I8c22f22c2d96bdd7fb99a87273ba574e22a86923
Signed-off-by: Stephan Bergmann <sbergman@redhat.com>
(cherry picked from commit 52a533cc31f630ad482fe0fde8d925b459c787bf)
-rw-r--r-- | pyuno/source/module/uno.py | 50 |
1 files changed, 41 insertions, 9 deletions
diff --git a/pyuno/source/module/uno.py b/pyuno/source/module/uno.py index 86011f3b4c97..d99884a64d68 100644 --- a/pyuno/source/module/uno.py +++ b/pyuno/source/module/uno.py @@ -263,11 +263,14 @@ def _uno_import( name, *optargs, **kwargs ): try: # print "optargs = " + repr(optargs) return _g_delegatee( name, *optargs, **kwargs ) - except ImportError: + except ImportError as e: # process optargs globals, locals, fromlist = list(optargs)[:3] + [kwargs.get('globals',{}), kwargs.get('locals',{}), kwargs.get('fromlist',[])][len(optargs):] - if not fromlist: + # from import form only, but skip if an uno lookup has already failed + if not fromlist or hasattr(e, '_uno_import_failed'): raise + # hang onto exception for possible use on subsequent uno lookup failure + py_import_exc = e modnames = name.split( "." ) mod = None d = sys.modules @@ -281,26 +284,55 @@ def _uno_import( name, *optargs, **kwargs ): RuntimeException = pyuno.getClass( "com.sun.star.uno.RuntimeException" ) for x in fromlist: if x not in d: + failed = False if x.startswith( "typeOf" ): try: d[x] = pyuno.getTypeByName( name + "." + x[6:len(x)] ) - except RuntimeException as e: - raise ImportError( "type " + name + "." + x[6:len(x)] +" is unknown" ) + except RuntimeException: + failed = True else: try: # check for structs, exceptions or interfaces d[x] = pyuno.getClass( name + "." + x ) - except RuntimeException as e: + except RuntimeException: # check for enums try: d[x] = Enum( name , x ) - except RuntimeException as e2: + except RuntimeException: # check for constants try: d[x] = getConstantByName( name + "." + x ) - except RuntimeException as e3: - # no known uno type ! - raise ImportError( "type "+ name + "." +x + " is unknown" ) + except RuntimeException: + failed = True + + if failed: + # We have an import failure, but cannot distinguish between + # uno and non-uno errors as uno lookups are attempted for all + # "from xxx import yyy" imports following a python failure. + # + # The traceback from the original python exception is kept to + # pinpoint the actual failing location, but in Python 3 the + # original message is most likely unhelpful for uno failures, + # as it will most commonly be a missing top level module, + # like 'com'. Our exception appends the uno lookup failure. + # This is more ambiguous, but it plus the traceback should be + # sufficient to identify a root cause for python or uno issues. + # + # Our exception is raised outside of the nested exception + # handlers above, to avoid Python 3 nested exception + # information for the RuntimeExceptions during lookups. + # + # Finally, a private attribute is used to prevent further + # processing if this failure was in a nested import. That + # keeps the exception relevant to the primary failure point, + # preventing us from re-processing our own import errors. + + uno_import_exc = ImportError( + "%s (or '%s.%s' is unknown)" % (py_import_exc, name, x) + ).with_traceback(py_import_exc.__traceback__) + uno_import_exc._uno_import_failed = True + raise uno_import_exc + return mod # private function, don't use |