From acc7484b0fd1d5df2a709399bcdf03ec81943e71 Mon Sep 17 00:00:00 2001 From: David Bolen Date: Mon, 29 Jul 2013 12:44:26 +0200 Subject: 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 (cherry picked from commit 52a533cc31f630ad482fe0fde8d925b459c787bf) --- pyuno/source/module/uno.py | 50 +++++++++++++++++++++++++++++++++++++--------- 1 file 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 -- cgit v1.2.3