~ubuntu-branches/ubuntu/hardy/gnue-common/hardy

« back to all changes in this revision

Viewing changes to src/datasources/drivers/Base/Schema/Creation/Creation.py

  • Committer: Bazaar Package Importer
  • Author(s): Andrew Mitchell
  • Date: 2005-03-09 11:06:31 UTC
  • Revision ID: james.westby@ubuntu.com-20050309110631-8gvvn39q7tjz1kj6
Tags: upstream-0.5.14
ImportĀ upstreamĀ versionĀ 0.5.14

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# GNU Enterprise Common - Base DB Driver - Schema Creation
 
2
#
 
3
# Copyright 2001-2005 Free Software Foundation
 
4
#
 
5
# This file is part of GNU Enterprise
 
6
#
 
7
# GNU Enterprise is free software; you can redistribute it
 
8
# and/or modify it under the terms of the GNU General Public
 
9
# License as published by the Free Software Foundation; either
 
10
# version 2, or (at your option) any later version.
 
11
#
 
12
# GNU Enterprise is distributed in the hope that it will be
 
13
# useful, but WITHOUT ANY WARRANTY; without even the implied
 
14
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 
15
# PURPOSE. See the GNU General Public License for more details.
 
16
#
 
17
# You should have received a copy of the GNU General Public
 
18
# License along with program; see the file COPYING. If not,
 
19
# write to the Free Software Foundation, Inc., 59 Temple Place
 
20
# - Suite 330, Boston, MA 02111-1307, USA.
 
21
#
 
22
# $Id: Creation.py 6851 2005-01-03 20:59:28Z jcater $
 
23
 
 
24
import gnue
 
25
 
 
26
# =============================================================================
 
27
# Exceptions
 
28
# =============================================================================
 
29
 
 
30
class Error (gException):
 
31
  pass
 
32
 
 
33
class NoCreationError (Error):
 
34
  def __init__ (self):
 
35
    msg = _("Database creation not implemented by this driver")
 
36
    Error.__init__ (self, msg)
 
37
 
 
38
class DefinitionError (Error):
 
39
  pass
 
40
 
 
41
class MissingKeyError (DefinitionError):
 
42
  MSG = u_("The definition has no attribute '%s'")
 
43
  def __init__ (self, attribute):
 
44
    DefinitionError.__init__ (self, self.MSG % attribute)
 
45
 
 
46
class TableDefinitionError (MissingKeyError):
 
47
  MSG = u_("The table definition has no attribute '%s'")
 
48
 
 
49
class FieldDefinitionError (MissingKeyError):
 
50
  MSG = u_("The field definition has no attribute '%s'")
 
51
 
 
52
class PrimaryKeyDefinitionError (MissingKeyError):
 
53
  MSG = u_("Primarykey definition has no attribute '%s'")
 
54
 
 
55
class PrimaryKeyFieldsError (Error):
 
56
  def __init__ (self, table, name):
 
57
    msg = u_("Primarykey '%(name)s' of table '%(table)s' has no fields") \
 
58
          % {'name' : name,
 
59
             'table': table}
 
60
    Error.__init__ (self, msg)
 
61
 
 
62
class PrimaryKeyError (DefinitionError):
 
63
  def __init__ (self, table):
 
64
    msg = u_("Table '%s' has a primary key which is not allowed on "
 
65
             "table modification") % table
 
66
    DefinitionError.__init__ (self, msg)
 
67
 
 
68
class IndexDefinitionError (MissingKeyError):
 
69
  MSG = u_("Index definition has no attribute '%s'")
 
70
 
 
71
class IndexFieldsError (Error):
 
72
  def __init__ (self, table, name):
 
73
    msg = u_("Index '%(name)s' of table '%(table)s' has no fields") \
 
74
          % {'name' : name,
 
75
             'table': table}
 
76
    Error.__init__ (self, msg)
 
77
 
 
78
class ConstraintDefinitionError (MissingKeyError):
 
79
  MSG = u_("Constraint definition has no attribute '%s'")
 
80
 
 
81
class ConstraintFieldsError (Error):
 
82
  def __init__ (self, table, name, fields):
 
83
    msg = u_("Constraint '%(name)s' of table '%(table)s' has no '%(fields)s'")\
 
84
          % {'name'  : name,
 
85
             'table' : table,
 
86
             'fields': fields}
 
87
    Error.__init__ (self, msg)
 
88
 
 
89
class ConstraintTypeError (Error):
 
