Opened 4 years ago

Last modified 4 years ago

#23670 new defect

rest_index_of_methods does not work in pyx files

Reported by: rws Owned by:
Priority: major Milestone: sage-8.1
Component: documentation Keywords:
Cc: Merged in:
Authors: Reviewers:
Report Upstream: N/A Work issues:
Branch: Commit:
Dependencies: Stopgaps:

Status badges

Description

When adding the following to a source file:

  • {INDEX_OF_METHODS} in the doc head
  • from sage.misc.rest_index_of_methods import doc_index, gen_thematic_rest_table_index to imports
  • from sage.misc.decorators import rename_keyword to imports
  • @doc_index("xyz") as decorator to a method of class X
  • __doc__ = __doc__.replace("{INDEX_OF_METHODS}",gen_thematic_rest_table_index(X)) at the bottom of the file

it will pass make if the file is a .py file but give an error like the following if it's a .pyx file:

(example complex_double.pyx with the decorator at line 2288)
...
[dochtml]   File "sage/rings/complex_double.pyx", line 2288, in init sage.rings.complex_double
[dochtml]   File "/home/ralf/sage/local/lib/python2.7/site-packages/sage/misc/rest_index_of_methods.py", line 318, in hey
[dochtml]     setattr(f,"doc_index",name)
[dochtml] AttributeError: 'method_descriptor' object has no attribute 'doc_index'
Makefile:985: recipe for target 'doc-html' failed

Change History (13)

comment:1 Changed 4 years ago by rws

This may well be unsolvable. Opinions?

comment:2 in reply to: ↑ description Changed 4 years ago by jdemeyer

Replying to rws:

  • @doc_index("xyz") as decorator to a method of class X

Python class or extension type (cdef class)?

My guess is that Python classes in Cython files should still work.

