added "import='x, y'" / "import='*'" to namespace tag, will cut down on dots
added filename-relative lookup to TemplateLookup
diff --git a/lib/mako/codegen.py b/lib/mako/codegen.py
index a0ec91d..aaa9c47 100644
--- a/lib/mako/codegen.py
+++ b/lib/mako/codegen.py
@@ -118,7 +118,7 @@
         if not self.in_def and len(self.identifiers.locally_assigned) > 0:
             self.printer.writeline("__locals = {}")
 
-        self.write_variable_declares(self.identifiers, first="kwargs")
+        self.write_variable_declares(self.identifiers, toplevel=True)
 
         for n in self.node.nodes:
             n.accept_visitor(self)
@@ -136,7 +136,7 @@
     def write_inherit(self, node):
         self.printer.writeline("def _mako_inherit(context):")
         self.printer.writeline("_mako_generate_namespaces(context)")
-        self.printer.writeline("return runtime.inherit_from(context, %s)" % (repr(node.attributes['file'])))
+        self.printer.writeline("return runtime.inherit_from(context, %s, _template_filename)" % (repr(node.attributes['file'])))
         self.printer.writeline(None)
 
     def write_namespaces(self, namespaces):
@@ -151,6 +151,8 @@
             )
         self.printer.writeline("def _mako_generate_namespaces(context):")
         for node in namespaces.values():
+            if node.attributes.has_key('import'):
+                self.compiler.has_ns_imports = True
             self.write_source_comment(node)
             if len(node.nodes):
                 self.printer.writeline("def make_namespace():")
@@ -168,7 +170,7 @@
                 callable_name = "make_namespace()"
             else:
                 callable_name = "None"
-            self.printer.writeline("ns = runtime.Namespace(%s, context.clean_inheritance_tokens(), templateuri=%s, callables=%s)" % (repr(node.name), node.parsed_attributes.get('file', 'None'), callable_name))
+            self.printer.writeline("ns = runtime.Namespace(%s, context.clean_inheritance_tokens(), templateuri=%s, callables=%s, calling_filename=_template_filename)" % (repr(node.name), node.parsed_attributes.get('file', 'None'), callable_name))
             if eval(node.attributes.get('inheritable', "False")):
                 self.printer.writeline("context['self'].%s = ns" % (node.name))
             self.printer.writeline("context.namespaces[(render, %s)] = ns" % repr(node.name))
@@ -177,7 +179,7 @@
             self.printer.writeline("pass")
         self.printer.writeline(None)
             