90
  def __init__ (self, table, name, cType):
 
91
    msg = u_("Type '%(type)s' of constraint '%(name)s' in table '%(table)s' "
 
92
             "not supported") % \
 
93
            {'table': table,
 
94
             'name' : name,
 
95
             'type' : cType}
 
96
    Error.__init__ (self, msg)
 
97
 
 
98
class MissingTypeTransformationError (Error):
 
99
  def __init__ (self, typename):
 
100
    msg = u_("No type transformation for '%s' found") % typename
 
101
    Error.__init__ (self, msg)
 
102
 
 
103
 
 
104
class LengthError (Error):
 
105
  def __init__ (self, identifier, maxlen):
 
106
    msg = u_("The idendifier '%(identifier)s' exceeds the maximum length "
 
107
             "of %(maxlength)d characters") \
 
108
          % {'identifier': identifier,
 
109
             'maxlength': maxlen or 0}
 
110
    Error.__init__ (self, msg)
 
111
 
 
112
 
 
113
# =============================================================================
 
114
# Base class for drivers schema creation support
 
115
# =============================================================================
 
116
class Creation:
 
117
 
 
118
  MAX_NAME_LENGTH = None        # Max. length of an identifier
 
119
  END_COMMAND     = ""          # Character used for command termination
 
120
  
 
121
  # ---------------------------------------------------------------------------
 
122
  # Constructor
 
123
  # ---------------------------------------------------------------------------
 
124
 
 
125
  def __init__ (self, connection = None, introspector = None):
 
126
    self.connection   = connection
 
127
    self.introspector = introspector
 
128
    self.lookup       = {}
 
129
 
 
130
    if connection is not None and introspector is None:
 
131
      self.introspector = connection.introspector
 
132
 
 
133
 
 
134
  # ---------------------------------------------------------------------------
 
135
  # Create a database
 
136
  # ---------------------------------------------------------------------------
 
137
 
 
138
  def createDatabase (self):
 
139
    """
 
140
    Descendants can override this function to create a database. Usually all
 
141
    information needed could be gathered from the connection object.
 
142
    """
 
143
    raise NoCreationError
 
144
 
 
145
 
 
146
  # ---------------------------------------------------------------------------
 
147
  # Create a table from a table definition
 
148
  # ---------------------------------------------------------------------------
 
149
 
 
150
  def createTable (self, tableDefinition, codeOnly = False):
 
151
    """
 
152
    This function creates a table using the given definition and returns a
 
153
    code-tuple, which can be used to to this.
 
154
 
 
155
    @param tableDefinition: a dictionary of the table to be created
 
156
    @param codeOnly: if TRUE no operation takes place, but only the code will
 
157
        be returned.
 
158
    @return: a tuple of sequences (prologue, body, epliogue) containing the
 
159
        code to perform the action.
 
160
    """
 
161
    self._validateTable (tableDefinition)
 
162
    return ([], [], [])
 
163
  
 
164
 
 
165
  # ---------------------------------------------------------------------------
 
166
  # Create a primary key
 
167
  # ---------------------------------------------------------------------------
 
168
 
 
169
  def createPrimaryKey (self, tableName, keyDefinition, codeOnly = False):
 
170
    """
 
171
    This function creates a primary key for the given table using the primary
 
172
    key definition.
 
173
 
 
174
    @param tableName: name of the table for which a key should be created
 
175
    @param keyDefinition: a dictionary of the primary key to be created 
 
176
    @param codeOnly: if TRUE no operation takes place, but only the code will
 
177
        be returned.
 
178
    @return: a tuple of sequences (prologue, body, epliogue) containing the
 
179
        code to perform the action.
 
180
    """
 
181
    self._validatePrimaryKey (tableName, keyDefinition)
 
182
    return ([], [], [])
 
183
 
 
184
 
 
185
  # ---------------------------------------------------------------------------
 
186
  # Create an index
 
187
  # ---------------------------------------------------------------------------
 
188
 
 
189
  def createIndex (self, tableName, indexDefinition, codeOnly = False):
 
190
    """
 
191
    This function creates an index for the given table using the index
 
192
    definition.
 
193
 
 
194
    @param tableName: name of the table for which an index should be created
 
195
    @param indexDefinition: a dictionary of the index to be created 
 
196
    @param codeOnly: if TRUE no operation takes place, but only the code will
 
197
        be returned.
 
198
    @return: a tuple of sequences (prologue, body, epliogue) containing the
 
199
        code to perform the action.
 
200
    """
 
201
    self._validateIndex (tableName, indexDefinition)
 
202
    return ([], [], [])
 
203
 
 
204
 
 
205
  # ---------------------------------------------------------------------------
 
206
  # Drop an index
 
207
  # ---------------------------------------------------------------------------
 
208
 
 
209
  def dropIndex (self, tableName, indexName, codeOnly = False):
 
210
    """
 
211
    This function drops an index from the given table using the index
 
212
    definition.
 
213
 
 
214
    @param tableName: name of the table to drop an index from
 
215
    @param indexName: name of the index to be dropped 
 
216
    @param codeOnly: if TRUE no operation takes place, but only the code will
 
217
        be returned.
 
218
    @return: a tuple of sequences (prologue, body, epliogue) containing the
 
219
        code to perform the action.
 
220
    """
 
221
    return ([], [], [])
 
222
 
 
223
 
 
224
  # ---------------------------------------------------------------------------
 
225
  # Create a constraint
 
226
  # ---------------------------------------------------------------------------
 
227
 
 
228
  def createConstraint (self, tableName, constraintDef, codeOnly = False):
 
229
    """
 
230
    This function creates a constraint for the given table using the constraint
 
231
    definition.
 
232
 
 
233
    @param tableName: name of the table for which an index should be created
 
234
    @param constraintDef: a dictionary of the constraint to be created 
 
235
    @param codeOnly: if TRUE no operation takes place, but only the code will
 
236
        be returned.
 
237
    @return: a tuple of sequences (prologue, body, epliogue) containing the
 
238
        code to perform the action.
 
239
    """
 
240
    self._validateConstraint (tableName, constraintDef)
 
241
    return ([], [], [])
 
242
 
 
243
 
 
244
  # ---------------------------------------------------------------------------
 
245
  # Modify a table
 
246
  # ---------------------------------------------------------------------------
 
247
 
 
248
  def modifyTable (self, tableDefinition, codeOnly = False):
 
249
    """
 
250
    This function modifies a table according to the given definition.
 
251
 
 
252
    @param tableDefinition: a dictionary of the table to be modified
 
253
    @param codeOnly: if TRUE no operation takes place, but only the code will
 
254
        be returned.
 
255
    @return: a tuple of sequences (prologue, body, epliogue) containing the
 
256
        code to perform the action.
 
257
    """
 
258
    self._validateTable (tableDefinition, True)
 
259
    return ([], [], [])
 
260
 
 
261
 
 
262
  # ---------------------------------------------------------------------------
 
263
  # Create fields for a table
 
264
  # ---------------------------------------------------------------------------
 
265
 
 
266
  def createFields (self, tableName, fields, forAlter = False):
 
267
    """
 
268
    This function creates all listed fields in the given table. If forAlter is
 
269
    TRUE this function should create the fields for a table modification.
 
270
 
 
271
    @param tableName: name of the table for which fields should be created or
 
272
        modified.
 
273
    @param fields: a list of field definition dictionaries, describing the
 
274
        fields to be created or modified.
 
275
    @param forAlter: if TRUE the fields should be modified, otherwise created
 
276
    @return: a tuple of sequences (prologue, body, epliogue) containing the
 
277
        code to perform the action.
 
278
    """
 
279
    for field in fields:
 
280
      self._validateField (tableName, field)
 
281
    return ([], [], [])
 
282
 
 
283
 
 
284
  # ---------------------------------------------------------------------------
 
285
  # Check wether an element exists or not
 
286
  # ---------------------------------------------------------------------------
 
287
 
 
288
  def exists (self, elementName, elementType = None):
 
289
    """
 
290
    This function examines, wether an element exists in a datamodel or not.
 
291
    It's doing this using the given introspector. If no introspecor is
 
292
    available the result is FALSE.
 
293
 
 
294
    @param elementName: name of the element to be examined
 
295
    @param elementType: type of the element to be examined (optional)
 
296
    @return: TRUE if the element was found, otherwise FALSE
 
297
    """
 
298
    if self.introspector is not None:
 
299
      return self.introspector.find (name = elementName, type = elementType)
 
300
    else:
 
301
      return False
 
302
 
 
303
 
 
304
  # ---------------------------------------------------------------------------
 
305
  # Validate a given table definition
 
306
  # ---------------------------------------------------------------------------
 
307
 
 
308
  def validate (self, tableDef):
 
