Changeset 284

Show
Ignore:
Timestamp:
12/17/07 12:22:12 (7 years ago)
Author:
ged
Message:
  • added support for custom base classes which inherit from another class (ie
    not directly from object)
  • added check so that using an inexisting column in an order_by or other
    column-name based argument raises an exception.
  • fixed bug in setup_entities (it always used the global entity list and not
    the list given as argument).
Location:
elixir/trunk
Files:
2 modified

Legend:

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

    r279 r284  
    8282        self.builders = [] 
    8383 
     84        self.is_base = is_base(entity) 
    8485        self.parent = None 
    8586        self.children = [] 
    8687 
    8788        for base in entity.__bases__: 
    88             if isinstance(base, EntityMeta) and not base.__bases__[0] is object: 
     89            if isinstance(base, EntityMeta) and not is_base(base): 
    8990                if self.parent: 
    9091                    raise Exception('%s entity inherits from several entities,' 
     
    252253                    self.parent._descriptor.add_constraint(constraint) 
    253254                return 
    254             elif self.inheritance == 'concrete': 
     255            elif self.inheritance == 'concrete':  
     256                #TODO: we should also copy columns from the parent table if the 
     257                # parent is a base entity (whatever the inheritance type -> elif 
     258                # will need to be changed) 
    255259                # copy all columns from parent table 
    256260                for col in self.parent._descriptor.columns: 
     
    438442            check_duplicate = not self.allowcoloverride 
    439443         
    440         if check_duplicate and self.get_column(col.key) is not None: 
     444        if check_duplicate and self.get_column(col.key, False) is not None: 
    441445            raise Exception("Column '%s' already exist in '%s' ! " %  
    442446                            (col.key, self.entity.__name__)) 
     
    481485        self.mapper_options['extension'] = extensions 
    482486 
    483     def get_column(self, key): 
     487    def get_column(self, key, check_missing=True): 
    484488        "need to support both the case where the table is already setup or not" 
    485489        #TODO: support SA table/autoloaded entity 
     
    487491            if col.key == key: 
    488492                return col 
     493        if check_missing: 
     494            raise Exception("No column named '%s' found in the table of the " 
     495                            "'%s' entity!" % (key, self.entity.__name__)) 
    489496        return None 
    490497 
     
    531538            return self.entity.table.columns 
    532539        else: 
     540            #FIXME: depending on the type of inheritance, we should also  
     541            # return the parent entity's columns (for example for order_by  
     542            # using a column defined in the parent. 
    533543            return self._columns 
    534544    columns = property(columns) 
     
    581591        return getattr(owner, self.attrname) 
    582592 
     593def is_base(cls): 
     594    """ 
     595    Scan bases classes to see if any is an instance of EntityMeta. If we 
     596    don't find any, it means the current entity is a base class (like  
     597    the 'Entity' class). 
     598    """ 
     599    for base in cls.__bases__: 
     600        if isinstance(base, EntityMeta): 
     601            return False 
     602    return True 
    583603 
    584604class EntityMeta(type): 
    585605    """ 
    586606    Entity meta class.  
    587     You should only use this if you want to define your own base class for your 
    588     entities (ie you don't want to use the provided 'Entity' class). 
     607    You should only use it directly if you want to define your own base class  
     608    for your entities (ie you don't want to use the provided 'Entity' class). 
    589609    """ 
    590610    _entities = {} 
    591611 
    592612    def __init__(cls, name, bases, dict_): 
    593         # only process subclasses of Entity, not Entity itself 
    594         if bases[0] is object: 
     613        # Only process further subclasses of the base classes (Entity et al.), 
     614        # not the base classes themselves. We don't want the base entities to  
     615        # be registered in an entity collection, nor to have a table name and  
     616        # so on.  
     617        if is_base(cls): 
    595618            return 
    596619 
     
    621644            prop.attach(cls, name) 
    622645 
    623         # process mutators. Needed before setup_proxy for metadata 
     646        # Process mutators. Needed before _install_autosetup_triggers so that 
     647        # we know of the metadata 
    624648        process_mutators(cls) 
    625649 
     
    710734    '''Setup all entities in the list passed as argument''' 
    711735 
    712     for entity in elixir.entities: 
     736    for entity in entities: 
    713737        if entity._descriptor.autosetup: 
    714738            _cleanup_autosetup_triggers(entity) 
     
    783807    ''' 
    784808    __metaclass__ = EntityMeta 
    785  
     809     
    786810    def __init__(self, **kwargs): 
    787811        for key, value in kwargs.items(): 
  • elixir/trunk/tests/test_custombase.py

    r279 r284  
    5151         
    5252        assert b.data == '-b1-' 
     53 
     54    def test_non_object_base(self): 
     55        class BaseParent(object): 
     56            def test(self): 
     57                return "success" 
     58 
     59        class InheritedBase(BaseParent): 
     60            __metaclass__ = EntityMeta 
     61 
     62        class A(InheritedBase): 
     63            name = Field(String(30)) 
     64 
     65        setup_all(True) 
     66         
     67        a1 = A(name="a1") 
     68         
     69        session.flush() 
     70        session.clear() 
     71         
     72        a = A.query.filter_by(name="a1").one() 
     73         
     74        assert a.name == 'a1' 
     75        assert a.test() == "success" 
     76