-    def write_variable_declares(self, identifiers, first=None):
+    def write_variable_declares(self, identifiers, toplevel=False):
         """write variable declarations at the top of a function.
         
         the variable declarations are in the form of callable definitions for defs and/or
@@ -209,6 +211,13 @@
         # which cannot be referenced beforehand.  
         to_write = to_write.difference(identifiers.locally_declared)
         
+        if toplevel and getattr(self.compiler, 'has_ns_imports', False):
+            self.printer.writeline("_import_ns = {}")
+            self.compiler.has_imports = True
+            for ident, ns in self.compiler.namespaces.iteritems():
+                if ns.attributes.has_key('import'):
+                    self.printer.writeline("_mako_get_namespace(context, %s).populate(_import_ns, %s)" % (repr(ident),  repr(re.split(r'\s*,\s*', ns.attributes['import']))))
+                        
         for ident in to_write:
             if ident in comp_idents:
                 comp = comp_idents[ident]
@@ -219,10 +228,10 @@
             elif ident in self.compiler.namespaces:
                 self.printer.writeline("%s = _mako_get_namespace(context, %s)" % (ident, repr(ident)))
             else:
-                if first is not None:
-                    self.printer.writeline("%s = %s.get(%s, context.get(%s, UNDEFINED))" % (ident, first, repr(ident), repr(ident)))
+                if getattr(self.compiler, 'has_ns_imports', False):
+                    self.printer.writeline("%s = _import_ns.get(%s, kwargs.get(%s, context.get(%s, UNDEFINED)))" % (ident, repr(ident), repr(ident), repr(ident)))
                 else:
-                    self.printer.writeline("%s = context.get(%s, UNDEFINED)" % (ident, repr(ident)))
+                    self.printer.writeline("%s = kwargs.get(%s, context.get(%s, UNDEFINED))" % (ident, repr(ident), repr(ident)))
         
     def write_source_comment(self, node):
         if self.last_source_line != node.lineno:
@@ -331,7 +340,7 @@
                 
     def visitIncludeTag(self, node):
         self.write_source_comment(node)
-        self.printer.writeline("runtime.include_file(context, %s, import_symbols=%s)" % (node.parsed_attributes['file'], repr(node.attributes.get('import', False))))
+        self.printer.writeline("runtime.include_file(context, %s, _template_filename)" % (node.parsed_attributes['file']))
 
     def visitNamespaceTag(self, node):
         pass
@@ -360,7 +369,7 @@
                 "context.push_buffer()",
                 "try:"
             )
-        self.write_variable_declares(body_identifiers, first="kwargs")
+        self.write_variable_declares(body_identifiers)
         for n in node.nodes:
             n.accept_visitor(self)
         self.write_def_finish(node, buffered, False)
diff --git a/lib/mako/lookup.py b/lib/mako/lookup.py
index 6bdf586..4670eb5 100644
--- a/lib/mako/lookup.py
+++ b/lib/mako/lookup.py
@@ -20,7 +20,7 @@
             return True
         except exceptions.TemplateLookupException, e:
             return False
-    def get_template(self, uri):
+    def get_template(self, uri, relativeto=None):
         raise NotImplementedError()
         
 class TemplateLookup(TemplateCollection):
@@ -36,15 +36,26 @@
             self.__collection = util.LRUCache(collection_size)
         self._mutex = threading.Lock()
         
-    def get_template(self, uri):
+    def get_template(self, uri, relativeto=None):
             try:
                 if self.filesystem_checks:
                     return self.__check(uri, self.__collection[uri])
                 else:
                     return self.__collection[uri]
             except KeyError:
-                u = re.sub(r'^\/+', '', uri)
+                if uri[0] != '/':
+                    u = uri
+                    if relativeto is not None:
+                        for dir in self.directories:
+                            print relativeto[0:len(dir)]
+                            if relativeto[0:len(dir)] == dir:
+                                u = posixpath.join(posixpath.dirname(relativeto[len(dir) + 1:]), u)
+                                break
+                else:
+                    u = re.sub(r'^\/+', '', uri)
+
                 for dir in self.directories:
+                    
                     srcfile = posixpath.join(dir, u)
                     if os.access(srcfile, os.F_OK):
                         return self.__load(srcfile, uri)
diff --git a/lib/mako/parsetree.py b/lib/mako/parsetree.py
index 3aae9df..d1a35a1 100644
--- a/lib/mako/parsetree.py
+++ b/lib/mako/parsetree.py
@@ -223,7 +223,7 @@
 class NamespaceTag(Tag):
     __keyword__ = 'namespace'
     def __init__(self, keyword, attributes, **kwargs):
-        super(NamespaceTag, self).__init__(keyword, attributes, (), ('name','inheritable','file'), ('name',), **kwargs)
+        super(NamespaceTag, self).__init__(keyword, attributes, (), ('name','inheritable','file','import'), ('name',), **kwargs)
         self.name = attributes['name']
     def declared_identifiers(self):
         return []
diff --git a/lib/mako/runtime.py b/lib/mako/runtime.py
index 01a23a9..099c6b2 100644
--- a/lib/mako/runtime.py
+++ b/lib/mako/runtime.py
@@ -77,11 +77,11 @@
    
 class Namespace(object):
     """provides access to collections of rendering methods, which can be local, from other templates, or from imported modules"""
-    def __init__(self, name, context, module=None, template=None, templateuri=None, callables=None, inherits=None, populate_self=True):
+    def __init__(self, name, context, module=None, template=None, templateuri=None, callables=None, inherits=None, populate_self=True, calling_filename=None):
         self.name = name
         self._module = module
         if templateuri is not None:
-            self.template = _lookup_template(context, templateuri)
+            self.template = _lookup_template(context, templateuri, calling_filename)
         else:
             self.template = template
         self.context = context
@@ -96,6 +96,29 @@
     module = property(lambda s:s._module or s.template.module)
     filename = property(lambda s:s._module and s._module.__file__ or s.template.filename)
     
+    def populate(self, d, l):
+        for ident in l:
+            if ident == '*':
+                for (k, v) in self._get_star():
+                    d[k] = v
+            else:
+                d[ident] = getattr(self, ident)
+    
+    def _get_star(self):
+        if self.callables is not None:
+            for k in self.callables:
+                yield (k, self.callables[key])
+        if self.template is not None:
+            def get(key):
+                callable_ = self.template.get_def(key).callable_
+                return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
+            for k in self.template.module._exports:
+                yield (k, get(k))
+        if self.module is not None:
+            for k in dir(self.module):
+                if k[0] != '_':
+                    yield (k, getattr(self.module, k))
+                            
     def __getattr__(self, key):
         if self.callables is not None:
             try:
@@ -131,16 +154,16 @@
         buf = context.pop_buffer()
         return buf.getvalue()
         
-def include_file(context, uri, import_symbols):
+def include_file(context, uri, calling_filename):
     """locate the template from the given uri and include it in the current output."""
-    template = _lookup_template(context, uri)
+    template = _lookup_template(context, uri, calling_filename)
     (callable_, ctx) = _populate_self_namespace(context.clean_inheritance_tokens(), template)
     callable_(ctx)
         
-def inherit_from(context, uri):
+def inherit_from(context, uri, calling_filename):
     """called by the _inherit method in template modules to set up the inheritance chain at the start
     of a template's execution."""