309
    """
 
310
    This function validates all parts of a table definition.
 
311
    @param tableDef: dictionary describing the table and it's parts.
 
312
    """
 
313
    self._validateTable (tableDef)
 
314
    tableName = tableDef['name']
 
315
 
 
316
    if tableDef.has_key ('primarykey'):
 
317
      self._validatePrimaryKey (tableName, tableDef ['primarykey'])
 
318
 
 
319
    if tableDef.has_key ('fields'):
 
320
      for field in tableDef ['fields']:
 
321
        self._validateField (tableName, field)
 
322
 
 
323
    if tableDef.has_key ('indices'):
 
324
      for index in tableDef ['indices']:
 
325
        self._validateIndex (tableName, index)
 
326
 
 
327
    if tableDef.has_key ('constraints'):
 
328
      for constraint in tableDef ['constraints']:
 
329
        self._validateConstraint (tableName, constraint)
 
330
 
 
331
 
 
332
  # ---------------------------------------------------------------------------
 
333
  # Make sure to release all references
 
334
  # ---------------------------------------------------------------------------
 
335
 
 
336
  def close (self):
 
337
    """
 
338
    This function releases all circular references held by the creator instance
 
339
    """
 
340
 
 
341
    self.introspector = None
 
342
    self.connection   = None
 
343
    self.lookup       = {}
 
344
 
 
345
 
 
346
  # ---------------------------------------------------------------------------
 
347
  # Call the appropriate method for a type-transformation
 
348
  # ---------------------------------------------------------------------------
 
349
 
 
350
  def _translateType (self, fieldDefinition):
 
351
    """
 
352
    This function calls the appropriate method for a type-conversion according
 
353
    to the field definition's datatype and returns this method's result.
 
354
 
 
355
    @param fieldDefinition: dictionary describing the field.
 
356
    @return: a string with the native data type for the field definition.
 
357
    """
 
358
    if not fieldDefinition.has_key ('type'):
 
359
      raise FieldDefinitionError, ('type')
 
360
 
 
361
    aMethod = self.__findMethod (self.__class__, fieldDefinition ['type'])
 
362
    if aMethod is None:
 
363
      raise MissingTypeTransformationError, (fieldDefinition ['type'])
 
364
 
 
365
    return aMethod (self, fieldDefinition)
 
366
 
 
367
 
 
368
  # ---------------------------------------------------------------------------
 
369
  # Create code for a single field
 
370
  # ---------------------------------------------------------------------------
 
371
 
 
372
  def _processField (self, tableName, fieldDef, forAlter = False):
 
373
    """
 
374
    This function creates a portion of code which defines the given field in
 
375
    the table tableName. 
 
376
    
 
377
    @param tableName: the table this field belongs to.
 
378
    @param fieldDef: the dictionary describing the field.
 
379
    @param forAlter: If TRUE this function produces code for a table
 
380
        modification, otherwise for a table creation.
 
381
    @return: a tuple of sequences (prologue, body, epliogue) containing the
 
382
        code to perform the action.
 
383
    """
 
384
    return ([], [], [])
 
385
 
 
386
 
 
387
  # ---------------------------------------------------------------------------
 
388
  # Create a usable name for a seuquence like object
 
389
  # ---------------------------------------------------------------------------
 
390
 
 
391
  def _getSequenceName (self, tableName, fieldDefinition):
 
392
    """
 
393
    This function creates a name for a sequence like object using the table-
 
394
    and fieldname. It respects a given restriction of identifier length.
 
395
 
 
396
    @param tableName: name of the table
 
397
    @param fieldDefinition: dictionary describing the field
 
398
    @return: string with a name for the given sequence
 
399
    """
 
400
 
 
401
    res = "%s_%s_seq" % (tableName, fieldDefinition ['name'])
 
402
    if self._nameTooLong (res):
 
403
      res = "%s_%s_seq" % (tableName, id (fieldDefinition))
 
404
 
 
405
    if self._nameTooLong (res):
 
406
      res = "%s_seq" % (id (fieldDefinition))
 
407
 
 
408
    return self._shortenName (res)
 
409
 
 
410
 
 
411
  # ---------------------------------------------------------------------------
 
412
  # Check if an identifier is too long
 
413
  # ---------------------------------------------------------------------------
 
414
 
 
415
  def _nameTooLong (self, aName):
 
416
    """
 
417
    This function returns TRUE if @aName exceeds MAX_NAME_LENGTH, otherwise
 
418
    FALSE. 
 
419
    """
 
