Ticket #11935: trac11935_weak_pickling_by_construction_rel11943-nt.patch

File trac11935_weak_pickling_by_construction_rel11943-nt.patch, 32.8 KB (added by nthiery, 7 years ago)
  • sage/categories/bimodules.py

    # HG changeset patch
    # User Simon King <simon.king@uni-jena.de>
    # Date 1318941258 -7200
    # Node ID 15bd1ff2ac6782a34906cadf45bd400f962d2253
    # Parent  02bd55d02cd49a785ff35bbe772cc30a546c07cf
    #11935: Make parent/element classes independent of base rings
    
    Other change in sage.categories.examples.semigroups_cython:
    - rename the experimental class IdempotentSemigroups.ElementMethods
      and remove its super class.
    - discards unused code
    
    diff --git a/sage/categories/bimodules.py b/sage/categories/bimodules.py
    a b Bimodules 
    1111#                  http://www.gnu.org/licenses/
    1212#******************************************************************************
    1313
    14 from sage.categories.category import Category
    15 from sage.misc.cachefunc import cached_method
     14from sage.misc.unknown import Unknown
     15from sage.categories.category import Category, CategoryWithParameters
    1616from sage.categories.left_modules import LeftModules
    1717from sage.categories.right_modules import RightModules
    1818
    from sage.categories.rings import Rings 
    2020_Rings = Rings()
    2121
    2222#?class Bimodules(Category_over_base_rng, Category_over_base_rng):
    23 class Bimodules(Category):
     23class Bimodules(CategoryWithParameters):
    2424    """
    2525    The category of `(R,S)`-bimodules
    2626
  • sage/categories/category.py

    diff --git a/sage/categories/category.py b/sage/categories/category.py
    a b from sage.misc.unknown import Unknown 
    104104
    105105from sage.structure.sage_object import SageObject
    106106from sage.structure.unique_representation import UniqueRepresentation
    107 from sage.structure.dynamic_class import dynamic_class_internal
     107from sage.structure.dynamic_class import dynamic_class
    108108
    109109from weakref import WeakValueDictionary
    110110_join_cache = WeakValueDictionary()
    class Category(UniqueRepresentation, Sag 
    351351    same super_categories. For example, Algebras(QQ) has
    352352    VectorSpaces(QQ) as super category, whereas Algebras(ZZ) only has
    353353    Modules(ZZ) as super category. In particular, the constructed
    354     parent_class and element_class will differ (inheriting, or not,
    355     methods specific for vector spaces). On the other hand, caching
    356     ensures that two identical hierarchy of classes are built only
    357     once::
     354    parent class and element class will differ (inheriting, or not,
     355    methods specific for vector spaces)::
    358356
    359         # TODO: redo the same with Algebras
    360         # and show the mro for Algebras(QQ) w.r.t Algebras(ZZ)
    361         # 2009/03/11: this feature is temporarily broken, due to the current work around for pickling
    362         sage: Coalgebras(QQ).parent_class is Coalgebras(FractionField(QQ[x])).parent_class # todo: not implemented
     357        sage: Algebras(QQ).parent_class is Algebras(ZZ).parent_class
     358        False
     359        sage: issubclass(Algebras(QQ).parent_class, VectorSpaces(QQ).parent_class)
     360        True
     361
     362    On the other hand, identical hierarchies of classes are,
     363    preferably, built only once (e.g. for cagories over a base ring)::
     364
     365        sage: Algebras(QQ).parent_class is Algebras(GF(5)).parent_class
     366        True
     367        sage: Coalgebras(QQ).parent_class is Coalgebras(FractionField(QQ[x])).parent_class
    363368        True
    364369
    365370    We now construct a parent in the usual way::
    class Category(UniqueRepresentation, Sag 
    436441
    437442        INPUT:
    438443
    439         - s -- A string giving the name of this category.  If None,
    440           the name is determined from the name of the class.
     444        - ``s`` -- A string giving the name of this category.
     445          If None, the name is determined from the name of the class.
    441446
    442447        EXAMPLES::
    443448
    class Category(UniqueRepresentation, Sag 
    651656        ``self``; this is the first test that is done in
    652657        :meth:`is_subcategory`.
    653658
    654         This default implementation tests whether the parent class
    655         of ``category`` is a subclass of the parent class of ``self``.
    656         Currently (as of trac ticket #11900) this is a complete
    657         subcategory test. But this will change with trac ticket #11935.
     659        This default implementation tests whether the parent class of
     660        ``category`` is a subclass of the parent class of ``self``.
     661        This is most of the time a complete subcategory test.
     662
     663        .. warning::
     664
     665            This test is incomplete for categories in
     666            :class:`CategoryWithParameters`, as introduced by
     667            :trac:`11935`. This method is therefore overwritten by
     668            :meth:`~sage.categories.category.CategoryWithParameters._subcategory_hook_`.
    658669
    659670        EXAMPLE::
    660671
    class Category(UniqueRepresentation, Sag 
    10261037        """
    10271038        pass
    10281039
     1040    def _make_named_class(self, name, method_provider, cache=False):
     1041        """
     1042        Construction of the parent/element/... class of self.
     1043
     1044        INPUT:
     1045
     1046        - ``name`` -- a string; the name of the class as an attribute of ``self``.
     1047          E.g. "parent_class"
     1048        - ``method_provider`` -- a string; the name of an attribute of
     1049          ``self`` that provides methods for the new class (in
     1050          addition to those coming from the super categories).
     1051          E.g. "ParentMethods"
     1052        - ``cache`` -- a boolean or ``ignore_reduction`` (default: False)
     1053          (passed down to dynamic_class; for internal use only)
     1054
     1055        ASSUMPTION:
     1056
     1057        It is assumed that this method is only called from a lazy
     1058        attribute whose name coincides with the given ``name``
     1059
     1060        OUTPUT:
     1061
     1062        A dynamic class with bases given by the corresponding named
     1063        classes of ``self``'s super_categories and methods taken from
     1064        the class ``getattr(self,method_provider)``.
     1065
     1066        .. NOTE::
     1067
     1068            In this default implementation, the reduction data of the
     1069            named class makes it depend on ``self``. Since the result
     1070            is going to be stored in a lazy attribute of ``self``
     1071            anyway, we may as well disable the caching in
     1072            ``dynamic_class`` (hence the default value ``cache=False``).
     1073
     1074            :class:`CategoryWithParameters` overrides this method so
     1075            that the same parent/element/... classes can be shared
     1076            between closely related categories.
     1077
     1078        .. SEEALSO:: :meth:`CategoryWithParameters._make_named_class`
     1079
     1080        EXAMPLES::
     1081
     1082            sage: PC = Rings()._make_named_class("parent_class", "ParentMethods"); PC
     1083            <class 'sage.categories.rings.Rings.parent_class'>
     1084            sage: type(PC)
     1085            <class 'sage.structure.dynamic_class.DynamicMetaclass'>
     1086            sage: PC.__bases__
     1087            (<class 'sage.categories.rngs.Rngs.parent_class'>, <class 'sage.categories.semirings.Semirings.parent_class'>)
     1088
     1089        Note that, by default, the result is not cached::
     1090
     1091            sage: PC is Rings()._make_named_class("parent_class", "ParentMethods")
     1092            False
     1093
     1094        Indeed this method is only meant to construct lazy attributes
     1095        like ``parent_class`` which already handle this caching::
     1096
     1097            sage: Rings().parent_class
     1098            <class 'sage.categories.rings.Rings.parent_class'>
     1099
     1100        Reduction for pickling also assumes the existence of this lazy
     1101        attribute::
     1102
     1103            sage: PC._reduction
     1104            (<built-in function getattr>, (Category of rings, 'parent_class'))
     1105            sage: loads(dumps(PC)) is Rings().parent_class
     1106            True
     1107
     1108        TESTS::
     1109
     1110            sage: class A: pass
     1111            sage: class BrokenCategory(Category):
     1112            ...       def super_categories(self): return []
     1113            ...       ParentMethods = 1
     1114            ...       class ElementMethods(A):
     1115            ...           pass
     1116            ...       class MorphismMethods(object):
     1117            ...           pass
     1118            sage: C = BrokenCategory()
     1119            sage: C._make_named_class("parent_class",   "ParentMethods")
     1120            Traceback (most recent call last):
     1121            ...
     1122            AssertionError: BrokenCategory.ParentMethods should be a class
     1123            sage: C._make_named_class("element_class",  "ElementMethods")
     1124            doctest:...: UserWarning: BrokenCategory.ElementMethods should not have a super class
     1125            <class '__main__.BrokenCategory.element_class'>
     1126            sage: C._make_named_class("morphism_class", "MorphismMethods")
     1127            <class '__main__.BrokenCategory.morphism_class'>
     1128        """
     1129        cls = self.__class__
     1130        class_name = "%s.%s"%(cls.__name__, name)
     1131        method_provider_cls = getattr(self, method_provider, None)
     1132        if method_provider_cls is None:
     1133            # If the category provides no XXXMethods class,
     1134            # point to the documentation of the category itself
     1135            doccls = cls
     1136        else:
     1137            # Otherwise, check XXXMethods
     1138            import inspect
     1139            assert inspect.isclass(method_provider_cls),\
     1140                "%s.%s should be a class"%(type(self).__name__, method_provider)
     1141            mro = inspect.getmro(method_provider_cls)
     1142            if len(mro) > 2 or (len(mro) == 2 and mro[1] is not object):
     1143                from warnings import warn
     1144                warn("%s.%s should not have a super class"%(type(self).__name__, method_provider))
     1145            # and point the documentation to it
     1146            doccls = method_provider_cls
     1147        self._super_categories
     1148        return dynamic_class(class_name,
     1149                             tuple(getattr(cat,name) for cat in self._super_categories),
     1150                             method_provider_cls, prepend_cls_bases = False, doccls = doccls,
     1151                             reduction = (getattr, (self, name)), cache = cache)
     1152
     1153
    10291154    @lazy_attribute
    10301155    def parent_class(self):
    10311156        """
    class Category(UniqueRepresentation, Sag 
    10371162            <class 'sage.categories.algebras.Algebras.parent_class'>
    10381163            sage: type(C)
    10391164            <class 'sage.structure.dynamic_class.DynamicMetaclass'>
     1165
     1166        By :trac:`11935`, some categories share their parent
     1167        classes. For example, the parent class of an algebra only
     1168        depends on the base ring if the choice of the base ring alters
     1169        the type of the super categories. A typical example is the
     1170        category of algebras over a field versus algebras over a
     1171        non-field::
     1172
     1173            sage: Algebras(QQ).parent_class is Algebras(GF(3)).parent_class
     1174            True
     1175            sage: Algebras(QQ).parent_class is Algebras(ZZ).parent_class
     1176            False
     1177            sage: Algebras(ZZ['t']).parent_class is Algebras(ZZ['t','x']).parent_class
     1178            True
     1179
     1180        See :class:`CategoryWithParameters` for an abstract base class for
     1181        categories that depend on parameters, even though the parent
     1182        and element classes only depend on the parent or element
     1183        classes of its super categories. It is used in
     1184        :class:`~sage.categories.bimodules.Bimodules`,
     1185        :class:`~sage.categories.category_types.Category_over_base` and
     1186        :class:`sage.categories.category.JoinCategory`.
    10401187        """
    1041         # Remark:
    1042         # For now, we directly call the underlying function, avoiding the overhead
    1043         # of using a cached function. The rationale: When this lazy method is called
    1044         # then we can be sure that the parent class had not been constructed before.
    1045         # The parent and element classes belong to a category, and they are pickled
    1046         # as such. Hence, they are rightfully cached as an attribute of a category.
    1047         #
    1048         # However, we should try to "unify" parent classes. They should depend on the
    1049         # super categories, but not on the base (except when the super categories depend
    1050         # on the base). When that is done, calling the cached function will be needed again.
    1051         #return dynamic_class("%s.parent_class"%self.__class__.__name__,
    1052         #                     tuple(cat.parent_class for cat in self.super_categories),
    1053         #                     self.ParentMethods,
    1054         #                     reduction = (getattr, (self, "parent_class")))
    1055         return dynamic_class_internal.f("%s.parent_class"%self.__class__.__name__,
    1056                              tuple(cat.parent_class for cat in self._super_categories),
    1057                              self.ParentMethods,
    1058                              reduction = (getattr, (self, "parent_class")))
     1188        return self._make_named_class('parent_class', 'ParentMethods')
    10591189
    10601190    @lazy_attribute
    10611191    def element_class(self):
    class Category(UniqueRepresentation, Sag 
    10681198            <class 'sage.categories.algebras.Algebras.element_class'>
    10691199            sage: type(C)
    10701200            <class 'sage.structure.dynamic_class.DynamicMetaclass'>
     1201
     1202        By :trac:`11935`, some categories share their element
     1203        classes. For example, the element class of an algebra only
     1204        depends on the base ring if the choice of the base ring alters
     1205        the type of the super categories. A typical example is the
     1206        category of algebras over a field versus algebras over a
     1207        non-field::
     1208
     1209            sage: Algebras(QQ).element_class is Algebras(GF(3)).element_class
     1210            True
     1211            sage: Algebras(QQ).element_class is Algebras(ZZ).element_class
     1212            False
     1213            sage: Algebras(ZZ['t']).element_class is Algebras(ZZ['t','x']).element_class
     1214            True
    10711215        """
    1072         # Remark:
    1073         # For now, we directly call the underlying function, avoiding the overhead
    1074         # of using a cached function. The rationale: When this lazy method is called
    1075         # then we can be sure that the element class had not been constructed before.
    1076         # The parent and element classes belong to a category, and they are pickled
    1077         # as such. Hence, they are rightfully cached as an attribute of a category.
    1078         #
    1079         # However, we should try to "unify" element classes. They should depend on the
    1080         # super categories, but not on the base (except when the super categories depend
    1081         # on the base). When that is done, calling the cached function will be needed again.
    1082         #return dynamic_class("%s.element_class"%self.__class__.__name__,
    1083         #                     (cat.element_class for cat in self.super_categories),
    1084         #                     self.ElementMethods,
    1085         #                     reduction = (getattr, (self, "element_class"))
    1086         #                     )
    1087         return dynamic_class_internal.f("%s.element_class"%self.__class__.__name__,
    1088                              tuple(cat.element_class for cat in self._super_categories),
    1089                              self.ElementMethods,
    1090                              reduction = (getattr, (self, "element_class")))
     1216        return self._make_named_class('element_class', 'ElementMethods')
    10911217
    10921218    def required_methods(self):
    10931219        """
    class HomCategory(Category): 
    16171743        return []
    16181744
    16191745
     1746##############################################################################
     1747# Parametrized categories whose parent/element class depend only on
     1748# the super categories
     1749##############################################################################
     1750
     1751class CategoryWithParameters(Category):
     1752    """
     1753    A parametrized category whose parent/element classes depend only on its super categories
     1754
     1755    Many categories in Sage are parametrized, like ``C=Algebras(K)``
     1756    which takes a base ring as parameter. In many cases however, the
     1757    operations provided by ``C`` in the parent class and element class
     1758    depend only on the super categories of ``C``. For example, the
     1759    vector space operations are provided if and only if ``K`` is a
     1760    field, since ``VectorSpaces(K)`` is a super category of ``C`` only
     1761    in that case. In such cases, and as an optimization (see :trac:`11935`),
     1762    we want to use the same parent and element class for all fields.
     1763    This is the purpose of this abstract class.
     1764
     1765    Currently, :class:`~sage.categories.category.JoinCategory`,
     1766    :class:`~sage.categories.category_types.Category_over_base` and
     1767    :class:`~sage.categories.bimodules.Bimodules` inherit from this
     1768    class.
     1769
     1770    EXAMPLES::
     1771
     1772        sage: C1 = Algebras(QQ)
     1773        sage: C2 = Algebras(GF(3))
     1774        sage: C3 = Algebras(ZZ)
     1775        sage: from sage.categories.category import CategoryWithParameters
     1776        sage: isinstance(C1, CategoryWithParameters)
     1777        True
     1778        sage: C1.parent_class is C2.parent_class
     1779        True
     1780        sage: C1.parent_class is C3.parent_class
     1781        False
     1782
     1783    """
     1784    def _make_named_class(self, name, method_provider):
     1785        """
     1786        Purpose: Create the parent/element/... class of ``self``.
     1787
     1788        INPUT:
     1789
     1790        - ``name`` -- a string; the name of the class as an attribute of ``self``
     1791        - ``method_provider`` -- a string; the name of an attribute of
     1792          ``self`` that provides methods for the new class (in
     1793          addition to what comes from the super categories).
     1794
     1795        ASSUMPTION:
     1796
     1797        It is assumed that this method is only called from a lazy
     1798        attribute whose name coincides with the given ``name``
     1799
     1800        OUTPUT:
     1801
     1802        A dynamic class that has the corresponding named classes of
     1803        the super categories of ``self`` as bases and contains the
     1804        methods provided by ``getattr(self,method_provider)``.
     1805
     1806        .. NOTE::
     1807
     1808            This method overrides :meth:`Category._make_named_class`
     1809            so that the returned class *only* depends on the
     1810            corresponding named classes of the super categories and on
     1811            the provided methods. This allows for sharing the named
     1812            classes across closely related categories providing the
     1813            same code to their parents, elements and so on.
     1814
     1815        EXAMPLES::
     1816
     1817        The categories of bimodules over the ring ``ZZ['x']`` or the
     1818        ring ``ZZ`` provide the same methods to their parents and
     1819        elements::
     1820
     1821            sage: Bimodules(ZZ,ZZ['x']).parent_class is Bimodules(ZZ,ZZ).parent_class #indirect doctest
     1822            True
     1823            sage: Bimodules(ZZ,ZZ['x']).element_class is Bimodules(ZZ,ZZ).element_class
     1824            True
     1825
     1826        On the other hand, modules over a field have more methods than
     1827        modules over a ring::
     1828
     1829            sage: Modules(GF(3)).parent_class is Modules(ZZ).parent_class
     1830            False
     1831            sage: Modules(GF(3)).element_class is Modules(ZZ).element_class
     1832            False
     1833
     1834        TESTS::
     1835
     1836            sage: Modules(GF(3),dispatch=False).parent_class  is Modules(ZZ).parent_class
     1837            True
     1838            sage: Modules(GF(3),dispatch=False).element_class is Modules(ZZ).element_class
     1839            True
     1840            sage: PC = Algebras(QQ).parent_class; PC   # indirect doctest
     1841            <class 'sage.categories.algebras.Algebras.parent_class'>
     1842            sage: type(PC)
     1843            <class 'sage.structure.dynamic_class.DynamicMetaclass'>
     1844            sage: PC.__bases__
     1845            (<class 'sage.categories.rings.Rings.parent_class'>,
     1846             <class 'sage.categories.vector_spaces.VectorSpaces.parent_class'>)
     1847            sage: loads(dumps(PC)) is PC
     1848            True
     1849        """
     1850        # Implementation: we use the cache functionality of
     1851        # dynamic_class, and specify that the result depends only on
     1852        # the classes this class is built from
     1853        # (e.g. ``self.ParentMethods`` and ``c.parent_class`` for each
     1854        # super category ``c`` of ``self``) and not on the reduction
     1855        # data (which includes ``self``).
     1856        return Category._make_named_class(self, name, method_provider, cache="ignore_reduction")
     1857
     1858    def _subcategory_hook_(self, C):
     1859        """
     1860        A quick but partial test whether ``C`` is a subcategory of ``self``
     1861
     1862        INPUT:
     1863
     1864        - ``C`` -- a category
     1865
     1866        OUTPUT:
     1867
     1868        - ``False``, if ``C.parent_class`` is not a subclass of
     1869          ``self.parent_class``, and :obj:`~sage.misc.unknown.Unknown`
     1870          otherwise.
     1871
     1872        EXAMPLES::
     1873
     1874            sage: Bimodules(QQ,QQ)._subcategory_hook_(Modules(QQ))
     1875            Unknown
     1876            sage: Bimodules(QQ,QQ)._subcategory_hook_(Rings())
     1877            False
     1878        """
     1879        if not issubclass(C.parent_class, self.parent_class):
     1880            return False
     1881        return Unknown
     1882
     1883
    16201884#############################################################
    16211885# Join of several categories
    16221886#############################################################
    16231887
    1624 class JoinCategory(Category):
     1888class JoinCategory(CategoryWithParameters):
    16251889    """
    16261890    A class for joins of several categories. Do not use directly;
    16271891    see Category.join instead.
    class JoinCategory(Category): 
    16351899        [Category of groups, Category of commutative additive monoids]
    16361900        sage: J.all_super_categories(proper=True)
    16371901        [Category of groups, Category of monoids, Category of semigroups, Category of magmas, Category of commutative additive monoids, Category of commutative additive semigroups, Category of additive magmas, Category of sets, Category of sets with partial maps, Category of objects]
     1902
     1903    By :trac:`11935`, join categories and categories over base
     1904    rings inherit from :class:`CategoryWithParameters`. This allows
     1905    for sharing parent and element classes between similar
     1906    categories. For example, since polynomial rings belong to a join
     1907    category and since the underlying implementation is the same for
     1908    all finite fields, we have::
     1909
     1910        sage: GF(3)['x'].category()
     1911        Join of Category of euclidean domains and Category of commutative algebras over Finite Field of size 3
     1912        sage: type(GF(3)['x']) is type(GF(5)['z'])
     1913        True
     1914
    16381915    """
    16391916
    16401917    def __init__(self, super_categories, **kwds):
    class JoinCategory(Category): 
    16981975        """
    16991976        return all(category.is_subcategory(X) for X in self._super_categories)
    17001977
     1978    def is_subcategory(self, C):
     1979        """
     1980        Tell whether this join category is subcategory of another category `C`.
     1981
     1982        EXAMPLES::
     1983
     1984            sage: Category.join([Rings(),Modules(QQ)]).is_subcategory(Category.join([Rngs(),Bimodules(QQ,QQ)]))
     1985            True
     1986
     1987        """
     1988        if C is self:
     1989            return True
     1990        hook = C._subcategory_hook_(self)
     1991        if hook is Unknown:
     1992            return any(X.is_subcategory(C) for X in self._super_categories)
     1993        return hook
     1994
    17011995    def _repr_(self):
    17021996        """
    17031997        Print representation.
  • sage/categories/category_types.py

    diff --git a/sage/categories/category_types.py b/sage/categories/category_types.py
    a b This is placed in a separate file from c 
    1515#*****************************************************************************
    1616
    1717from sage.misc.latex import latex
    18 from category import Category
     18from sage.misc.unknown import Unknown
     19from category import Category, CategoryWithParameters
    1920from objects import Objects
    2021
    2122####################################################################
    class Sequences(Category): 
    197198#############################################################
    198199# Category of objects over some base object
    199200#############################################################
    200 class Category_over_base(Category):
     201class Category_over_base(CategoryWithParameters):
    201202    def __init__(self, base, name=None):
    202203        Category.__init__(self, name)
    203204        self.__base = base
    class Category_over_base(Category): 
    234235        """
    235236        return "\\mathbf{%s}_{%s}"%(self._label, latex(self.__base))
    236237
     238    def _subcategory_hook_(self, C):
     239        """
     240        A quick test whether a category `C` may be subcategory of this category.
     241
     242        INPUT:
     243
     244        - `C` `` a category (type not tested)
     245
     246        OUTPUT:
     247
     248        a boolean if it is certain that `C` is (or is not) a
     249        subcategory of self. :obj:`~sage.misc.unknown.Unknown`
     250        otherwise.
     251
     252        EXAMPLES::
     253
     254            sage: Algebras(QQ)._subcategory_hook_(HopfAlgebras(QQ))
     255            True
     256            sage: Algebras(QQ)._subcategory_hook_(HopfAlgebras(ZZ))
     257            False
     258            sage: VectorSpaces(QQ)._subcategory_hook_(VectorSpaces(QQ).hom_category())
     259            True
     260            sage: VectorSpaces(QQ)._subcategory_hook_(Category.join([VectorSpaces(QQ).hom_category(),Rings()]))
     261            Unknown
     262
     263        """
     264        if not issubclass(C.parent_class, self.parent_class):
     265            return False
     266        try:
     267            if C.base() is self.__base:
     268                return True
     269        except AttributeError:
     270            pass
     271        return Unknown
     272
    237273#    def construction(self):
    238274#        return (self.__class__, self.__base)
    239275
  • sage/categories/examples/semigroups_cython.pyx

    diff --git a/sage/categories/examples/semigroups_cython.pyx b/sage/categories/examples/semigroups_cython.pyx
    a b from sage.categories.all import Category 
    77from sage.misc.cachefunc import cached_method
    88from sage.categories.examples.semigroups import LeftZeroSemigroup as LeftZeroSemigroupPython
    99
    10 class DummyClass:
    11     def method(self):
    12         """
    13         TESTS::
    14 
    15             sage: from sage.categories.examples.semigroups_cython import DummyClass
    16             sage: DummyClass().method()
    17         """
    18         pass
    19 
    20 cdef class DummyCClass:
    21     def method(self):
    22         """
    23         TESTS::
    24 
    25             sage: from sage.categories.examples.semigroups_cython import DummyCClass
    26             sage: DummyCClass().method()
    27         """
    28         pass
    29 
    30     cpdef cpmethod(self):
    31         """
    32         TESTS::
    33 
    34             sage: from sage.categories.examples.semigroups_cython import DummyCClass
    35             sage: DummyCClass().cpmethod()
    36         """
    37         pass
    38 
    39 instancemethod     = type(DummyClass.method)
    40 method_descriptor  = type(DummyCClass.method)
    41 
    42 cdef class IdempotentSemigroupsElement(Element):
     10cdef class IdempotentSemigroupsElementMethods:
    4311    def _pow_(self, i):
    4412        """
    4513        EXAMPLES::
    cdef class IdempotentSemigroupsElement(E 
    6432        return True
    6533
    6634class IdempotentSemigroups(Category):
    67     #@cached_method
    6835    def super_categories(self):
    6936        """
    7037        EXAMPLES::
    class IdempotentSemigroups(Category): 
    7542        """
    7643        return [Semigroups()]
    7744
    78     ElementMethods = IdempotentSemigroupsElement
     45    ElementMethods = IdempotentSemigroupsElementMethods
    7946
    8047
    8148cdef class LeftZeroSemigroupElement(Element):
    class LeftZeroSemigroup(LeftZeroSemigrou 
    179146
    180147    Comments:
    181148
    182     - nested classes seem not to be currently supported by cython
     149    - nested classes seem not to be currently supported by Cython
    183150
    184     - one cannot play ugly use class surgery tricks (as with _mul_parent)
     151    - one cannot play ugly class surgery tricks (as with _mul_parent).
    185152      available operations should really be declared to the coercion model!
    186153
    187154    EXAMPLES::
  • sage/structure/dynamic_class.py

    diff --git a/sage/structure/dynamic_class.py b/sage/structure/dynamic_class.py
    a b an inheritance can be partially emulated 
    119119from sage.misc.cachefunc import weak_cached_function
    120120from sage.structure.unique_representation import ClasscallMetaclass
    121121
    122 def dynamic_class(name, bases, cls = None, reduction = None, doccls=None):
     122def dynamic_class(name, bases, cls = None, reduction = None, doccls = None,
     123                  prepend_cls_bases = True, cache=True):
    123124    r"""
    124125    INPUT:
    125126
    def dynamic_class(name, bases, cls = Non 
    128129    - ``cls`` -- a class or None
    129130    - ``reduction`` -- a tuple or None
    130131    - ``doccls`` -- a class or None
     132    - ``prepend_cls_bases`` -- a boolean (default: True)
     133    - ``cache`` -- a boolean or "ignore_reduction" (default: True)
    131134
    132135    Constructs dynamically a new class ``C`` with name ``name``, and
    133136    bases ``bases``. If ``cls`` is provided, then its methods will be
    134     inserted into ``C`` as well. The module of ``C`` is set from the
    135     module of ``cls`` or from the first base class (``bases`` should
    136     be non empty if ``cls` is ``None``).
     137    inserted into ``C``, and its bases will be prepended to ``bases``
     138    (unless ``prepend_cls_bases`` is False).
    137139
    138     Documentation and source instrospection is taken from ``doccls``, or
    139     ``cls`` if ``doccls`` is ``None``, or ``bases[0]`` if both are ``None``.
     140    The module, documentation and source instrospection is taken from
     141    ``doccls``, or ``cls`` if ``doccls`` is ``None``, or ``bases[0]``
     142    if both are ``None`` (therefore ``bases`` should be non empty if
     143    ``cls` is ``None``).
    140144
    141145    The constructed class can safely be pickled (assuming the
    142146    arguments themselves can).
    143147
    144     The result is cached, ensuring unique representation of dynamic
    145     classes.
     148    Unless ``cache`` is False, the result is cached, ensuring unique
     149    representation of dynamic classes.
    146150
    147151    See :mod:`sage.structure.dynamic_class` for a discussion of the
    148152    dynamic classes paradigm, and its relevance to Sage.
    def dynamic_class(name, bases, cls = Non 
    200204        sage: FooBar.mro()
    201205        [<class '__main__.FooBar'>, <type 'object'>, <class __main__.Bar at ...>]
    202206
     207    .. RUBRIC:: Pickling
     208
    203209    Dynamic classes are pickled by construction. Namely, upon
    204210    unpickling, the class will be reconstructed by recalling
    205211    dynamic_class with the same arguments::
    def dynamic_class(name, bases, cls = Non 
    213219        sage: type(FooBar)
    214220        <class 'sage.structure.dynamic_class.DynamicMetaclass'>
    215221
     222
    216223    The following (meaningless) example illustrates how to customize
    217224    the result of the reduction::
    218225
    def dynamic_class(name, bases, cls = Non 
    222229        sage: loads(dumps(BarFoo))
    223230        '3'
    224231
     232    .. RUBRIC:: Caching
     233
     234    By default, the built class is cached:
     235
     236         sage: dynamic_class("FooBar", (Bar,), Foo) is FooBar
     237         True
     238         sage: dynamic_class("FooBar", (Bar,), Foo, cache=True) is FooBar
     239         True
     240
     241    and the result depends on the reduction::
     242
     243        sage: dynamic_class("BarFoo", (Foo,), Bar, reduction = (str, (3,))) is BarFoo
     244        True
     245        sage: dynamic_class("BarFoo", (Foo,), Bar, reduction = (str, (2,))) is BarFoo
     246        False
     247
     248    With ``cache=False``, a new class is created each time::
     249
     250         sage: FooBar1 = dynamic_class("FooBar", (Bar,), Foo, cache=False); FooBar1
     251         <class '__main__.FooBar'>
     252         sage: FooBar2 = dynamic_class("FooBar", (Bar,), Foo, cache=False); FooBar2
     253         <class '__main__.FooBar'>
     254         sage: FooBar1 is FooBar
     255         False
     256         sage: FooBar2 is FooBar1
     257         False
     258
     259    With ``cache="ignore_reduction"``, the class does not depend on
     260    the reduction::
     261
     262        sage: BarFoo = dynamic_class("BarFoo", (Foo,), Bar, reduction = (str, (3,)), cache="ignore_reduction")
     263        sage: dynamic_class("BarFoo", (Foo,), Bar, reduction = (str, (2,)), cache="ignore_reduction") is BarFoo
     264        True
     265
     266    In particular, the reduction used is that provided upon creating the first class::
     267
     268        sage: dynamic_class("BarFoo", (Foo,), Bar, reduction = (str, (2,)), cache="ignore_reduction")._reduction
     269        (<type 'str'>, (3,))
     270
     271    .. WARNING::
     272
     273        The behaviour upon creating several dynamic classes from the
     274        same data but with different values for ``cache`` option is
     275        currently left unspecified. In other words, for a given
     276        application, it is recommended to consistently use the same
     277        value for that option.
     278
    225279    TESTS::
    226280
    227281        sage: import __main__
    def dynamic_class(name, bases, cls = Non 
    254308    #assert(len(bases) > 0 )
    255309    assert(type(name) is str)
    256310    #    assert(cls is None or issubtype(type(cls), type) or type(cls) is classobj)
    257     return dynamic_class_internal(name, bases, cls, reduction, doccls)
     311    if cache is True:
     312        return dynamic_class_internal(name, bases, cls, reduction, doccls, prepend_cls_bases)
     313    elif cache is False:
     314        # bypass the cached method
     315        return dynamic_class_internal.f(name, bases, cls, reduction, doccls, prepend_cls_bases)
     316    else: # cache = "ignore_reduction"
     317        result = dynamic_class_internal(name, bases, cls, False, doccls, prepend_cls_bases)
     318        if result._reduction is False:
     319            result._reduction = reduction
     320        return result
     321
    258322
    259323@weak_cached_function
    260 def dynamic_class_internal(name, bases, cls = None, reduction = None, doccls = None):
     324def dynamic_class_internal(name, bases, cls = None, reduction = None, doccls = None, prepend_cls_bases=True):
    261325    r"""
    262326    See sage.structure.dynamic_class.dynamic_class? for indirect doctests.
    263327
    def dynamic_class_internal(name, bases,  
    309373        # Anything else that should not be kept?
    310374        if methods.has_key("__dict__"):
    311375            methods.__delitem__("__dict__")
    312         bases = cls.__bases__ + bases
     376        if prepend_cls_bases:
     377            bases = cls.__bases__ + bases
    313378    else:
    314379        methods = {}
    315380    if doccls is None: