Changeset 513

Show
Ignore:
Timestamp:
11/09/09 21:10:55 (4 years ago)
Author:
ged
Message:

- do not leak options_defaults from a subclass into a parent class
- do not initialize useless attributes for base and abstract classes

Location:
elixir/trunk
Files:
3 modified

Legend:

Unmodified
Added
Removed
  • elixir/trunk/elixir/entity.py

    r512 r513  
    4848    def __init__(self, entity): 
    4949        self.entity = entity 
    50         # entity.__module__ is not always reliable (eg in mod_python) 
    51         self.module = sys.modules.get(entity.__module__) 
    52  
    53         self.builders = [] 
    54  
    5550        self.parent = None 
    56         #XXX: use entity.__subclasses__ ? 
    57         self.children = [] 
    5851 
    5952        bases = [] 
     
    7366                    bases.append(base) 
    7467        self.bases = bases 
    75  
    76         if not is_entity(entity): 
     68        if not is_entity(entity) or is_abstract_entity(entity): 
    7769            return 
     70 
     71        # entity.__module__ is not always reliable (eg in mod_python) 
     72        self.module = sys.modules.get(entity.__module__) 
     73 
     74        self.builders = [] 
     75 
     76        #XXX: use entity.__subclasses__ ? 
     77        self.children = [] 
    7878 
    7979        # used for multi-table inheritance 
     
    9898 
    9999        # base class(es) options_defaults 
    100         base_defaults = {} 
    101         for base in self.bases: 
    102             base_defaults.update(getattr(base, 'options_defaults', {})) 
     100        options_defaults = self.options_defaults() 
    103101 
    104102        complete_defaults = options.options_defaults.copy() 
     
    111109        # set default value for other options 
    112110        for key in options.valid_options: 
    113             value = base_defaults.get(key, complete_defaults[key]) 
     111            value = options_defaults.get(key, complete_defaults[key]) 
    114112            if isinstance(value, dict): 
    115113                value = value.copy() 
     
    121119            if hasattr(self.module, attr): 
    122120                setattr(self, key, getattr(self.module, attr)) 
     121 
     122    def options_defaults(self): 
     123        base_defaults = {} 
     124        for base in self.bases: 
     125            base_defaults.update(base._descriptor.options_defaults()) 
     126        base_defaults.update(getattr(self.entity, 'options_defaults', {})) 
     127        return base_defaults 
    123128 
    124129    def setup_options(self): 
  • elixir/trunk/elixir/options.py

    r511 r513  
    242242            raise Exception("'%s' is not a valid option for Elixir entities." 
    243243                            % kwarg) 
    244     if not hasattr(entity, 'options_defaults'): 
     244 
     245    # We use __dict__ instead of hasattr to not check its presence within the 
     246    # parent, and thus update the parent dict instead of creating a local dict. 
     247    if not entity.__dict__.get('options_defaults'): 
    245248        entity.options_defaults = {} 
    246249    entity.options_defaults.update(kwargs) 
  • elixir/trunk/tests/test_abstract.py

    r512 r513  
    3333        class AbstractPerson(Entity): 
    3434            using_options(abstract=True) 
     35            using_options_defaults(tablename=camel_to_underscore) 
    3536 
    3637            firstname = Field(String(30)) 
    3738            lastname = Field(String(30)) 
    3839 
    39         class AbstractEmployed(AbstractPerson): 
     40        class AbstractEmployee(AbstractPerson): 
    4041            using_options(abstract=True) 
     42            using_options_defaults(identity=camel_to_underscore) 
    4143 
    4244            corporation = Field(String(30)) 
    4345 
    44         class Employed(AbstractEmployed): 
     46        class ConcreteEmployee(AbstractEmployee): 
    4547            service = Field(String(30)) 
    4648 
    47         class Citizen(AbstractPerson): 
     49        class ConcreteCitizen(AbstractPerson): 
    4850            country = Field(String(30)) 
    4951 
     
    5153 
    5254        assert not hasattr(AbstractPerson, 'table') 
    53         assert not hasattr(AbstractEmployed, 'table') 
    54         assert hasattr(Employed, 'table') 
    55         assert hasattr(Citizen, 'table') 
     55        assert not hasattr(AbstractEmployee, 'table') 
     56        assert hasattr(ConcreteEmployee, 'table') 
     57        assert hasattr(ConcreteCitizen, 'table') 
     58        assert ConcreteEmployee.table.name == 'concrete_employee' 
     59        assert ConcreteCitizen.table.name == 'concrete_citizen' 
    5660 
    57         assert 'firstname' in Employed.table.columns 
    58         assert 'lastname' in Employed.table.columns 
    59         assert 'corporation' in Employed.table.columns 
    60         assert 'service' in Employed.table.columns 
     61        assert 'firstname' in ConcreteEmployee.table.columns 
     62        assert 'lastname' in ConcreteEmployee.table.columns 
     63        assert 'corporation' in ConcreteEmployee.table.columns 
     64        assert 'service' in ConcreteEmployee.table.columns 
    6165 
    62         assert 'firstname' in Citizen.table.columns 
    63         assert 'lastname' in Citizen.table.columns 
    64         assert 'corporation' not in Citizen.table.columns 
    65         assert 'country' in Citizen.table.columns 
     66        assert 'firstname' in ConcreteCitizen.table.columns 
     67        assert 'lastname' in ConcreteCitizen.table.columns 
     68        assert 'corporation' not in ConcreteCitizen.table.columns 
     69        assert 'country' in ConcreteCitizen.table.columns 
     70        # test that the options_defaults do not leak into the parent base 
     71        assert ConcreteCitizen._descriptor.identity == 'concretecitizen' 
    6672 
    6773    def test_simple_relation(self): 
     
    166172            using_options(inheritance='multi') 
    167173 
    168         class DatedContact(AbstractDated, Contact): 
     174        class MixedDatedContact(AbstractDated, Contact): 
    169175            using_options(inheritance='multi') 
    170176 
    171177        setup_all(True) 
    172178 
    173         assert 'created_date' in DatedContact.table.columns 
    174         assert 'modified_date' in DatedContact.table.columns 
    175         assert DatedContact._descriptor.identity == 'dated_contact' 
    176         assert DatedContact.table.name == 'dated_contact' 
     179        assert 'created_date' in MixedDatedContact.table.columns 
     180        assert 'modified_date' in MixedDatedContact.table.columns 
     181        assert MixedDatedContact._descriptor.identity == 'mixed_dated_contact' 
     182        assert MixedDatedContact.table.name == 'mixed_dated_contact' 
    177183 
    178         contact1 = DatedContact(first_name=u"Guido", last_name=u"van Rossum") 
     184        contact1 = MixedDatedContact(first_name=u"Guido", 
     185                                     last_name=u"van Rossum") 
    179186        session.commit() 
    180187 
     188