Author: Ronan Lamy <ronan.l...@gmail.com>
Branch: 
Changeset: r78631:89862db1c9f1
Date: 2015-07-21 19:38 +0100
http://bitbucket.org/pypy/pypy/changeset/89862db1c9f1/

Log:    merge branch 'numpy-docstrings'

diff --git a/pypy/module/micronumpy/__init__.py 
b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -2,7 +2,9 @@
 
 
 class MultiArrayModule(MixedModule):
-    appleveldefs = {'arange': 'app_numpy.arange'}
+    appleveldefs = {
+        'arange': 'app_numpy.arange',
+        'add_docstring': 'app_numpy.add_docstring'}
     interpleveldefs = {
         'ndarray': 'ndarray.W_NDimArray',
         'dtype': 'descriptor.W_Dtype',
@@ -29,6 +31,8 @@
         'set_string_function': 'appbridge.set_string_function',
         'typeinfo': 'descriptor.get_dtype_cache(space).w_typeinfo',
         'nditer': 'nditer.W_NDIter',
+
+        'set_docstring': 'support.descr_set_docstring',
     }
     for c in ['MAXDIMS', 'CLIP', 'WRAP', 'RAISE']:
         interpleveldefs[c] = 'space.wrap(constants.%s)' % c
diff --git a/pypy/module/micronumpy/app_numpy.py 
b/pypy/module/micronumpy/app_numpy.py
--- a/pypy/module/micronumpy/app_numpy.py
+++ b/pypy/module/micronumpy/app_numpy.py
@@ -3,6 +3,7 @@
 import math
 
 import _numpypy