-    template = _lookup_template(context, uri)
+    template = _lookup_template(context, uri, calling_filename)
     self_ns = context['self']
     ih = self_ns
     while ih.inherits is not None:
@@ -157,9 +180,9 @@
             gen_ns(context)
         return (template.callable_, lclcontext)
 
-def _lookup_template(context, uri):
+def _lookup_template(context, uri, relativeto):
     lookup = context._with_template.lookup
-    return lookup.get_template(uri)
+    return lookup.get_template(uri, relativeto)
 
 def _populate_self_namespace(context, template, self_ns=None):
     if self_ns is None:
diff --git a/test/def.py b/test/def.py
index 1513422..a0e409a 100644
--- a/test/def.py
+++ b/test/def.py
@@ -206,24 +206,20 @@
 
     def test_scope_nine(self):
         """test that 'enclosing scope' doesnt get exported to other templates"""
-        tmpl = {}
-        class LocalTmplCollection(lookup.TemplateCollection):
-            def get_template(self, uri):
-                return tmpl[uri]
-        collection = LocalTmplCollection()
         
-        tmpl['main'] = Template("""
+        l = lookup.TemplateLookup()
+        l.put_string('main', """
         <%
             x = 5
         %>
         this is main.  <%include file="secondary"/>
-""", lookup=collection)
+""")
 
-        tmpl['secondary'] = Template("""
+        l.put_string('secondary', """
         this is secondary.  x is ${x}
-""", lookup=collection)
+""")
 
