Changeset 18

Show
Ignore:
Timestamp:
12/31/01 06:38:54 (7 years ago)
Author:
arjanmol
Message:

New Element implementation

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/gaphor/AUTHORS

    r5 r18  
    1 Arjan Molenaar <arjan@xirion.nl> 
     1Arjan Molenaar <arjanmolenaar@hetnet.nl> 
  • trunk/gaphor/ChangeLog

    r5 r18  
     12001-12-29  Arjan Molenaar  <arjanmolenaar@hetnet.nl> 
     2 
     3        * gaphor/UML/Element.py: Reimplemented, now all sorts of relations 
     4          work properly. 
     5 
    162001-10-26  Arjan Molenaar  <arjanmolenaar@hetnet.nl> 
    27 
  • trunk/gaphor/configure.in

    r5 r18  
    4040    Makefile 
    4141    utils/Makefile 
    42     src/Makefile 
    43     src/model/Makefile 
    44     src/gui/Makefile 
     42    gaphor/Makefile 
     43    gaphor/UML/Makefile 
     44    gaphor/ui/Makefile 
    4545    tests/Makefile 
    4646    doc/Makefile) 
  • trunk/gaphor/gaphor/UML/Element.py

    r17 r18  
    11# vim: sw=4 
    2 # 
    3 # Base class for all UML model objects 
    4 # 
    5  
    6 import types, copy 
    7  
    8 # Some default types as defined in the MetaModel. 
    9 class Integer(int): pass 
    10 class UnlimitedInteger(long): pass 
    11 class Boolean(int): pass 
    12 class String(str): pass 
    13 class Name(String): pass 
    14 class Expression(String): pass 
    15 class LocationReference(String): pass 
    16 # Don't know what to do with this one: 
    17 Geometry = types.ListType 
    18  
    19 FALSE = 0 
    20 TRUE = not FALSE 
    21  
    22 class Enumeration_: 
    23     '''The Enumerration class is an abstract class that can be used to create 
    24     enumerated types. One should inherit from Enumeration and define a variable 
    25     '_values' at class level, which holds a list of valid values for the class. 
    26     ''' 
    27     def __init__(self): 
    28         self.v = self._values[0] 
    29     def __setattr__(self, key, value): 
    30         if key == 'v' and value in self._values: 
    31             self.__dict__['v'] = value 
    32         else: 
    33             raise AttributeError, "Value '" + str(value) + "' is an invalid enumeration type." 
    34  
    35 class Sequence: 
    36     '''A Sequence class has the following properties: 
    37     - A sequence is an unordered list of unique elements. 
    38     - Only accepts object of a certain type (or descendants). 
    39     - Only keep one reference to the object. 
    40     - A Sequence might have an owner. In that care the owners 
    41       sequence_{add|remove}() functions are called to allow 
    42       bi-directional relations to be added and deleted.''' 
    43     def __init__(self, owner, type): 
    44         self.owner = owner 
    45         self.requested_type = type 
    46         self.list = [] 
    47  
    48     def __len__(self): 
    49         return self.list.__len__() 
    50  
    51     def __setitem__(self, key, value): 
    52         raise Exception, "Sequence: items should not be overwritten." 
    53  
    54     def __delitem__(self, key): 
    55         if self.owner: 
    56             self.owner.sequence_remove(self, obj) 
    57         else: 
    58             self.list.__delitem__(key) 
    59  
    60     def __getitem__(self, key): 
    61         return self.list.__getitem__(key) 
    62  
    63     def __getslice__(self, i, j): 
    64         return self.list.__getslice__(i, j) 
    65  
    66     def __setslice__(self, i, j, s): 
    67         raise Exception, "Sequence: items should not be overwritten." 
    68  
    69     def __delslice__(self, i, j): 
    70         raise Exception, "Sequence: items should not be deleted this way." 
    71  
    72     def __contains__(self, obj): 
    73         return self.list.__contains__(obj) 
    74  
    75     def append(self, obj): 
    76         if isinstance (obj, self.requested_type): 
    77             if self.list.count(obj) == 0: 
    78                 self.list.append(obj) 
    79         else: 
    80             raise ValueError, "Sequence._add(obj): Object is not of type " + \ 
    81                                 str(self.requested_type) 
    82  
    83     def remove(self, key): 
    84         self.__delitem__(key) 
    85  
    86     def index(self, key): 
    87         return self.list.index(key) 
    88      
    89  
    90 if __name__ == '__main__': 
    91     print "\n============== Starting Sequence tests... ============\n" 
    92  
    93 # End of Sequence tests 
    94  
    952# 
    963# Base class for all UML model objects 
     
    10916# 
    11017 
     18 
     19import types, copy 
     20 
     21# Some default types as defined in the MetaModel. 
     22class Integer(int): pass 
     23class UnlimitedInteger(long): pass 
     24class Boolean(int): pass 
     25class String(str): pass 
     26class Name(String): pass 
     27class Expression(String): pass 
     28class LocationReference(String): pass 
     29# Don't know what to do with this one: 
     30Geometry = types.ListType 
     31 
     32FALSE = 0 
     33TRUE = not FALSE 
     34 
     35class Enumeration_: 
     36    '''The Enumerration class is an abstract class that can be used to create 
     37    enumerated types. One should inherit from Enumeration and define a variable 
     38    '_values' at class level, which holds a list of valid values for the class. 
     39    ''' 
     40    def __init__(self): 
     41        self.v = self._values[0] 
     42    def __setattr__(self, key, value): 
     43        if key == 'v' and value in self._values: 
     44            self.__dict__['v'] = value 
     45        else: 
     46            raise AttributeError, "Value '" + str(value) + "' is an invalid enumeration type." 
     47 
     48class Sequence: 
     49    '''A Sequence class has the following properties: 
     50    - A sequence is an unordered list of unique elements. 
     51    - Only accepts object of a certain type (or descendants). 
     52    - Only keep one reference to the object. 
     53    - A Sequence might have an owner. In that care the owners 
     54      sequence_{add|remove}() functions are called to allow 
     55      bi-directional relations to be added and deleted.''' 
     56    def __init__(self, owner, type): 
     57        self.owner = owner 
     58        self.requested_type = type 
     59        self.list = [] 
     60 
     61    def __len__(self): 
     62        return self.list.__len__() 
     63 
     64    def __setitem__(self, key, value): 
     65        raise Exception, "Sequence: items should not be overwritten." 
     66 
     67    def __delitem__(self, key): 
     68        if self.owner: 
     69            self.owner.sequence_remove(self, key) 
     70        else: 
     71            self.list.__delitem__(key) 
     72 
     73    def __getitem__(self, key): 
     74        return self.list.__getitem__(key) 
     75 
     76    def __getslice__(self, i, j): 
     77        return self.list.__getslice__(i, j) 
     78 
     79    def __setslice__(self, i, j, s): 
     80        raise IndexError, "Sequence: items should not be overwritten." 
     81 
     82    def __delslice__(self, i, j): 
     83        raise IndexError, "Sequence: items should not be deleted this way." 
     84 
     85    def __contains__(self, obj): 
     86        return self.list.__contains__(obj) 
     87 
     88    def append(self, obj): 
     89        if isinstance (obj, self.requested_type): 
     90            if self.list.count(obj) == 0: 
     91                #print "seq.list:", self.list 
     92                self.list.append(obj) 
     93                #print "seq.list:", self.list 
     94            #else: 
     95                #print "Sequence.append: Item already in sequence (" + str(obj) + ")" 
     96        else: 
     97            raise ValueError, "Sequence._add(obj): Object is not of type " + \ 
     98                                str(self.requested_type) 
     99 
     100    def remove(self, key): 
     101        self.__delitem__(key) 
     102 
     103    def index(self, key): 
     104        return self.list.index(key) 
     105     
     106 
    111107class Element: 
    112108    '''Element is the base class for *all* UML MetaModel classes. The 
     
    141137            return rec 
    142138 
     139    def __ensure_seq(self, key, type): 
     140        if not self.__dict__.has_key(key): 
     141            self.__dict__[key] = Sequence(self, type) 
     142        return self.__dict__[key] 
     143 
     144    def __del_seq_item(self, seq, val): 
     145        try: 
     146            index = seq.list.index(val) 
     147            del seq.list[index] 
     148        except ValueError: 
     149            pass 
     150 
    143151    def __getattr__(self, key): 
    144152        if key == "id": 
     
    151159            if rec[0] is Sequence: 
    152160                # We do not have a sequence here... create it and return it. 
    153                 self.__dict__[key] = Sequence(self, rec[1]) 
    154                 return self.__dict__[key] 
     161                return self.__ensure_seq (key, rec[1]) 
    155162            else: 
    156163                # Otherwise, return the default value 
     
    163170        2. In case of a bi-directional relationship: 
    164171           a. First remove a possible already existing relationship (not that 
    165               both sides can have a ultiplicity of '1'. 
     172              both sides can have a multiplicity of '1'. 
    166173           b. Set up a new relationship between self-value and value-self.''' 
    167174 
    168175        rec = self.__get_attr_info (key, self.__class__) 
     176        #print "__setattr__", rec 
    169177        if len(rec) == 2: # Attribute or one-way relation 
    170             self.__dict__[key] = value 
     178            if rec[0] is Sequence: 
     179                self.__ensure_seq (key, rec[1]).append(value) 
     180            else: 
     181                self.__dict__[key] = value 
    171182        else: 
    172183            xrec = value.__get_attr_info (rec[2], value.__class__) 
    173             if self.__dict__[key]: 
     184            #print "__setattr__x", xrec 
     185            if len(xrec) > 2: 
     186                assert xrec[2] == key 
     187            if self.__dict__.has_key(key): 
     188                #print "del old..." 
    174189                xself = self.__dict__[key] 
    175190                # Keep the relationship if we have a n:m relationship 
    176191                if rec[0] is not Sequence or xrec[0] is not Sequence: 
    177192                    if rec[0] is Sequence: 
    178                         del self.__dict__[key].list[xself] 
    179                     else: 
    180                         del self.__dict__[key] 
     193                        #print "del-seq-item rec" 
     194                        self.__del_seq_item(self.__dict__[key], xself) 
     195                    elif self.__dict__.has_key(key): 
     196                            #print "del-item rec" 
     197                            del self.__dict__[key] 
    181198                    if xrec[0] is Sequence: 
    182                         del xself.__dict__[key].list[self] 
    183                     else: 
    184                         del xself.__dict__[key] 
     199                        #print "del-seq-item xrec" 
     200                        xself.__del_seq_item(xself.__dict__[rec[2]], self) 
     201                    elif xself.__dict__.has_key(rec[2]): 
     202                            #print "del-item xrec" 
     203                            del xself.__dict__[rec[2]] 
     204            # Establish the relationship 
     205            if rec[0] is Sequence: 
     206                #print "add to seq" 
     207                self.__ensure_seq(key, rec[1]).append (value) 
     208            else: 
     209                #print "add to item" 
     210                self.__dict__[key] = value 
     211            if xrec[0] is Sequence: 
     212                #print "add to xseq" 
     213                value.__ensure_seq(rec[2], xrec[1]).append (self) 
     214            else: 
     215                #print "add to xitem" 
     216                value.__dict__[rec[2]] = self 
    185217             
    186     def __delattr__(self, name): 
     218    def __delattr__(self, key): 
     219        rec = self.__get_attr_info (key, self.__class__) 
     220        if rec[0] is Sequence: 
     221            raise AttributeError, "Element: you can not remove a sequence" 
     222        if not self.__dict__.has_key(key): 
     223            return 
     224        xval = self.__dict__[key] 
     225        del self.__dict__[key] 
     226        if len(rec) > 2: # Bi-directional relationship 
     227            xrec = xval.__get_attr_info (rec[2], rec[1]) 
     228            if xrec[0] is Sequence: 
     229                xval.__del_seq_item(xval.__dict__[rec[2]], self) 
     230            else: 
     231                del xval.__dict__[rec[2]] 
    187232 
    188233    def sequence_remove(self, seq, obj): 
    189234        '''Remove an entry. Should only be called by Sequence's implementation. 
    190235        This function is used to trap the 'del' function.''' 
    191         def del_attr (self, key, value, rec): 
    192             if rec[0] is not Sequence: 
    193                 del self.__dict__[key] 
    194             else: 
    195                 if not self.__dict__.has_key(key): 
    196                     self.__dict__[key] = Sequence(self, rec[1]) 
    197                 self.__dict__[key]._remove(value) 
    198  
    199         key = None 
    200         # Find the name for the Sequence... 
    201         for k in self.__dict__.keys(): 
    202             if self.__dict__[k] is seq: 
    203                 key = k 
    204                 break 
    205         if key is None: 
    206             return 
     236        # Find the key that belongs to 'seq' 
     237        for key in self.__dict__.keys(): 
     238            if self.__dict__[key] is seq: 
     239                break 
    207240        rec = self.__get_attr_info (key, self.__class__) 
    208         if len(rec) == 2: # One-way relation 
    209             del_attr (self, key, obj, rec) 
    210         else: 
    211             xrec = obj.__get_attr_info (rec[2], obj.__class__) 
    212             del_attr (self, key, obj, rec) 
    213             try: 
    214                 del_attr (obj, rec[2], self, xrec) 
    215             except AttributeError, e: 
    216                 self.__dict__[key]._add(obj) 
    217                 raise e 
    218  
    219 # END Element 
    220  
    221  
     241        if rec[0] is not Sequence: 
     242            raise AttributeError, "Element: This should be called from Sequence" 
     243        seq.list.remove(obj) 
     244        if len(rec) > 2: # Bi-directional relationship 
     245            xrec = obj.__get_attr_info (rec[2], rec[1]) 
     246            if xrec[0] is Sequence: 
     247                obj.__del_seq_item(obj.__dict__[rec[2]], self) 
     248            else: 
     249                del obj.__dict__[rec[2]] 
     250         
    222251if __name__ == '__main__': 
    223252 
    224253    print "\n============== Starting Element tests... ============\n" 
    225254 
    226     print "=== 1 ===" 
     255    print "=== Sequence: ", 
     256 
     257    class A(Element): _attrdef = { } 
     258 
     259    A._attrdef["seq"] = ( Sequence, types.StringType ) 
     260 
     261    a = A(1) 
     262    assert a.seq.list == [ ] 
     263 
     264    aap = "aap" 
     265    noot = "noot" 
     266    mies = "mies" 
     267 
     268    a.seq = aap 
     269    assert a.seq.list == [ aap ] 
     270 
     271    a.seq = noot 
     272    assert a.seq.list == [ aap, noot ] 
     273 
     274    assert len(a.seq) == 2 
     275    assert a.seq[0] is aap 
     276    assert a.seq[1] is noot 
     277    assert aap in a.seq 
     278    assert noot in a.seq 
     279    assert mies not in a.seq 
     280 
     281    print "\tOK ===" 
     282 
     283    print "=== Single:", 
    227284 
    228285    class A(Element): _attrdef = { } 
     
    250307    assert a.seq.list == [ noot ] 
    251308 
    252     print "=== 1:1 ===" 
     309    print "\tOK ===" 
     310 
     311    print "=== 1:1:", 
    253312 
    254313    class A(Element): _attrdef = { } 
     
    263322 
    264323    a.ref1 = a 
     324    #print a.ref1 
     325    #print a.ref2 
    265326    assert a.ref1 is a 
    266327    assert a.ref2 is a 
     
    268329    del a.ref1 
    269330    assert a.ref1 is None 
    270     print a.ref2 
    271 ####    assert a.ref2 is None 
     331    #print a.ref2 
     332    assert a.ref2 is None 
    272333 
    273334    a = A(1) 
     
    284345    assert a.ref2 is a 
    285346    assert b.ref1 is None 
    286 ####    assert b.ref2 is None 
    287  
    288     print "=== 1:n ===" 
     347    assert b.ref2 is None 
     348 
     349    print "\tOK ===" 
     350 
     351    print "=== 1:n", 
    289352 
    290353    class A(Element): _attrdef = { } 
     
    331394    assert b.seq.list == [ a, b ] 
    332395 
     396    b.ref = b 
     397    assert a.ref is b 
     398    assert a.seq.list == [ ] 
     399    assert b.ref is b 
     400    assert b.seq.list == [ a, b ] 
     401 
    333402    del b.seq[a] 
    334403    assert a.ref is None 
     
    337406    assert b.seq.list == [ b ] 
    338407 
     408    del b.ref 
     409    assert a.ref is None 
     410    assert a.seq.list == [ ] 
     411    assert b.ref is None 
     412    assert b.seq.list == [ ] 
     413 
     414    print "\tOK ===" 
     415 
     416    print "=== n:m:", 
     417 
     418    class A(Element): _attrdef = { } 
     419 
     420    A._attrdef['seq1'] = ( Sequence, A, 'seq2' ) 
     421    A._attrdef['seq2'] = ( Sequence, A, 'seq1' ) 
     422 
     423    a = A(1) 
     424    assert a.seq1.list == [ ] 
     425    assert a.seq2.list == [ ] 
     426 
     427    b = A(2) 
     428    assert b.seq1.list == [ ] 
     429    assert b.seq2.list == [ ] 
     430 
     431    a.seq1 = a 
     432    assert a.seq1.list == [ a ] 
     433    assert a.seq2.list == [ a ] 
     434    assert b.seq1.list == [ ] 
     435    assert b.seq2.list == [ ] 
     436 
     437    a.seq2 = a 
     438    assert a.seq1.list == [ a ] 
     439    assert a.seq2.list == [ a ] 
     440    assert b.seq1.list == [ ] 
     441    assert b.seq2.list == [ ] 
     442 
     443    a.seq1 = b 
     444    assert a.seq1.list == [ a, b ] 
     445    assert a.seq2.list == [ a ] 
     446    assert b.seq1.list == [ ] 
     447    assert b.seq2.list == [ a ] 
     448 
     449    del a.seq1[a] 
     450    assert a.seq1.list == [ b ] 
     451    assert a.seq2.list == [ ] 
     452    assert b.seq1.list == [ ] 
     453    assert b.seq2.list == [ a ] 
     454 
     455    b.seq1 = a 
     456    assert a.seq1.list == [ b ] 
     457    assert a.seq2.list == [ b ] 
     458    assert b.seq1.list == [ a ] 
     459    assert b.seq2.list == [ a ] 
     460 
     461    try: 
     462        del a.seq1 
     463    except AttributeError: 
     464        pass 
     465    except Exception: 
     466        assert 0 
     467    assert a.seq1.list == [ b ] 
     468    assert a.seq2.list == [ b ] 
     469    assert b.seq1.list == [ a ] 
     470    assert b.seq2.list == [ a ] 
     471 
     472    print "\tOK ===" 
     473 
     474    print "\n============== All Element tests passed... ============\n"