Skip to content
This repository

Implement additional error handling in util.import_object function #430

Merged
merged 3 commits into from about 1 year ago

2 participants

Alexey Kachayev Ben Darnell
Alexey Kachayev

Actually tornado.util.import_object can raise several different exceptions (ValueError, IndexError, AttributeError, ImportError) in different cases. This is not so convenient to handle all of them. Of course, there are two ways to improve such behavior:

  1. Standardize exceptions and raise for ex. ImportError or ValueError.

  2. Return None in case of failed operation.

According to usage of this function in framework:

https://github.com/facebook/tornado/blob/master/tornado/httpclient.py#L196

I implemented second approach. DocTest for function is updated so you can find all cases there.

Ben Darnell
Collaborator

Returning None instead of raising an exception is a semantic change that needs to be matched by a check on the return value at every call site. I think that in general it's better for import_object to raise an exception than return None. It would be nice if it raised a consistent exception, but not necessary (and your change doesn't guarantee None on a failed import; it could still raise SyntaxError or any other error produced by top-level code in the imported module).

Alexey Kachayev

So, as far as first approach is preferable, I'll update this branch ASAP (actually I have both implementations).

P.S. Regarding to SyntaxError, I don't see problems here cause SyntaxError can be raised anywhere and we can't protect against it (and we even should not do this).

Alexey Kachayev

Done. Now we will get standard ImportError for "missing" modules.

Ben Darnell bdarnell merged commit 54f56d4 into from April 14, 2013
Ben Darnell bdarnell closed this April 14, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.

Showing 1 changed file with 21 additions and 1 deletion. Show diff stats Hide diff stats

  1. 22  tornado/util.py
22  tornado/util.py
... ...
@@ -1,5 +1,7 @@
1 1
 """Miscellaneous utility functions."""
2 2
 
  3
+import sys
  4
+
3 5
 class ObjectDict(dict):
4 6
     """Makes a dictionary behave like an object."""
5 7
     def __getattr__(self, name):
@@ -15,6 +17,7 @@ def __setattr__(self, name, value):
15 17
 def import_object(name):
16 18
     """Imports an object by name.
17 19
 
  20
+    import_object('x') is equivalent to 'import x'.
18 21
     import_object('x.y.z') is equivalent to 'from x.y import z'.
19 22
 
20 23
     >>> import tornado.escape
@@ -22,10 +25,27 @@ def import_object(name):
22 25
     True
23 26
     >>> import_object('tornado.escape.utf8') is tornado.escape.utf8
24 27
     True
  28
+    >>> import_object('tornado') is tornado
  29
+    True
  30
+    >>> import_object('missing_module')
  31
+    Traceback (most recent call last):
  32
+        ...
  33
+    ImportError: No module named missing_module
  34
+    >>> import_object('tornado.missing_module')
  35
+    Traceback (most recent call last):
  36
+        ...
  37
+    ImportError: No module named missing_module
25 38
     """
  39
+    if name.count('.') == 0:
  40
+        return __import__(name, None, None)
  41
+
26 42
     parts = name.split('.')
27 43
     obj = __import__('.'.join(parts[:-1]), None, None, [parts[-1]], 0)
28  
-    return getattr(obj, parts[-1])
  44
+    try:
  45
+        return getattr(obj, parts[-1])
  46
+    except AttributeError:
  47
+        exc_info = sys.exc_info()
  48
+        raise ImportError, "No module named %s" % parts[-1], exc_info[2] 
29 49
 
30 50
 # Fake byte literal support:  In python 2.6+, you can say b"foo" to get
31 51
 # a byte literal (str in 2.x, bytes in 3.x).  There's no way to do this
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.