420
    return (self.MAX_NAME_LENGTH is not None) and \
 
421
           (len (aName) > self.MAX_NAME_LENGTH)
 
422
 
 
423
 
 
424
  # ---------------------------------------------------------------------------
 
425
  # Make sure a given identifier doesn't exceed maximum length
 
426
  # ---------------------------------------------------------------------------
 
427
 
 
428
  def _shortenName (self, aName):
 
429
    """
 
430
    This function makes sure the given name doesn't exceed the maximum
 
431
    identifier length.
 
432
    @param aName: identifier to be checked
 
433
    @return: identifier with extra characters cut off
 
434
    """
 
435
    if self._nameTooLong (aName):
 
436
      return aName [:self.MAX_NAME_LENGTH]
 
437
    else:
 
438
      return aName
 
439
 
 
440
 
 
441
  # ---------------------------------------------------------------------------
 
442
  # Merge all sequences in the given tuples 
 
443
  # ---------------------------------------------------------------------------
 
444
 
 
445
  def mergeTuple (self, mergeInto, mergeFrom):
 
446
    """
 
447
    This function merges the sequences in the given tuples and returns the
 
448
    first one (which is changes as a side effect too).
 
449
    @param mergeInto: tuple with sequences which gets extended
 
450
    @param mergeFrom: tuple with sequences which mergeInto gets extended with
 
451
    @return: tuple of the same length as mergeInto with all sequences merged
 
452
        together.
 
453
    """
 
454
    for ix in range (len (mergeInto)):
 
455
      mergeInto [ix].extend (mergeFrom [ix])
 
456
    return mergeInto
 
457
 
 
458
 
 
459
  # ---------------------------------------------------------------------------
 
460
  # Validate a table definition
 
461
  # ---------------------------------------------------------------------------
 
462
 
 
463
  def _validateTable (self, tableDef, forAlter = False):
 
464
    """
 
465
    This function validates a table definition.
 
466
    @param tableDef: dictionary describing the table
 
467
 
 
468
    @raise TableDefinitionError: If tableDef has no key 'name'
 
469
    """
 
470
    self.__validateDefinition (tableDef, ['name'], TableDefinitionError)
 
471
    if self._nameTooLong (tableDef ['name']):
 
472
      raise LengthError, (tableDef ['name'], self.MAX_NAME_LENGTH)
 
473
 
 
474
    if forAlter and tableDef.has_key ('primarykey'):
 
475
      raise PrimaryKeyError, (tableDef ['name'])
 
476
 
 
477
 
 
478
  # ---------------------------------------------------------------------------
 
479
  # Validate a given primary key definition
 
480
  # ---------------------------------------------------------------------------
 
481
 
 
482
  def _validatePrimaryKey (self, tableName, keyDefinition):
 
483
    """
 
484
    This function validates a primarykey definition.
 
485
    @param tableName: name of the table the primary key belongs to
 
486
    @param keyDefinition: dictionary describing the primary key
 
487
 
 
488
    @raise PrimaryKeyDefinitionError: if 'name' or 'fields' are missing in the
 
489
        definition.
 
490
    @raise PrimaryKeyFieldsError: if 'fields' is an empty sequence
 
491
    """
 
492
    self.__validateDefinition (keyDefinition, ['name', 'fields'],
 
493
                               PrimaryKeyDefinitionError)
 
494
 
 
495
    if not len (keyDefinition ['fields']):
 
496
      raise PrimaryKeyFieldsError, (tableName, keyDefinition ['name'])
 
497
 
 
498
    for field in keyDefinition ['fields']:
 
499
      if self._nameTooLong (field):
 
500
        raise LengthError, (field, self.MAX_NAME_LENGTH)
 
501
 
 
502
 
 
503
  # ---------------------------------------------------------------------------
 
504
  # Validate a given index definition
 
505
  # ---------------------------------------------------------------------------
 
506
 
 
507
  def _validateIndex (self, tableName, indexDefinition):
 
508
    """
 
509
    This function validates an index definition.
 
510
    @param tableName: name of the table
 
511
    @param indexDefinition: dictionary describing the index
 
512
 
 
513
    @raise IndexDefinitionError: if 'name' or 'fields' are missing in the
 
514
        definition.
 
515
    @raise IndexFieldsError: if 'fields' is an empty sequence
 
516
    """
 
517
    self.__validateDefinition (indexDefinition, ['name', 'fields'],
 
518
                               IndexDefinitionError)
 
