Repository: numba/numba

Issue:
@jit result doesn't reflect original __doc__
When decorating a function with `@jit`, the original function's `__doc__` attribute (as well as other ones) isn't reflected. This breaks doctests attached as docstrings of jitted functions (i.e. the doctests are not run at all).



Discussion:
Hmm, apparently fixing this wouldn't be enough to make doctests work, since doctest relies on `inspect.isfunction` which we have no way of duck-typing around...
Still, it would probably be good to have the jitted function reflect some of the original function's metadata (using functools.update_wrapper ?).

I've reported an issue against the doctest module here: http://bugs.python.org/issue21740


Resolving patch:
diff --git a/numba/dispatcher.py b/numba/dispatcher.py
--- a/numba/dispatcher.py
+++ b/numba/dispatcher.py
@@ -2,6 +2,7 @@
 import inspect
 import contextlib
 import numpy
+import functools
 from numba.config import PYVERSION
 from numba import _dispatcher, compiler, utils
 from numba.typeconv.rules import default_type_manager
@@ -18,6 +19,16 @@ class Overloaded(_dispatcher.Dispatcher):
     __numba__ = "py_func"
 
     def __init__(self, py_func, locals={}, targetoptions={}):
+        """
+        Parameters
+        ----------
+        py_func: function object to be compiled
+        locals: dict, optional
+            Mapping of local variable names to Numba types.  Used to override
+            the types deduced by the type inference engine.
+        targetoptions: dict, optional
+            Target-specific config options.
+        """
         self.tm = default_type_manager
 
         argspec = inspect.getargspec(py_func)
@@ -26,12 +37,17 @@ def __init__(self, py_func, locals={}, targetoptions={}):
         super(Overloaded, self).__init__(self.tm.get_pointer(), argct)
 
         self.py_func = py_func
+        functools.update_wrapper(self, py_func)
+
+        # other parts of Numba assume the old Python 2 name for code object
         self.func_code = get_code_object(py_func)
+        # but newer python uses a different name
+        self.__code__ = self.func_code
+
         self.overloads = {}
 
         self.targetoptions = targetoptions
         self.locals = locals
-        self.doc = py_func.__doc__
         self._compiling = False
 
         self.targetdescr.typing_context.insert_overloaded(self)


Test patch:
diff --git a/numba/tests/test_func_interface.py b/numba/tests/test_func_interface.py
new file mode 100644
--- /dev/null
+++ b/numba/tests/test_func_interface.py
@@ -0,0 +1,44 @@
+from __future__ import print_function
+import numba.unittest_support as unittest
+from numba import jit
+
+
+class TestFuncInterface(unittest.TestCase):
+    def test_jit_function_docstring(self):
+
+        def add(x, y):
+            '''Return sum of two numbers'''
+            return x + y
+
+        c_add = jit(add)
+        self.assertEqual(c_add.__doc__, 'Return sum of two numbers')
+
+    def test_jit_function_name(self):
+
+        def add(x, y):
+            return x + y
+
+        c_add = jit(add)
+        self.assertEqual(c_add.__name__, 'add')
+
+    def test_jit_function_module(self):
+
+        def add(x, y):
+            return x + y
+
+        c_add = jit(add)
+        # Expected answer depends on how you run this test.
+        # Compare to python function instead.
+        self.assertEqual(c_add.__module__, add.__module__)
+
+    def test_jit_function_code_object(self):
+        def add(x, y):
+            return x + y
+
+        c_add = jit(add)
+        self.assertEqual(c_add.__code__, add.__code__)
+        self.assertEqual(c_add.func_code, add.__code__)
+
+
+if __name__ == '__main__':
+    unittest.main()