Ticket #7448: trac_7448-nested_class_sphinx-fh.5.patch

File trac_7448-nested_class_sphinx-fh.5.patch, 11.8 KB (added by mpatel, 12 years ago)

Only fix rendering of nested classes.

  • doc/common/conf.py

    # HG changeset patch
    # User Florent Hivert <Florent.Hivert@univ-rouen.fr>
    # Date 1266948766 -3600
    # Node ID 0ffd635336d6158ab3695bbc5b79f600f90423a6
    # Parent  229d0893f9923e5fef1ad51183ca0acd70321a17
    #7448 : Fixes Sphinx rendering of nested classes
    
    diff --git a/doc/common/conf.py b/doc/common/conf.py
    a b def process_docstring_module_title(app,  
    285285        else:
    286286            break
    287287
    288 def skip_NestedClass(app, what, name, obj, skip, options):
     288def skip_member(app, what, name, obj, skip, options):
    289289    """
    290     Don't include the docstring for any class/function/object in
    291     sage.misc.misc whose ``name`` contains "MainClass.NestedClass".
    292     (This is to avoid some Sphinx warnings when processing
    293     sage.misc.misc.)  Otherwise, abide by Sphinx's decision.
     290    To suppress Sphinx warnings / errors, we
     291
     292    - Don't include the docstring for any nested class which has been
     293      inserted into its module by
     294      :class:`sage.misc.NestedClassMetaclass` only for pickling.  The
     295      class will be properly documented inside its surrounding class.
     296
     297    - Don't include
     298      sagenb.notebook.twist.userchild_download_worksheets.zip.
     299
     300    Otherwise, we abide by Sphinx's decision.  Note: The object
     301    ``obj`` is excluded (included) if this handler returns True
     302    (False).
    294303    """
    295     skip_nested = str(obj).find("sage.misc.misc") != -1 and name.find("MainClass.NestedClass") != -1
    296     skip_download_worksheets = name.find("userchild_download_worksheets.zip") != -1
    297     return skip or skip_nested or skip_download_worksheets
     304    if (hasattr(obj, '__name__') and obj.__name__.find('.') != -1 and
     305        obj.__name__.split('.')[-1] != name):
     306        return True
     307
     308    if name.find("userchild_download_worksheets.zip") != -1:
     309        return True
     310
     311    return skip
    298312
    299313def process_dollars(app, what, name, obj, options, docstringlines):
    300314    r"""
    def setup(app): 
    330344    app.connect('autodoc-process-docstring', process_docstring_module_title)
    331345    app.connect('autodoc-process-docstring', process_dollars)
    332346    app.connect('autodoc-process-docstring', process_mathtt)
    333     app.connect('autodoc-skip-member', skip_NestedClass)
     347    app.connect('autodoc-skip-member', skip_member)
  • doc/common/sage_autodoc.py

    diff --git a/doc/common/sage_autodoc.py b/doc/common/sage_autodoc.py
    a b class ClassDocumenter(ModuleLevelDocumen 
    844844
    845845    def import_object(self):
    846846        ret = ModuleLevelDocumenter.import_object(self)
    847         # if the class is documented under another name, document it
     847        # If the class is already documented under another name, document it
    848848        # as data/attribute
     849        #
     850        # Notes from Florent Hivert (2010-02-18) Sage trac #7448:
     851        #
     852        #  - The original goal of this was that if some class is aliased, the
     853        # alias is generated as a link rather than duplicated. For example in:
     854        #     class A: pass
     855        #     B = A
     856        # Then B is an alias of A, and should be generated as such.
     857        #
     858        #  - the way it is solved is to compare the name under which the
     859        # current class is found and the actual name if the class (stored in
     860        # the attribute __name__):
     861        #   if hasattr(self.object, '__name__'):
     862        #       self.doc_as_attr = (self.objpath[-1] != self.object.__name__)
     863        #   else:
     864        #       self.doc_as_attr = True
     865        #
     866        #  - The original implementation as well as the new one don't work if
     867        # a class is aliased from a different place under the same name. For
     868        # example, in the following
     869        #     class A: pass
     870        #     class Container:
     871        #         A = A
     872        # The nested copy Container.A is also documented. Actually, it seems
     873        # that there is no way to solve this by introspection. I'll submbit
     874        # this problem on sphinx trac.
     875        #
     876        #  - Now, to work around a pickling bug of nested class in Python,
     877        # by using the metaclass NestedMetaclass, we change the attribute
     878        # __name__ of the nested class. For example, in
     879        #     class A(object): pass
     880        #        __metaclass__ = NestedClassMetaclass
     881        #        class B(object): pass
     882        # the class B get its name changed to 'A.B'. Such dots '.' in names
     883        # are not supposed to occur in normal python name. I use it to check
     884        # if the class is a nested one and to compare its __name__ with its
     885        # path.
     886        #
     887        # References: Sage #5986, file sage/misc/nested_class.py
    849888        if ret:
    850889            if hasattr(self.object, '__name__'):
    851                 self.doc_as_attr = (self.objpath[-1] != self.object.__name__)
     890                name = self.object.__name__
     891                self.doc_as_attr = (self.objpath != name.split('.') and
     892                                    self.check_module())
    852893            else:
    853894                self.doc_as_attr = True
    854895        return ret
  • doc/en/reference/misc.rst

    diff --git a/doc/en/reference/misc.rst b/doc/en/reference/misc.rst
    a b Miscellaneous 
    3131   sage/misc/sagedoc
    3232   sage/rings/arith
    3333   sage/misc/nested_class
     34   sage/misc/nested_class_test
    3435   sage/misc/classcall_metaclass
  • sage/misc/nested_class.py

    diff --git a/sage/misc/nested_class.py b/sage/misc/nested_class.py
    a b way which is incompatible with the pickl 
    1010    sage: A.B.__name__
    1111    'B'
    1212
    13 instead of the a priori more natural `A.B`.
     13instead of the a priori more natural ``"A.B"``.
    1414
    1515Furthermore, upon pickling (here in save_global) *and* unpickling (in
    16 load_global) a class with name "A.B" in a module mod, the standard
    17 cPickle module searches for "A.B" in mod.__dict__ instead of looking
    18 up "A" and then "B" in the result.
     16load_global) a class with name ``"A.B"`` in a module ``mod``, the standard
     17cPickle module searches for ``"A.B"`` in ``mod.__dict__`` instead of looking
     18up ``"A"`` and then ``"B"`` in the result.
    1919
    2020See: http://groups.google.com/group/sage-devel/browse_thread/thread/6c7055f4a580b7ae/
    2121
    2222This module provides two utilities to workaround this issue:
    2323
    2424 - :func:`nested_pickle` "fixes" recursively the name of the
    25    subclasses of a class and inserts their fullname 'A.B' in
    26    mod.__dict__
     25   subclasses of a class and inserts their fullname ``"A.B"`` in
     26   ``mod.__dict__``
    2727
    28  - :class:`NestedClassMetaclass` is a metaclass ensuring that nested_pickle is
    29    called on a class upon creation.
     28 - :class:`NestedClassMetaclass` is a metaclass ensuring that
     29   :func:`nested_pickle` is called on a class upon creation.
    3030
    3131See also :mod:`sage.misc.nested_class_test`.
    3232
    All of this is not perfect. In the follo 
    6464    ...       A2 = A1.A2
    6565    ...
    6666
    67 The name for A1.A2 could potentially be set to B1.A2. But that will work anyway.
     67The name for ``"A1.A2"`` could potentially be set to ``"B1.A2"``. But that will work anyway.
    6868"""
    6969
    7070import sys
    7171
     72__all__ = ['modify_for_nested_pickle', 'nested_pickle',
     73           'NestedClassMetaclass', 'MainClass'
     74           # Comment out to silence Sphinx warning about nested classes.
     75           #, 'SubClass', 'CopiedClass', 'A1'
     76           ]
     77
    7278def modify_for_nested_pickle(cls, name_prefix, module):
    7379    r"""
    7480    Modify the subclasses of the given class to be picklable, by
    def nested_pickle(cls): 
    127133        sage: nested_pickle(A)
    128134        <class '__main__.A'>
    129135
    130     then the name of class B will be modified to 'A.B', and the 'A.B'
    131     attribute of the module will be set to class B::
    132    
     136    then the name of class ``"B"`` will be modified to ``"A.B"``, and the ``"A.B"``
     137    attribute of the module will be set to class ``"B"``::
     138
    133139        sage: A.B.__name__
    134140        'A.B'
    135141        sage: getattr(module, 'A.B', 'Not found')
    136142        <class __main__.A.B at ...>
    137143
    138     In Python 2.6, decorators work with classes; then @nested_pickle
     144    In Python 2.6, decorators work with classes; then ``@nested_pickle``
    139145    should work as a decorator::
    140146
    141147        sage: @nested_pickle    # todo: not implemented
    class NestedClassMetaclass(type): 
    179185    """
    180186    def __init__(self, *args):
    181187        r"""
    182         This invokes the nested_pickle on construction. 
    183        
     188        This invokes the nested_pickle on construction.
     189
    184190        sage: from sage.misc.nested_class import NestedClassMetaclass
    185191        sage: class A(object):
    186192        ...       __metaclass__ = NestedClassMetaclass
    class MainClass(object): 
    207213    """
    208214
    209215    __metaclass__ = NestedClassMetaclass
    210    
     216
    211217    class NestedClass(object):
    212218        r"""
    213219        EXAMPLES::
    class SubClass(MainClass): 
    237243
    238244    EXAMPLES::
    239245
    240         sage: from sage.misc.nested_class import *
     246        sage: from sage.misc.nested_class import SubClass
    241247        sage: loads(dumps(SubClass.NestedClass()))
    242248        <sage.misc.nested_class.MainClass.NestedClass object at 0x...>
     249        sage: loads(dumps(SubClass()))
     250        <sage.misc.nested_class.SubClass object at 0x...>
    243251    """
    244252    pass
    245253
    class CopiedClass(object): 
    251259
    252260    EXAMPLES::
    253261
    254         sage: from sage.misc.nested_class import *
     262        sage: from sage.misc.nested_class import CopiedClass
    255263        sage: loads(dumps(CopiedClass.NestedClass()))
    256264        <sage.misc.nested_class.MainClass.NestedClass object at 0x...>
    257265        sage: loads(dumps(CopiedClass.NestedSubClass()))
    258266        <sage.misc.nested_class.MainClass.NestedClass.NestedSubClass object at 0x...>
    259         sage: loads(dumps(SubClass()))
    260         <sage.misc.nested_class.SubClass object at 0x...>
    261267    """
    262268    NestedClass = MainClass.NestedClass
    263269    NestedSubClass = MainClass.NestedClass.NestedSubClass
    class A1: 
    271277    class A2:
    272278        class A3:
    273279            pass
     280
  • sage/misc/nested_class_test.py

    diff --git a/sage/misc/nested_class_test.py b/sage/misc/nested_class_test.py
    a b  
    11"""
     2Test for nested class Parent
     3
    24This file contains a discussion, examples, and tests about nested
    35classes and parents. It is kept in a separate file to avoid import
    46loops.
    alternative is to use ClasscallMetaclass 
    4345#                  http://www.gnu.org/licenses/
    4446#******************************************************************************
    4547
     48__all__ = [] # Don't document any parents
     49
    4650from sage.structure.parent import Parent
    4751from sage.structure.element_wrapper import ElementWrapper
    4852from sage.structure.unique_representation import UniqueRepresentation
    class TestParent4(Parent): 
    120124
    121125    class Element(ElementWrapper):
    122126        pass
     127
     128
     129# Class for tests:
     130class B(object):
     131    """
     132    A normal external class.
     133    """
     134    pass
     135
     136class ABB(object):
     137    class B(object):
     138        """
     139        This class is broken and can't be pickled.
     140        A warning is emmited during compilation.
     141        """
     142        pass
     143
     144class ABL(object):
     145    """
     146    There is no problem here.
     147    """
     148    B=B
     149
     150class ALB(object):
     151    """
     152    There is a nested class just below. Which can't be properly sphinxed.
     153    """
     154    class C(object):
     155        """
     156        Internal C class.
     157
     158        Thanks to the links below this class is pickled ok.
     159        But it is sphixed wrong: It is typeset as a link to an outer class.
     160        """
     161        pass
     162
     163C = ALB.C
     164
     165
     166
     167class ABBMeta(object):
     168    __metaclass__ = NestedClassMetaclass
     169    class B(object):
     170        """
     171        B interne
     172        """
     173        pass
     174
     175class ABLMeta(object):
     176    __metaclass__ = NestedClassMetaclass
     177    B=B
     178
     179class ALBMeta(object):
     180    """
     181    There is a nested class just below which is properly sphinxed.
     182    """
     183    __metaclass__ = NestedClassMetaclass
     184    class CMeta(object):
     185        """
     186        B interne
     187        """
     188        pass
     189
     190CMeta = ALBMeta.CMeta