519
    if not len (indexDefinition ['fields']):
 
520
      raise IndexFieldsError, (tableName, indexDefinition ['name'])
 
521
 
 
522
    for field in indexDefinition ['fields']:
 
523
      if self._nameTooLong (field):
 
524
        raise LengthError, (field, self.MAX_NAME_LENGTH)
 
525
 
 
526
 
 
527
  # ---------------------------------------------------------------------------
 
528
  # Validate a given constraint definition
 
529
  # ---------------------------------------------------------------------------
 
530
 
 
531
  def _validateConstraint (self, tableName, constDef):
 
532
    """
 
533
    This function validates a constraint definition.
 
534
    @param tableName: name of the table the constraint belongs to
 
535
    @param constDef: the dictionary describing the constraint
 
536
 
 
537
    @raise ConstraintDefinitionError: if 'name' or 'fields' are missing in the
 
538
        definition.
 
539
    @raise ConstraintFieldsError: if 'fields' or 'reffields' is an empty
 
540
        sequence.
 
541
    """
 
542
    self.__validateDefinition (constDef,
 
543
        ['name', 'fields', 'reftable', 'reffields'], ConstraintDefinitionError)
 
544
 
 
545
    if not len (constDef ['fields']):
 
546
      raise ConstraintFieldsError, (tableName, constDef ['name'], 'fields')
 
547
    if not len (constDef ['reffields']):
 
548
      raise ConstraintFieldsError, (tableName, constDef ['name'], 'reffields')
 
549
 
 
550
    if constDef.has_key ('type') and constDef ['type'] != 'foreignkey':
 
551
      raise ConstraintTypeError, (tableName, constDef ['name'],
 
552
                                  constDef ['type'])
 
553
 
 
554
    if self._nameTooLong (constDef ['reftable']):
 
555
      raise LengthError, (constDef ['reftable'], self.MAX_NAME_LENGTH)
 
556
 
 
557
    for field in constDef ['fields'] + constDef ['reffields']:
 
558
      if self._nameTooLong (field):
 
559
        raise LengthError, (field, self.MAX_NAME_LENGTH)
 
560
 
 
561
 
 
562
  # ---------------------------------------------------------------------------
 
563
  # Validate a field definition
 
564
  # ---------------------------------------------------------------------------
 
565
 
 
566
  def _validateField (self, tableName, fieldDef):
 
567
    """
 
568
    This function validates a field definition.
 
569
    @param tableName: name of the table
 
570
    @param fieldDef: dictionary describing the field
 
571
 
 
572
    @raise FieldDefinitionError: If the dictionary has no 'name' and 'type'
 
573
        keys.
 
574
    """
 
575
    self.__validateDefinition (fieldDef, ['name', 'type'], FieldDefinitionError)
 
576
    if self._nameTooLong (fieldDef ['name']):
 
577
      raise LengthError, (fieldDef ['name'], self.MAX_NAME_LENGTH)
 
578
 
 
579
 
 
580
  # ---------------------------------------------------------------------------
 
581
  # Validate all keys in an arbitrary definition
 
582
  # ---------------------------------------------------------------------------
 
583
 
 
584
  def __validateDefinition (self, definition, keys, defError):
 
585
    """
 
586
    This function raises an exception if a key in the given sequence is missing
 
587
    in the definition.
 
588
    @param definition: dictionary to be checked
 
589
    @param keys: sequence of keys which must exist in definition
 
590
    @param defError: DefinitionError class raised on a missing key
 
591
    """
 
592
    for key in keys:
 
593
      if not definition.has_key (key):
 
594
        raise defError, (key)
 
595
 
 
596
 
 
597
  # ---------------------------------------------------------------------------
 
598
  # find a method in a class or its' superclasses
 
599
  # ---------------------------------------------------------------------------
 
600
 
 
601
  def __findMethod (self, aClass, aMethod):
 
602
    """
 
603
    This function looks for a method in a class and all its' superclasses.
 
604
 
 
605
    @param aClass: the class where the search starts
 
606
    @param aMethod: name of the method to be looked for
 
607
    @return: function pointer to the method found or None if search failed.
 
608
    """
 
609
 
 
610
    if aClass.__dict__.has_key (aMethod):
 
611
      return aClass.__dict__ [aMethod]
 
612
    else:
 
613
      for base in aClass.__bases__:
 
614
        result = self.__findMethod (base, aMethod)
 
615
        if result is not None:
 
616
          return result
 
617
 
 
618
    return None
 
619