Gaetan de Menten schrieb:
>> I assume that you agree that having "resolve_root" on a per-entity basis
>> makes sense.
>>     
>
> Hmm no. Seems like I wasn't clear enough. I meant it as an option (ie
> argument to the constructor) on the EntityCollection class.
>
> What would a use case for what you suggest be? If you specify a
> specific resolve_root for *one* particular entity, you might as well
> use the absolute paths. That feature would only make sense if you have
> *lots* of relations to the same target module within the same entity
> *and* that target module is not the current module (or one close to it
> in the module hierarchy). This seems like a very unlikely combination
> and not worth a feature in the default distribution (you could still
> implement it as a custom collection if you wish).
>   

For example, I thought of merging different projects, which have 
different module roots. So that you just set the default option 
reslove_root different depending whether you are in the former project A 
part or in that of project B.
Also think of the problem, that if the resolve_root is defined on 
collection basis, you can never "break out" using absolute path.

But you're still right, that those are very special use cases. They can 
also be solve using a user-defined resolve function. Another solution 
might be that you allow to provide a function, which generates the 
module_root (like the tablename option).

I append a new patch against r455, adding a "module_root" argument to 
EntityCollection and making some improvements in the resolve implementation.

General question: where should we discuss this, here or on trac?

Kind regards

Johannes

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"SQLElixir" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/sqlelixir?hl=en
-~----------~----~----~----~------~----~------~--~---

Index: elixir/collection.py
===================================================================
--- elixir/collection.py	(Revision 455)
+++ elixir/collection.py	(Arbeitskopie)
@@ -7,7 +7,12 @@
 
 # default entity collection
 class EntityCollection(list):
-    def __init__(self, entities=None):
+    def __init__(self, module_root=None, entities=None):
+        if module_root is None:
+            self.module_root = '__main__'
+        else:
+            self.module_root = module_root
+        
         # _entities is a dict of entities keyed on their name.
         self._entities = {}
         list.__init__(self)
@@ -32,35 +37,50 @@
         Resolve a key to an Entity. The optional `entity` argument is the
         "source" entity when resolving relationship targets.
         '''
-        path = rsplit(key, '.', 1)
-        classname = path.pop()
-        if path:
-            # Do we have a fully qualified entity name?
-            module = sys.modules[path.pop()]
-            return getattr(module, classname, None)
-        else:
-            # Otherwise we look in the entities of this collection
-            res = self._entities.get(key, None)
-            if res is None:
-                if entity:
-                    raise Exception("Couldn't resolve target '%s' in '%s'" \
-                                    % (key, entity.__name__))
-                else:
-                    raise Exception("This collection does not contain any "
-                                    "entity corresponding to the key '%s'!"
-                                    % key)
-            elif len(res) > 1:
-                raise Exception("'%s' resolves to several entities, you should"
-                                " use the full path (including the full module"
-                                " name) to that entity." % key)
+        
+        relative_path, classname = rsplit(key, '.', 1)
+        
+        if key.startswith('.'):
+            if entity is None:
+                raise Exception("Couldn't resolve relative target '%s', "
+                                "because no entity was passed." % key)
             else:
-                return res[0]
+                link = relative_path[1:]
+                full_path = entity.__module__
+                
+                while link.startswith('.'):
+                    rdot = full_path.rfind('.')
+                    if rdot < 1:
+                        raise Exception("Couldn't resolve relative target "
+                            "'%s' relative to '%s'" % (key, entity.__module__))
+                    
+                    link = link[1:]
+                    full_path = full_path[:rdot]
+                
+                if len(link) > 0:
+                    full_path = '%s.%s' % (full_path, link)
 
+        else:
+            full_path = '%s.%s' % (self.module_root, relative_path)
+            
+        if full_path.startswith('__main__.'):
+           full_path = full_path[9:]         
+        
+        module = sys.modules.get(full_path, None)
+        if module is None:
+            raise Exception("Couldn't find module '%s'." % full_path)
+            
+        res = getattr(module, classname, None)
+        if res is None:
+            raise Exception("Couldn't find class '%s' in module '%s'."
+                            % (classname, full_path) )
+        
+        return res
+    
     def clear(self):
         self._entities = {}
         del self[:]
-
+    
     def __getattr__(self, key):
         return self.resolve(key)
 
-

Reply via email to