orderedstuf fails where stuf works

Issue #1 resolved
Jonathan Eunice created an issue

I created a simple subclass of stuf. It works fine. But when I tried to base it on orderedstuf instead (in order to print the fields in a more attractive and comprehensible order), it fails spectacularly.

from stuf import stuf, orderedstuf

class User(stuf):

    def __init__(self, **kwargs):
        self.name  = kwargs.get('name',  None)
        self.email = kwargs.get('email', None)

print User(name='Joe')

class OUser(orderedstuf):

    def __init__(self, **kwargs):
        self.name  = kwargs.get('name',  None)
        self.email = kwargs.get('email', None)

print OUser(name='Moe')

Result:

User([('name', 'Joe'), ('email', None)])
Traceback (most recent call last):
  File "/Users/jeunice/pytest/pypi/wtest.py", line 74, in <module>
    print OUser(name='Moe')
  File "/Users/jeunice/pytest/pypi/wtest.py", line 71, in __init__
    self.name  = kwargs.get('name',  None)
  File "/Library/Python/2.7/site-packages/stuf/_core.py", line 59, in __setattr__
    self[key] = value
  File "/Library/Python/2.7/site-packages/stuf/desc.py", line 36, in __get__
    return self if this is None else self._set(this)
  File "/Library/Python/2.7/site-packages/stuf/desc.py", line 28, in _set
    return setter(this, self.name, self.method(this))

  ... hundreds of repetitive lines omitted...

  File "/Library/Python/2.7/site-packages/stuf/desc.py", line 36, in __get__
    return self if this is None else self._set(this)
  File "/Library/Python/2.7/site-packages/stuf/desc.py", line 28, in _set
    return setter(this, self.name, self.method(this))
  File "/Library/Python/2.7/site-packages/stuf/_core.py", line 136, in __getitem__
    return getitem(self)
  File "/Library/Python/2.7/site-packages/stuf/_core.py", line 27, in __getattr__
    if key == 'iteritems':
RuntimeError: maximum recursion depth exceeded in cmp

Comments (6)

  1. Lynn Rees repo owner

    You need to call super i.e.:

    from stuf import stuf, orderedstuf
    
    class User(stuf):
    
        def __init__(self, **kwargs):
            self.name  = kwargs.get('name',  None)
            self.email = kwargs.get('email', None)
    
    print User(name='Joe')
    
    class OUser(orderedstuf):
    
        def __init__(self, **kwargs):
            super(OUser, self).__init__(**kwargs)
            self.name  = kwargs.get('name',  None)
            self.email = kwargs.get('email', None)
    
    print OUser(name='Moe')
    
  2. Jonathan Eunice reporter

    I accept "you need to call superclass initializer, doofus!" as a proper solution. DUH.

    I should be doing the same thing for User. Not doing so is sloppy. But as a teaching moment, any insight why only the first one squeaks by? I'm not seeing it.

    FWIW, the final cleaned-up code follows.

    from stuf import stuf, orderedstuf
    from say import say
    
    class User(stuf):
    
        def __init__(self, **kwargs):
            super(User, self).__init__(**kwargs)
            self.setdefault('name', None)
            self.setdefault('email', None)
    
    say> User(name='Joe')
    
    class OUser(orderedstuf):
    
        def __init__(self, **kwargs):
            super(OUser, self).__init__()
            self.name  = kwargs.get('name',  None)
            self.email = kwargs.get('email', None)
    
    say> OUser(name='Moe')
    

    yields the proper result on both Python 2.7 and 3.3:

    User(name='Joe', email=None)
    OUser(name='Moe', email=None)
    
  3. Lynn Rees repo owner

    orderedstuf inherits from wrapstuf, which has to initialize a _wrapped variable in its __init__. Unless super is called, that __init__ doesn't get called and _wrapped doesn't get initialized leading to the infinite loop as the object looks for a _wrapped variable that's never there.

    When orderedstuf was originally coded, subclassing OrderedDict was a pain. I vaguely recall the rationale for this was because its author (probably Raymond Hettinger) believed forcing reimplemention of key methods in a subclass leads to better inheritance hierarchies. Since I wanted a minimal implementation, orderedstuf wraps OrderedDict rather than subclassing it. It stores the wrapped OrderedDict in the _wrapped variable. Depending upon if arguments are passed to the class constructor, the OrderedDict can be empty or populated. The _mapping class variable points to the type of data structure being mapped, in this case OrderedDict.

  4. Log in to comment