Contact: fumanchu@aminus.org

Log in as guest/dejavu to create tickets

Changeset 188

Show
Ignore:
Timestamp:
03/07/06 17:32:23
Author:
fumanchu
Message:

Fix for #48 (unitclass.identifiers should be strings, not property instances).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/arenas.py

    r187 r188  
    227227                        # Allow identifiers to be supplied as args or kwargs 
    228228                        # (since the common case will be a single identifier). 
    229                         for arg, id in zip(args, cls.identifiers): 
    230                             kwargs[str(id.key)] = arg 
     229                        for arg, key in zip(args, cls.identifiers): 
     230                            kwargs[str(key)] = arg 
    231231                        expr = logic.filter(**kwargs) 
    232232                        try: 
     
    437437        indices = [] 
    438438        added_fields = 0 
    439         for prop in cls.identifiers: 
    440             if prop.key not in fields: 
     439        for key in cls.identifiers: 
     440            if key not in fields: 
    441441                added_fields += 1 
    442                 fields.append(prop.key) 
    443             indices.append(fields.index(prop.key)) 
     442                fields.append(key) 
     443            indices.append(fields.index(key)) 
    444444         
    445445        for row in self.arena.storage(cls).view(cls, fields, expr): 
     
    482482    def count(self, cls, expr): 
    483483        """count(cls, expr) -> Number of Units of class 'cls'.""" 
    484         idnames = [prop.key for prop in cls.identifiers] 
    485         return len(self.distinct(cls, idnames, expr)) 
     484        return len(self.distinct(cls, cls.identifiers, expr)) 
    486485     
    487486    #################################### 
  • trunk/doc/managing.html

    r187 r188  
    277277 
    278278<h4>Collections: Lists of Units</h4> 
    279 <p>The <tt>UnitCollection</tt> class provides a means of storing a list 
    280 of Units, or rather, a list of Unit identifiers. You use its <tt>Type</tt> 
     279<p>The <tt>UnitCollection</tt> class provides a means of storing a list of 
     280Units, or rather, a list of Unit identifier values. You use its <tt>Type</tt> 
    281281property to indicate the class of the indexed Units. That value should be 
    282282the <b>name</b> of the Unit Class, <b>not</b> the class object itself 
     
    296296 
    297297<p>When you need to retrieve the actual Units which are indexed by the 
    298 Collection, call the <tt class='def'>units(quota=None)</tt> method, 
    299 which will 
    300 look up the Units and return them in a list. Since the Collection only 
    301 stores identifiers, it is possible that one of the indexed Units may have 
     298Collection, call the <tt class='def'>units(quota=None)</tt> method, which 
     299will look up the Units and return them in a list. Since the Collection only 
     300stores identifier values, it is possible that one of the indexed Units may have 
    302301been destroyed since the list was built. The <tt>units</tt> method simply 
    303302passes over these "phantom" Units. You can inspect the full list of IDs 
  • trunk/doc/modeling.html

    r187 r188  
    6868<h4>Unit ID's</h4> 
    6969<p>All Units possess an <tt>identifiers</tt> attribute, a tuple of 
    70 their UnitProperties which define the uniqueness of a Unit. The 
     70their UnitProperties names which define the uniqueness of a Unit. The 
    7171<tt>Unit</tt> base class possesses a single Unit Property, an int 
    7272named 'ID', and its <tt>identifiers</tt> attribute is therefore 
    73 <tt>(ID,)</tt>. That's not a string in the tuple; it's a reference 
    74 to the actual UnitProperty class. If you wish to use identifiers 
     73<tt>('ID',)</tt>. That's a string in the tuple; older versions of Dejavu 
     74used a reference to the actual UnitProperty class instead. If you wish 
     75to use identifiers 
    7576of a different number, types, or names, simply replace the 
    7677<tt>identifiers</tt> attribute in your subclass:</p> 
     
    8283    Model = UnitProperty(unicode) 
    8384    UnitNumber = UnitProperty(int) 
    84     identifiers = (Model, UnitNumber
     85    identifiers = ('Model', 'UnitNumber'
    8586</pre> 
    8687 
     
    329330to help Sandboxes generate new IDs. The default value is an instance of 
    330331<tt>UnitSequencerInteger</tt>, which examines all existing Units, finds 
    331 the maximum integer ID, adds 1, and uses that value for the new ID.</p> 
     332the maximum integer ID, adds 1, and uses that value for the new ID. 
     333[StorageManagers are free to optimize any sequencer, whether builtin or 
     334custom, in order to take advantage of ID-generation tools in the database 
     335or other storage provider. All builtin database StorageManagers optimize 
     336UnitSequencerInteger in this way.]</p> 
    332337 
    333338<p>The other useful Sequencer is <tt>UnitSequencerNull</tt>, which simply 
     
    562567 
    563568<p>The <tt>distinct</tt> function can also be used as a <tt>count</tt> 
    564 function by passing <tt>attrs = [prop.key for prop in cls.identifiers]</tt>. 
     569function by passing <tt>attrs = cls.identifiers</tt>. 
    565570Sandboxes provide a <tt class='def'>count(cls, expr)</tt> method which does 
    566571just this.</p> 
  • trunk/engines.py

    r187 r188  
    126126    def units(self, quota=None): 
    127127        cls = self.unit_class() 
    128         idnames = [prop.key for prop in cls.identifiers] 
    129128         
    130129        output = [] 
     
    134133                if quota and i >= quota: 
    135134                    break 
    136                 unit = self.sandbox.unit(cls, **dict(zip(idnames, eachID))) 
     135                filter = dict(zip(cls.identifiers, eachID)) 
     136                unit = self.sandbox.unit(cls, **filter) 
    137137                if unit: 
    138138                    output.append(unit) 
     
    491491            else: 
    492492                newset = [] 
    493                 idnames = [prop.key for prop in cls.identifiers] 
    494493                for id in mem: 
    495                     unit = self.sandbox.unit(cls, **dict(zip(idnames, id))) 
     494                    filter = dict(zip(cls.identifiers, id)) 
     495                    unit = self.sandbox.unit(cls, **filter) 
    496496                    if unit and expr(unit): 
    497497                        newset.append(id) 
     
    584584                    A.universal = False 
    585585                else: 
    586                     idnames = [prop.key for prop in cls.identifiers] 
    587586                    for id in A.Members: 
    588                         unit = self.sandbox.unit(cls, **dict(zip(idnames, id))) 
     587                        filter = dict(zip(cls.identifiers, id)) 
     588                        unit = self.sandbox.unit(cls, **filter) 
    589589                        if unit: 
    590590                            farUnits = ua.__get__(unit)() 
  • trunk/storage/__init__.py

    r187 r188  
    311311                indices = [] 
    312312                added_fields = 0 
    313                 for prop in cls.identifiers: 
    314                     if prop.key not in fields: 
    315                         fields.append(prop.key) 
     313                for key in cls.identifiers: 
     314                    if key not in fields: 
     315                        fields.append(key) 
    316316                        added_fields += 1 
    317                     indices.append(fields.index(prop.key)) 
     317                    indices.append(fields.index(key)) 
    318318                 
    319319                for row in self.nextstore.view(cls, fields, expr): 
  • trunk/storage/db.py

    r187 r188  
    746746        # Place the identifier properties first 
    747747        # in case others depend upon them. 
    748         idnames = [prop.key for prop in wclass.identifiers] 
    749         keys = idnames + [k for k in wclass.properties() if k not in idnames] 
     748        keys = list(wclass.identifiers) + [k for k in wclass.properties() 
     749                                           if k not in wclass.identifiers] 
    750750        cols = [(wclass, k) for k in keys] 
    751751        colnames = ['%s.%s' % (self.alias or self.tablename, 
     
    10051005            # See load_expanded, for example. 
    10061006            props = [] 
    1007             idnames = [prop.key for prop in cls.identifiers] 
     1007            idnames = list(cls.identifiers) 
    10081008            for key in idnames + [x for x in cls.properties() if x not in idnames]: 
    10091009                index, ftype = columns[self.column_name(clsname, key, quoted=False)] 
     
    10531053        if not unit.sequencer.valid_id(unit.identity()): 
    10541054            # Examine all existing IDs and grant the "next" one. 
    1055             id_fields = [self.column_name(clsname, prop.key) 
    1056                          for prop in cls.identifiers] 
     1055            id_fields = [self.column_name(clsname, key) 
     1056                         for key in cls.identifiers] 
    10571057            data, cols = self.fetch('SELECT %s FROM %s;' % 
    10581058                                    (', '.join(id_fields), tablename)) 
     
    10611061                coerce = self.fromAdapter.coerce 
    10621062                coltypes = [cols[x][1] for x in xrange(len(cols))] 
    1063                 expectedTypes = [prop.type for prop in cls.identifiers] 
     1063                expectedTypes = [getattr(cls, key).type 
     1064                                 for key in cls.identifiers] 
    10641065                newdata = [] 
    10651066                for row in data: 
     
    10951096        col = self.column_name 
    10961097        c = self.toAdapter.coerce 
    1097         idnames = [prop.key for prop in unit.identifiers] 
    10981098        return " AND ".join(["%s = %s" % (col(clsname, key), 
    10991099                                          c(getattr(unit, key))) 
    1100                              for key in idnames]) 
     1100                             for key in unit.identifiers]) 
    11011101     
    11021102    def save(self, unit, forceSave=False): 
     
    11071107             
    11081108            parms = [] 
    1109             idnames = [prop.key for prop in cls.identifiers] 
    11101109            for key in cls.properties(): 
    1111                 if key not in idnames: 
     1110                if key not in cls.identifiers: 
    11121111                    subtype = self.expanded_columns.get((clsname, key)) 
    11131112                    if subtype: 
  • trunk/storage/storeado.py

    r187 r188  
    501501        prop = getattr(cls, key) 
    502502        if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 
    503             if prop in cls.identifiers: 
     503            if key in cls.identifiers: 
    504504                return ("INTEGER IDENTITY(%s, 1) NOT NULL" 
    505505                        % cls.sequencer.initial) 
     
    582582        data, col_defs = self.fetch("SELECT IDENT_CURRENT('%s');" 
    583583                                    % str(tablename)) 
    584         setattr(unit, cls.identifiers[0].key, data[0][0]) 
     584        setattr(unit, cls.identifiers[0], data[0][0]) 
    585585         
    586586        # Now that we have an ID, save our expanded tables. 
     
    710710        prop = getattr(cls, key) 
    711711        if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 
    712             if prop in cls.identifiers: 
     712            if key in cls.identifiers: 
    713713                return "AUTOINCREMENT(%s, 1)" % cls.sequencer.initial 
    714714        bytes = int(prop.hints.get('bytes', '4')) 
     
    721721        prop = getattr(cls, key) 
    722722        if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 
    723             if prop in cls.identifiers: 
     723            if key in cls.identifiers: 
    724724                return "AUTOINCREMENT(%s, 1)" % cls.sequencer.initial 
    725725        bytes = int(prop.hints.get('bytes', 0)) 
     
    818818        # Grab the new ID. This is threadsafe because db.reserve has a mutex. 
    819819        data, col_defs = self.fetch("SELECT @@IDENTITY;") 
    820         setattr(unit, cls.identifiers[0].key, data[0][0]) 
     820        setattr(unit, cls.identifiers[0], data[0][0]) 
    821821         
    822822        # Now that we have an ID, save our expanded tables. 
  • trunk/storage/storemysql.py

    r187 r188  
    125125            typename = "INTEGER" 
    126126        if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 
    127             if prop in cls.identifiers: 
     127            if key in cls.identifiers: 
    128128                typename += " AUTO_INCREMENT" 
    129129        return typename 
     
    246246        # Grab the new ID. This is threadsafe because db.reserve has a mutex. 
    247247        data, col_defs = self.fetch("SELECT LAST_INSERT_ID();") 
    248         setattr(unit, cls.identifiers[0].key, data[0][0]) 
     248        setattr(unit, cls.identifiers[0], data[0][0]) 
    249249         
    250250        # Now that we have an ID, save our expanded tables. 
     
    278278            dbtype = typename(cls, key) 
    279279            fields.append('%s %s' % (qname, dbtype)) 
    280             if getattr(cls, key) in cls.identifiers: 
     280            if key in cls.identifiers: 
    281281                if dbtype.endswith('BLOB') or dbtype == 'TEXT': 
    282282                    # MySQL won't allow indexes on a BLOB field 
     
    298298                # can't delete it until after the CREATE INDEX 
    299299                # statements below (or the counter will revert). 
    300                 colname = self.column_name(clsname, cls.identifiers[0].key
     300                colname = self.column_name(clsname, cls.identifiers[0]
    301301                self.execute("INSERT INTO %s (%s) VALUES (%s);" 
    302302                             % (tablename, colname, i - 1)) 
  • trunk/storage/storepypgsql.py

    r187 r188  
    1616        prop = getattr(cls, key) 
    1717        if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 
    18             if prop in cls.identifiers: 
     18            if key in cls.identifiers: 
    1919                return ("INTEGER DEFAULT nextval('%s_%s_seq') NOT NULL" 
    2020                        % (cls.__name__, key)) 
     
    148148        # Grab the new ID. This is threadsafe because db.reserve has a mutex. 
    149149        data, col_defs = self.fetch("SELECT last_value FROM %s_%s_seq;" 
    150                                     % (clsname, cls.identifiers[0].key)) 
    151         setattr(unit, cls.identifiers[0].key, data[0][0]) 
     150                                    % (clsname, cls.identifiers[0])) 
     151        setattr(unit, cls.identifiers[0], data[0][0]) 
    152152         
    153153        # Now that we have an ID, save our expanded tables. 
  • trunk/storage/storeshelve.py

    r187 r188  
    9191        try: 
    9292            if not unit.sequencer.valid_id(unit.identity()): 
    93                 ids = [[row[prop.key] for prop in unit.identifiers] 
     93                ids = [[row[key] for key in unit.identifiers] 
    9494                       for row in data.itervalues()] 
    9595                unit.sequencer.assign(unit, ids) 
  • trunk/storage/storesqlite.py

    r187 r188  
    139139        if _autoincrement_support: 
    140140            prop = getattr(cls, key, None) 
    141             if prop and prop.type is int and prop in cls.identifiers: 
     141            if prop and prop.type is int and key in cls.identifiers: 
    142142                if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 
    143143                    return "INTEGER PRIMARY KEY AUTOINCREMENT" 
     
    308308        # Grab the new ID. This is safe because db.reserve has a mutex. 
    309309        new_id = conn.sqlite_last_insert_rowid() 
    310         setattr(unit, cls.identifiers[0].key, new_id) 
     310        setattr(unit, cls.identifiers[0], new_id) 
    311311         
    312312        # Now that we have an ID, save our expanded tables. 
  • trunk/test/zoo_fixture.py

    r187 r188  
    116116    ID = None 
    117117    sequencer = dejavu.UnitSequencerNull() 
    118     identifiers = (ZooID, Name) 
     118    identifiers = ("ZooID", Name) 
    119119 
    120120Zoo.one_to_many('ID', Exhibit, 'ZooID') 
  • trunk/units.py

    r187 r188  
    245245            if m != (None,): 
    246246                newvalue = m[0] + 1 
    247         unit.identifiers[0].__set__(unit, newvalue) 
     247        setattr(unit, unit.identifiers[0], newvalue) 
    248248 
    249249 
     
    281281                                    % self.width) 
    282282            newvalue = maxid 
    283         unit.identifiers[0].__set__(unit, newvalue) 
     283        setattr(unit, unit.identifiers[0], newvalue) 
    284284 
    285285 
     
    412412        cls._properties = props 
    413413        cls._associations = assocs 
     414         
     415        # Keep backward compatibility from 1.4 to 1.5. See ticket #48. 
     416        ident = dct.get('identifiers', ()) 
     417        if ident: 
     418            newident = [] 
     419            for val in ident: 
     420                if isinstance(val, UnitProperty): 
     421                    # Substitute the name for the property 
     422                    val = val.key 
     423                newident.append(val) 
     424            cls.identifiers = tuple(newident) 
    414425     
    415426    def __lshift__(self, other): 
     
    487498    ID = UnitProperty(int, index=True) 
    488499    sequencer = UnitSequencerInteger() 
    489     identifiers = (ID,) 
     500    identifiers = ("ID",) 
    490501     
    491502    def __init__(self, **kwargs): 
     
    514525    def __copy__(self): 
    515526        newUnit = self.__class__() 
    516         for key in self.__class__.properties(): 
    517             if key not in self.identifiers: 
     527        for key, prop in self.__class__._properties.iteritems(): 
     528            if key in self.identifiers: 
     529                newUnit._properties[key] = prop.default 
     530            else: 
    518531                newUnit._properties[key] = self._properties[key] 
    519         for prop in self.identifiers: 
    520             prop.__set__(newUnit, None) 
    521532        newUnit.sandbox = None 
    522533        return newUnit 
     
    536547    def identity(self): 
    537548        # Must be immutable for use as a dictionary key. 
    538         return tuple([prop.__get__(self) for prop in self.identifiers]) 
     549        return tuple([getattr(self, key) for key in self.identifiers]) 
    539550     
    540551    def _property_hash(self):