+from _numpypy.multiarray import set_docstring
 
 def arange(start, stop=None, step=1, dtype=None):
     '''arange([start], stop[, step], dtype=None)
@@ -22,3 +23,13 @@
         arr[j] = i
         i += step
     return arr
+
+
+def add_docstring(obj, docstring):
+    old_doc = getattr(obj, '__doc__', None)
+    if old_doc is not None:
+        raise RuntimeError("%s already has a docstring" % obj)
+    try:
+        set_docstring(obj, docstring)
+    except:
+        raise TypeError("Cannot set a docstring for %s" % obj)
diff --git a/pypy/module/micronumpy/support.py 
b/pypy/module/micronumpy/support.py
--- a/pypy/module/micronumpy/support.py
+++ b/pypy/module/micronumpy/support.py
@@ -1,8 +1,12 @@
-from pypy.interpreter.error import OperationError, oefmt
 from rpython.rlib import jit
 from rpython.rlib.rarithmetic import ovfcheck
 from rpython.rtyper.lltypesystem import rffi, lltype
 
+from pypy.interpreter.error import OperationError, oefmt
+from pypy.interpreter.gateway import unwrap_spec, appdef
+from pypy.interpreter.typedef import GetSetProperty
+from pypy.objspace.std.typeobject import W_TypeObject
+from pypy.objspace.std.objspace import StdObjSpace
 
 def issequence_w(space, w_obj):
     from pypy.module.micronumpy.base import W_NDimArray
@@ -172,3 +176,27 @@
     elif req_order == 'A':
         return proto_order
 
+
+def descr_set_docstring(space, w_obj, w_docstring):
+    if not isinstance(space, StdObjSpace):
+        raise oefmt(space.w_NotImplementedError,
+                    "This only works with the real object space")
+    if isinstance(w_obj, W_TypeObject):
+        w_obj.w_doc = w_docstring
+        return
+    elif isinstance(w_obj, GetSetProperty):
+        if space.is_none(w_docstring):
+            doc = None
+        else:
+            doc = space.str_w(w_docstring)
+        w_obj.doc = doc
+        return
+    app_set_docstring(space, w_obj, w_docstring)
+
+app_set_docstring = appdef("""app_set_docstring_(obj, docstring):
+    import types
+    if isinstance(obj, types.MethodType):
+        obj.im_func.__doc__ = docstring
+    else:
+        obj.__doc__ = docstring
+""")
diff --git a/pypy/module/micronumpy/test/test_support_app.py 
b/pypy/module/micronumpy/test/test_support_app.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_support_app.py
@@ -0,0 +1,49 @@
+"""App-level tests for support.py"""
+import sys
+import py
+
+from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+from pypy.conftest import option
+
+class AppTestSupport(BaseNumpyAppTest):
+    def setup_class(cls):
+        if option.runappdirect and '__pypy__' not in sys.builtin_module_names:
+            py.test.skip("pypy only test")
+        BaseNumpyAppTest.setup_class.im_func(cls)
+
+    def test_add_docstring(self):
+        import numpy as np
+        foo = lambda: None
+        np.add_docstring(foo, "Does a thing")
+        assert foo.__doc__ == "Does a thing"
+
+    def test_type_docstring(self):
+        import numpy as np
+        import types
+        obj = types.ModuleType
+        doc = obj.__doc__
+        try:
+            np.set_docstring(obj, 'foo')
+            assert obj.__doc__ == 'foo'
+        finally:
+            np.set_docstring(obj, doc)
+
+        raises(RuntimeError, np.add_docstring, obj, 'foo')
+
+    def test_method_docstring(self):
+        import numpy as np
+        doc = int.bit_length.__doc__
+        try:
+            np.set_docstring(int.bit_length, 'foo')
+            assert int.bit_length.__doc__ == 'foo'
+        finally:
+            np.set_docstring(int.bit_length, doc)
+
+    def test_property_docstring(self):
+        import numpy as np
+        doc = np.flatiter.base.__doc__
+        try:
+            np.set_docstring(np.flatiter.base, 'foo')
+            assert np.flatiter.base.__doc__ == 'foo'
+        finally:
+            np.set_docstring(np.flatiter.base, doc)
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py 
b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -1361,3 +1361,26 @@
         assert np.add(np.zeros(5, dtype=np.int8), 257).dtype == np.int16
         assert np.subtract(np.zeros(5, dtype=np.int8), 257).dtype == np.int16
         assert np.divide(np.zeros(5, dtype=np.int8), 257).dtype == np.int16
+
+    def test_add_doc(self):
+        import sys
+        if '__pypy__' not in sys.builtin_module_names:
+            skip('')
+        try:
+            from numpy import set_docstring
+        except ImportError:
+            from _numpypy.multiarray import set_docstring
+        import numpy as np
+        assert np.add.__doc__ is None
+        add_doc = np.add.__doc__
+        ufunc_doc = np.ufunc.__doc__
+        try:
+            np.add.__doc__ = 'np.add'
+            assert np.add.__doc__ == 'np.add'
+            # Test for interferences between ufunc objects and their class
+            set_docstring(np.ufunc, 'np.ufunc')
+            assert np.ufunc.__doc__ == 'np.ufunc'
+            assert np.add.__doc__ == 'np.add'
+        finally:
+            set_docstring(np.ufunc, ufunc_doc)
+            np.add.__doc__ = add_doc
diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py
--- a/pypy/module/micronumpy/ufuncs.py
+++ b/pypy/module/micronumpy/ufuncs.py
@@ -86,6 +86,7 @@
         "identity", "int_only", "allow_bool", "allow_complex",
         "complex_to_float", "nargs", "nout", "signature"
     ]
+    w_doc = None
 
     def __init__(self, name, promote_to_largest, promote_to_float, 
promote_bools,
                  identity, int_only, allow_bool, allow_complex, 
complex_to_float):
@@ -105,6 +106,15 @@
     def descr_repr(self, space):
         return space.wrap("<ufunc '%s'>" % self.name)
 
+    def get_doc(self, space):
+        # Note: allows any object to be set as docstring, because why not?
+        if self.w_doc is None:
+            return space.w_None
+        return self.w_doc
+
+    def set_doc(self, space, w_doc):
+        self.w_doc = w_doc
+
     def descr_get_identity(self, space):
         if self.identity is None:
             return space.w_None
@@ -1144,6 +1154,7 @@
     __call__ = interp2app(W_Ufunc.descr_call),
     __repr__ = interp2app(W_Ufunc.descr_repr),
     __name__ = GetSetProperty(W_Ufunc.descr_get_name),
+    __doc__ = GetSetProperty(W_Ufunc.get_doc, W_Ufunc.set_doc),
 
     identity = GetSetProperty(W_Ufunc.descr_get_identity),
     accumulate = interp2app(W_Ufunc.descr_accumulate),
@@ -1157,8 +1168,6 @@
 )
 
 
-
-
 def ufunc_dtype_caller(space, ufunc_name, op_name, nin, bool_result):
     def get_op(dtype):
         try:
@@ -1481,7 +1490,7 @@
     if w_ret.external_loop:
         _parse_signature(space, w_ret, w_ret.signature)
     if doc:
-        w_ret.w_doc = space.wrap(doc)
+        w_ret.set_doc(space, space.wrap(doc))
     return w_ret
 
 # Instantiated in cpyext/ndarrayobject. It is here since ufunc calls
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to