| 1 | ''' |
|---|
| 2 | Default entity collection implementation |
|---|
| 3 | ''' |
|---|
| 4 | import sys |
|---|
| 5 | |
|---|
| 6 | from elixir.py23compat import rsplit |
|---|
| 7 | |
|---|
| 8 | # default entity collection |
|---|
| 9 | class EntityCollection(list): |
|---|
| 10 | def __init__(self, entities=None): |
|---|
| 11 | # _entities is a dict of entities keyed on their name. |
|---|
| 12 | self._entities = {} |
|---|
| 13 | list.__init__(self) |
|---|
| 14 | if entities is not None: |
|---|
| 15 | self.extend(entities) |
|---|
| 16 | |
|---|
| 17 | def extend(self, entities): |
|---|
| 18 | for e in entities: |
|---|
| 19 | self.append(e) |
|---|
| 20 | |
|---|
| 21 | def append(self, entity): |
|---|
| 22 | ''' |
|---|
| 23 | Add an entity to the collection. |
|---|
| 24 | ''' |
|---|
| 25 | super(EntityCollection, self).append(entity) |
|---|
| 26 | |
|---|
| 27 | existing_entities = self._entities.setdefault(entity.__name__, []) |
|---|
| 28 | existing_entities.append(entity) |
|---|
| 29 | |
|---|
| 30 | def resolve(self, key, entity=None): |
|---|
| 31 | ''' |
|---|
| 32 | Resolve a key to an Entity. The optional `entity` argument is the |
|---|
| 33 | "source" entity when resolving relationship targets. |
|---|
| 34 | ''' |
|---|
| 35 | path = rsplit(key, '.', 1) |
|---|
| 36 | classname = path.pop() |
|---|
| 37 | if path: |
|---|
| 38 | # Do we have a fully qualified entity name? |
|---|
| 39 | module = sys.modules[path.pop()] |
|---|
| 40 | return getattr(module, classname, None) |
|---|
| 41 | else: |
|---|
| 42 | # Otherwise we look in the entities of this collection |
|---|
| 43 | res = self._entities.get(key, None) |
|---|
| 44 | if res is None: |
|---|
| 45 | if entity: |
|---|
| 46 | raise Exception("Couldn't resolve target '%s' in '%s'" \ |
|---|
| 47 | % (key, entity.__name__)) |
|---|
| 48 | else: |
|---|
| 49 | raise Exception("This collection does not contain any " |
|---|
| 50 | "entity corresponding to the key '%s'!" |
|---|
| 51 | % key) |
|---|
| 52 | elif len(res) > 1: |
|---|
| 53 | raise Exception("'%s' resolves to several entities, you should" |
|---|
| 54 | " use the full path (including the full module" |
|---|
| 55 | " name) to that entity." % key) |
|---|
| 56 | else: |
|---|
| 57 | return res[0] |
|---|
| 58 | |
|---|
| 59 | def clear(self): |
|---|
| 60 | self._entities = {} |
|---|
| 61 | del self[:] |
|---|
| 62 | |
|---|
| 63 | def __getattr__(self, key): |
|---|
| 64 | return self.resolve(key) |
|---|
| 65 | |
|---|