MultiKeyDict re-implemented
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1513 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
		
							parent
							
								
									76193d0de0
								
							
						
					
					
						commit
						ca4c568e36
					
				
					 2 changed files with 37 additions and 46 deletions
				
			
		|  | @ -27,7 +27,7 @@ objects only partly fitting the requested key: | ||||||
|   >>> registry[('index.html', 'topic', 'zope3', 'Custom')] |   >>> registry[('index.html', 'topic', 'zope3', 'Custom')] | ||||||
|   'global index.html' |   'global index.html' | ||||||
| 
 | 
 | ||||||
|   >>> registry[('index.html', 'topic',)] = 'index.html for type "topic"' |   >>> registry[('index.html', 'topic', None, None)] = 'index.html for type "topic"' | ||||||
| 
 | 
 | ||||||
|   >>> registry[('index.html', 'topic', 'zope3', 'Custom')] |   >>> registry[('index.html', 'topic', 'zope3', 'Custom')] | ||||||
|   'index.html for type "topic"' |   'index.html for type "topic"' | ||||||
|  | @ -59,8 +59,7 @@ Index entries that are present in the stored dictionaries must always match: | ||||||
|   >>> registry.get(('edit.html', 'task', 'bugfixes', 'Custom')) is None |   >>> registry.get(('edit.html', 'task', 'bugfixes', 'Custom')) is None | ||||||
|   True |   True | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|   >>> registry[('edit.html', None, None, 'Custom')] = 'edit.html for Custom skin' |   >>> registry[('edit.html', None, None, 'Custom')] = 'edit.html for Custom skin' | ||||||
| 
 | 
 | ||||||
|   >>> registry.get(('edit.html', 'task', 'bugfixes')) is None |   >>> registry.get(('edit.html', 'task', 'bugfixes', '')) is None | ||||||
|   True |   True | ||||||
|  |  | ||||||
|  | @ -23,63 +23,55 @@ $Id$ | ||||||
| """ | """ | ||||||
| 
 | 
 | ||||||
| _not_found = object() | _not_found = object() | ||||||
| _default = object() |  | ||||||
| 
 | 
 | ||||||
| class MultiKeyDict(dict): | class MultiKeyDict(dict): | ||||||
| 
 | 
 | ||||||
|     def __init__(self, **kw): |     def __init__(self, **kw): | ||||||
|         super(MultiKeyDict, self).__init__(**kw) |         super(MultiKeyDict, self).__init__(**kw) | ||||||
|         self.singleKeyDict = {} |         self.submapping = {} | ||||||
| 
 | 
 | ||||||
|     def __setitem__(self, key, value): |     def __setitem__(self, key, value): | ||||||
|         assert type(key) is tuple |         assert type(key) is tuple | ||||||
|         super(MultiKeyDict, self).__setitem__(key, value) |         k0 = key[0] | ||||||
|         for n, k in enumerate(key): |         if len(key) > 1: | ||||||
|             if k: |             sub = self.submapping.setdefault(k0, MultiKeyDict()) | ||||||
|                 entry = self.singleKeyDict.setdefault((n, k), []) |             sub[key[1:]] = value | ||||||
|                 if value not in entry: |         base = super(MultiKeyDict, self).__setitem__(k0, value) | ||||||
|                     entry.append((key, value)) |  | ||||||
| 
 | 
 | ||||||
|     def __getitem__(self, key): |     def __getitem__(self, key): | ||||||
|         r = self.get(key, _default) |         r = self.get(key, _not_found) | ||||||
|         if r is _default: |         if r is _not_found: | ||||||
|             raise KeyError(key) |             raise KeyError(key) | ||||||
|         return r |         return r | ||||||
| 
 | 
 | ||||||
|     def get(self, key, default=None): |     def get(self, key, default=None): | ||||||
|         assert type(key) is tuple |         assert type(key) is tuple | ||||||
|         kl = list(key) |         k0 = key[0] | ||||||
|         while kl: |         rsub = _not_found | ||||||
|             r = super(MultiKeyDict, self).get(tuple(kl), _not_found) |         r0 = super(MultiKeyDict, self).get(k0, _not_found) | ||||||
|             if r is not _not_found: |         if r0 is _not_found: | ||||||
|                 return r |             r0 = self.getFallback(k0) | ||||||
|             kl.pop() |         if r0 is _not_found: | ||||||
|             return default |             return default | ||||||
| 
 |         if len(key) > 1: | ||||||
|     def get(self, key, default=None): |             sub = self.submapping.get(k0, _not_found) | ||||||
|         assert type(key) is tuple |             if sub is _not_found: | ||||||
|         firstTry = super(MultiKeyDict, self).get(key, _not_found) |                 sub = self.getSubmappingFallback(key) | ||||||
|         # fast return for full match: |             if sub is not _not_found: | ||||||
|         if firstTry is not _not_found: |                 rsub = sub.get(key[1:], _not_found) | ||||||
|             return firstTry |                 if rsub is _not_found: | ||||||
|         collector = {} |  | ||||||
|         for n, k in enumerate(key): |  | ||||||
|             rList = self.singleKeyDict.get((n, k), []) |  | ||||||
|             for r in rList: |  | ||||||
|                 skip = False |  | ||||||
|                 for nx, kx in enumerate(r[0]): |  | ||||||
|                     # if stored key elements are present they must match |  | ||||||
|                     if kx and (len(key) <= nx or kx != key[nx]): |  | ||||||
|                         skip = True |  | ||||||
|                         break |  | ||||||
|                 if skip: |  | ||||||
|                     continue |  | ||||||
|                 entry = collector.setdefault(r[1], []) |  | ||||||
|                 entry.append(n) |  | ||||||
|         if not collector: |  | ||||||
|                     return default |                     return default | ||||||
|         #print 'collector', collector |             else: | ||||||
|         results = sorted((-len(value), value, o) for o, value in collector.items()) |                 rsub = _not_found | ||||||
|         #print 'sorted', results |         result = rsub is _not_found and r0 or rsub | ||||||
|         return results[0][2] |         return result is _not_found and default or result | ||||||
| 
 | 
 | ||||||
|  |     def getFallback(self, key): | ||||||
|  |         return super(MultiKeyDict, self).get(None, _not_found) | ||||||
|  | 
 | ||||||
|  |     def getSubmappingFallback(self, key): | ||||||
|  |         return self.submapping.get(None, _not_found) | ||||||
|  | 
 | ||||||
|  |     def __repr__(self): | ||||||
|  |         return ('<MultiKeyDict %s; submapping: %s>' | ||||||
|  |                 % (super(MultiKeyDict, self).__repr__(), `self.submapping`)) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 helmutm
						helmutm