Can you try with @cython.binding(True) (see also #22747)?

comment:3 Changed 4 years ago by jdemeyer

From a simple stand-alone experiment I just did, this should work with @cython.binding(True)

comment:4 follow-up: Changed 4 years ago by rws

So what am I doing wrong here:

diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx
index be609678cf..e4b08d0e05 100644
--- a/src/sage/symbolic/expression.pyx
+++ b/src/sage/symbolic/expression.pyx
@@ -12,6 +12,9 @@ following the expression with a period ``.`` followed by the member
 function call, as it is usual in Python.
 
 The member functions can be grouped in the following categories:
+
+{INDEX_OF_METHODS}
+
  - algebraic operations: :func:`~Expression.coefficient`,
    :func:`~Expression.coefficients`, :func:`~Expression.content`,
    :func:`~Expression.default_variable`, :func:`~Expression.degree`,
@@ -202,6 +205,7 @@ from sage.misc.derivative import multi_derivative
 from sage.misc.superseded import deprecated_function_alias, deprecation
 from sage.rings.infinity import AnInfinity, infinity, minus_infinity, unsigned_infinity
 from sage.misc.decorators import rename_keyword
+from sage.misc.rest_index_of_methods import doc_index, gen_thematic_rest_table_index
 from sage.structure.dynamic_class import dynamic_class
 from sage.symbolic.operators import FDerivativeOperator, add_vararg, mul_vararg
 from sage.arith.numerical_approx cimport digits_to_bits
@@ -2337,6 +2341,8 @@ cdef class Expression(CommutativeRingElement):
         cdef Expression symbol0 = self.coerce_in(var)
         return self._gobj.is_polynomial(symbol0._gobj)
 
+    @cython.binding(True)
+    @doc_index("xyz")
     cpdef bint is_relational(self):
         """
         Return True if self is a relational expression.
@@ -12800,3 +12806,5 @@ cdef operators compatible_relation(operators lop, operators rop) except <operato
        return greater
     else:
         raise TypeError("incompatible relations")
+
+__doc__ = __doc__.replace("{INDEX_OF_METHODS}",gen_thematic_rest_table_index(Expression))

I get:

sage/symbolic/expression.pyx:2344:4: Cdef functions/classes cannot take arbitrary decorators.

comment:5 Changed 4 years ago by rws

Ah that is on top #23657 and may not apply cleanly to develop.

comment:6 Changed 4 years ago by jdemeyer

Did you forget cimport cython?

comment:7 in reply to: ↑ 4 Changed 4 years ago by jdemeyer

Replying to rws:

sage/symbolic/expression.pyx:2344:4: Cdef functions/classes cannot take arbitrary decorators.

I see. The problem is that this is a cpdef method.

comment:8 Changed 4 years ago by jdemeyer

With binding(True), it is possible to have a working doc_index for cpdef methods, just not using the decorator syntax.

comment:9 Changed 4 years ago by rws

The problem even with def members is that, while it compiles, the doc will not build. The error given in the ticket description is still there.

comment:10 follow-up: Changed 4 years ago by rws

Not only doc building crashes, Sage itself crashes already at startup. I placed the decorator on def is_exact:

/home/ralf/sage/local/lib/python2.7/site-packages/sage/misc/rest_index_of_methods.pyc in hey(f=<unbound method Expression.is_exact>)
    303     INPUT:
    304 
    305     - ``name`` -- a string, which will become the title of the index in which
    306       this function/method will appear.
    307 
    308     EXAMPLES::
    309 
    310         sage: from sage.misc.rest_index_of_methods import doc_index
    311         sage: @doc_index("Wouhouuuuu")
    312         ....: def a():
    313         ....:     print("Hey")
    314         sage: a.doc_index
    315         'Wouhouuuuu'
    316     """
    317     def hey(f):
--> 318         setattr(f,"doc_index",name)
        global setattr = undefined
        f = <unbound method Expression.is_exact>
        global name = undefined
    319         return f
    320     return hey
    321 
    322 __doc__ = __doc__.format(INDEX_OF_FUNCTIONS=gen_rest_table_index([gen_rest_table_index]))

AttributeError: 'instancemethod' object has no attribute 'doc_index'

comment:11 in reply to: ↑ 10 ; follow-up: Changed 4 years ago by jdemeyer

Replying to rws:

I placed the decorator on def is_exact:

What is your exact diff here?

comment:12 in reply to: ↑ 11 Changed 4 years ago by rws

Replying to jdemeyer:

Replying to rws:

I placed the decorator on def is_exact:

What is your exact diff here?

On top of develop:

diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx
index 45f73f0851..75327bc1b5 100644
--- a/src/sage/symbolic/expression.pyx
+++ b/src/sage/symbolic/expression.pyx
@@ -2,6 +2,8 @@
 """
 Symbolic Expressions
 
+{INDEX_OF_METHODS}
+
 RELATIONAL EXPRESSIONS:
 
 We create a relational expression::
@@ -136,7 +138,7 @@ Test if :trac:`9947` is fixed::
 #                  http://www.gnu.org/licenses/
 #*****************************************************************************
 from __future__ import print_function, absolute_import
-
+cimport cython
 from cysignals.signals cimport sig_on, sig_off
 
 from inspect import ismethod
@@ -157,6 +159,7 @@ from sage.misc.derivative import multi_derivative
 from sage.misc.superseded import deprecated_function_alias, deprecation
 from sage.rings.infinity import AnInfinity, infinity, minus_infinity, unsigned_infinity
 from sage.misc.decorators import rename_keyword
+from sage.misc.rest_index_of_methods import doc_index, gen_thematic_rest_table_index
 from sage.structure.dynamic_class import dynamic_class
 from sage.symbolic.operators import FDerivativeOperator, add_vararg, mul_vararg
 from sage.arith.numerical_approx cimport digits_to_bits
@@ -2307,6 +2310,8 @@ cdef class Expression(CommutativeRingElement):
         """
         return is_a_relational(self._gobj)
 
+    @cython.binding(True)
+    @doc_index("xyz")
     def is_exact(self):
         """
         Return True if this expression only contains exact numerical coefficients.
@@ -12755,3 +12760,5 @@ cdef operators compatible_relation(operators lop, operators rop) except <operato
        return greater
     else:
         raise TypeError("incompatible relations")
+
+__doc__ = __doc__.replace("{INDEX_OF_METHODS}",gen_thematic_rest_table_index(Expression))

comment:13 Changed 4 years ago by jdemeyer

Right, I see. In my "stand-alone experiment", I didn't actually use a decorator. I just tried to see if it would work conceptually.

This works:

cimport cython
from sage.misc.rest_index_of_methods import doc_index

cdef class X:
    @cython.binding(True)
    def meth(self):
        return
    
doc_index("foo")(X.__dict__["meth"])

But with a decorator, it does not work:

cimport cython
from sage.misc.rest_index_of_methods import doc_index

cdef class X:
    @doc_index("foo")
    @cython.binding(True)
    def meth(self):
        return 

I would say that this is a Cython bug.

Last edited 4 years ago by jdemeyer (previous) (diff)
Note: See TracTickets for help on using tickets.