Ticket #5979: parent-element_constructor-fix-5979-submitted.patch

File parent-element_constructor-fix-5979-submitted.patch, 4.1 KB (added by Nicolas M. Thiéry, 14 years ago)
  • sage/structure/coerce_maps.pyx

    # HG changeset patch
    # User Nicolas M. Thiery <nthiery@users.sf.net>
    # Date 1241455730 25200
    # Node ID 9b261cc69cc74c6730d3a20a8aaf026784f1cde4
    # Parent  b2fb9f8a5e257c9b2e6f295025c3e6de8bac4d71
    #5979 Parent: fixes broken (implicit) invariant between ._element_constructor and self._element_init_pass_parent
    
    In Parent, there is a (previously implicit) invariant, namely that:
    
    	self._element_init_pass_parent == guess_pass_parent(between ._element_constructor)
    
    This invariant was broken when self._element_constructor was set from
    self._element_constructor_ by __call__. This made the parent not to be
    passed properly to _element_constructor.
    
    The category patch #5891 depends heavily on this one, as this way of
    setting _element_constructor becomes the default one for simple
    parents.
    
    By the way, this patch makes a related trivial fix to a line that is
    apparently never used in coerce_maps, and adds a comment about it.
    
    diff --git a/sage/structure/coerce_maps.pyx b/sage/structure/coerce_maps.pyx
    a b cdef class DefaultConvertMap(Map): 
    4444        try:
    4545            if len(args) == 0:
    4646                if len(kwds) == 0:
    47                     return self._codomain.__element_constructor(self._codomain, x)
     47                    # This line is apparently never used in any tests (hivert, 2009-04-28)
     48                    return self._codomain._element_constructor(self._codomain, x)
    4849                else:
    4950                    return self._codomain._element_constructor(self._codomain, x, **kwds)
    5051            else:
  • sage/structure/parent.pyx

    diff --git a/sage/structure/parent.pyx b/sage/structure/parent.pyx
    a b cdef class Parent(category_object.Catego 
    124124    """
    125125    Parents are the Sage/mathematical analogues of container objects
    126126    in computer science.
     127
     128    Internal invariants:
     129     - self._element_init_pass_parent == guess_pass_parent(self, self._element_constructor)
     130       Ensures that self.__call__ passes down the parent properly to self._element_constructor.
     131       See #5979.
     132
    127133    """
    128134   
    129135    def __init__(self, base=None, *, categories=[], element_constructor=None, gens=None, names=None, normalize=True, **kwds):
    cdef class Parent(category_object.Catego 
    258264        By default this will dispatch as quickly as possible to
    259265        :meth:`_element_constructor_` though faster pathways are
    260266        possible if so desired.
     267
     268        TESTS:
     269
     270        We check that the invariant::
     271
     272                self._element_init_pass_parent == guess_pass_parent(self, self._element_constructor)
     273
     274        is preserved (see #5979)::
     275
     276            sage: class MyParent(Parent):
     277            ...       def _element_constructor_(self, x):
     278            ...           print self, x
     279            ...           return sage.structure.element.Element(parent = self)
     280            ...       def _repr_(self):
     281            ...           return "my_parent"
     282            ...
     283            sage: my_parent = MyParent()
     284            sage: x = my_parent("bla")
     285            my_parent bla
     286            sage: x.parent()         # indirect doctest
     287            my_parent
     288
     289            sage: x = my_parent()    # shouldn't this one raise an error?
     290            my_parent 0
     291            sage: x = my_parent(3)   # todo: not implemented  why does this one fail???
     292            my_parent 3
     293
     294
    261295        """
    262296        if self._element_constructor is None:
    263297            # Neither __init__ nor _populate_coercion_lists_ have been called...
    264298            try:
    265299                assert callable(self._element_constructor_)
    266300                self._element_constructor = self._element_constructor_
     301                self._element_init_pass_parent = guess_pass_parent(self, self._element_constructor)
    267302            except (AttributeError, AssertionError):
    268303                raise NotImplementedError
    269304        cdef Py_ssize_t i
    cdef class Parent(category_object.Catego 
    675710          is useful if parents are unique, or element_constructor is a
    676711          bound method (this latter case can be detected
    677712          automatically).
     713
     714
    678715        """
    679716        self.init_coerce(False)
    680717