-        assert flatten_result(tmpl['main'].render(x=2)) == "this is main. this is secondary. x is 2"
+        assert flatten_result(l.get_template('main').render(x=2)) == "this is main. this is secondary. x is 2"
         
     def test_scope_ten(self):
         t = Template("""
diff --git a/test/inheritance.py b/test/inheritance.py
index 3dc9f5d..28bc78f 100644
--- a/test/inheritance.py
+++ b/test/inheritance.py
@@ -5,13 +5,9 @@
 
 class InheritanceTest(unittest.TestCase):
     def test_basic(self):
-        tmpl = {}
-        class LocalTmplCollection(lookup.TemplateCollection):
-            def get_template(self, uri):
-                return tmpl[uri]
-        collection = LocalTmplCollection()
+        collection = lookup.TemplateLookup()
 
-        tmpl['main'] = Template("""
+        collection.put_string('main', """
 <%inherit file="base"/>
 
 <%def name="header">
@@ -19,9 +15,9 @@
 </%def>
 
 this is the content.
-""", lookup=collection)
+""")
 
-        tmpl['base'] = Template("""
+        collection.put_string('base', """
 This is base.
 
 header: ${self.header()}
@@ -33,9 +29,9 @@
 <%def name="footer">
     this is the footer. header again ${next.header()}
 </%def>
-""", lookup=collection)
+""")
 
-        assert result_lines(tmpl['main'].render()) == [
+        assert result_lines(collection.get_template('main').render()) == [
             'This is base.',
              'header:',
              'main header.',
diff --git a/test/lookup.py b/test/lookup.py
new file mode 100644
index 0000000..376bb2d
--- /dev/null
+++ b/test/lookup.py
@@ -0,0 +1,35 @@
+from mako.template import Template
+from mako import lookup
+from util import flatten_result, result_lines
+import unittest
+
+import os
+
+if not os.access('./test_htdocs', os.F_OK):
+    os.mkdir('./test_htdocs')
+    file('./test_htdocs/index.html', 'w').write("this is index")
+    file('./test_htdocs/incl.html', 'w').write("this is include 1")
+    os.mkdir('./test_htdocs/subdir')
+    file('./test_htdocs/subdir/incl.html', 'w').write("""
+        this is include 2
+    """)
+    file('./test_htdocs/subdir/index.html', 'w').write("""
+        this is sub index
+        <%include file="incl.html"/>
+    """)
+tl = lookup.TemplateLookup(directories=['./test_htdocs'])
+class LookupTest(unittest.TestCase):
+    def test_basic(self):
+        t = tl.get_template('index.html')
+        assert result_lines(t.render()) == [
+            "this is index"
+        ]
+    def test_subdir(self):
+        t = tl.get_template('/subdir/index.html')
+        assert result_lines(t.render()) == [
+            "this is sub index",
+            "this is include 2"
+        ]
+        
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file
diff --git a/test/namespace.py b/test/namespace.py
index 603aaa0..b8eb554 100644
--- a/test/namespace.py
+++ b/test/namespace.py
@@ -220,8 +220,106 @@
             "caller body:",
             "call body"
         ]
+
+    def test_import(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("functions.html","""
+            <%def name="foo">
+                this is foo
+            </%def>
+            
+            <%def name="bar">
+                this is bar
+            </%def>
+            
+            <%def name="lala">
+                this is lala
+            </%def>
+        """)
+
+        collection.put_string("func2.html", """
+            <%def name="a">
+                this is a
+            </%def>
+            <%def name="b">
+                this is b
+            </%def>
+        """)
+        collection.put_string("index.html", """
+            <%namespace name="func" file="functions.html" import="*"/>
+            <%namespace name="func2" file="func2.html" import="a, b"/>
+            ${foo()}
+            ${bar()}
+            ${lala()}
+            ${a()}
+            ${b()}
+            ${x}
+        """)
+        assert result_lines(collection.get_template("index.html").render(bar="this is bar", x="this is x")) == [
+            "this is foo",
+            "this is bar",
+            "this is lala",
+            "this is a",
+            "this is b",
+            "this is x"
+        ]
         
+    def test_closure_import(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("functions.html","""
+            <%def name="foo">
+                this is foo
+            </%def>
+            
+            <%def name="bar">
+                this is bar
+            </%def>
+        """)
         
+        collection.put_string("index.html", """
+            <%namespace name="func" file="functions.html" import="*"/>
+            <%def name="cl1">
+                ${foo()}
+            </%def>
+            
+            <%def name="cl2">
+                ${bar()}
+            </%def>
+            
+            ${cl1()}
+            ${cl2()}
+        """)
+        assert result_lines(collection.get_template("index.html").render(bar="this is bar", x="this is x")) == [
+            "this is foo",
+            "this is bar",
+        ]
+
+    def test_ccall_import(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("functions.html","""
+            <%def name="foo">
+                this is foo
+            </%def>
+            
+            <%def name="bar">
+                this is bar.
+                ${caller.body()}
+                ${caller.lala()}
+            </%def>
+        """)
         
+        collection.put_string("index.html", """
+            <%namespace name="func" file="functions.html" import="*"/>
+            <%call expr="bar()">
+                this is index embedded
+                foo is ${foo()}
+                <%def name="lala">
+                     this is lala ${foo()}
+                </%def>
+            </%call>
+        """)
+        print collection.get_template("index.html").code
+        print collection.get_template("index.html").render()
+
 if __name__ == '__main__':
     unittest.main()