diff --git a/doc/build/templates/base.html b/doc/build/templates/base.html
index 109a111557e28d9bf5097856adc9bf968fb97e0b..a26fd5b15828f4a2706a3d8e9b223036631a07ae 100644
--- a/doc/build/templates/base.html
+++ b/doc/build/templates/base.html
@@ -23,11 +23,11 @@
     version = toc.version
     last_updated = toc.last_updated
 
-    extension = context.get('extension', 'html')
-    paged = context.get('paged', True)
-    requestattr['extension'] = extension
-    requestattr['paged'] = paged
-    requestattr['toc'] = toc
+    kwargs = context.kwargs
+    kwargs.setdefault('extension', 'html')
+    extension = kwargs['extension']
+    kwargs.setdefault('paged', True)
+    kwargs.setdefault('toc', toc)
 %>
 
 <div id="topanchor"><a name="top"></a>&nbsp;</div>
@@ -38,7 +38,7 @@
 
 <div class="versionheader">Version: ${version}   Last Updated: ${time.strftime('%x %X', time.localtime(last_updated))}</div>
 
-${next.body()}
+${next.body(**kwargs)}
 
 
 
diff --git a/doc/build/templates/content_layout.html b/doc/build/templates/content_layout.html
index d9be1298e2ded62a51a517d5b26296921a0d6739..587eaaaeda78cf877e2fbccf9fdc717f9e558286 100644
--- a/doc/build/templates/content_layout.html
+++ b/doc/build/templates/content_layout.html
@@ -4,11 +4,11 @@
 <%namespace file="nav.html" import="topnav"/>
 
 <%
-    current = requestattr['toc'].get_by_file(self.template.module.filename)
+    current = toc.get_by_file(self.template.module.filename)
 %>
 
 <A name="<% current.path %>"></a>
 
 ${topnav(item=current)}
 
-${next.body()}
+${next.body(**context.kwargs)}
diff --git a/doc/build/templates/formatting.html b/doc/build/templates/formatting.html
index 13bfdb18951d94262255fbbfcc5aaed79c0710bf..6e9c16ca517475ee71766c30c1317ea18802a08b 100644
--- a/doc/build/templates/formatting.html
+++ b/doc/build/templates/formatting.html
@@ -16,7 +16,6 @@
 <%def name="section(path, description=None)">
     # Main section formatting element.
     <%
-        toc = requestattr['toc']
         item = toc.get_by_path(path)
         subsection = item.depth > 1
     %>
diff --git a/doc/build/templates/nav.html b/doc/build/templates/nav.html
index a4b6044a9cdec8ebca3649dbd315d6aeaf55e56d..c3ad05ead0cacac5ffe6101734d1e61713e0a244 100644
--- a/doc/build/templates/nav.html
+++ b/doc/build/templates/nav.html
@@ -3,12 +3,11 @@
 <%namespace name="tocns" file="toc.html"/>
 
 <%def name="itemlink(item, anchor=True)" filter="trim">
-    <a href="${ item.get_link(anchor=anchor, usefilename=requestattr['paged']) }">${ item.description }</a>
+    <a href="${ item.get_link(anchor=anchor, usefilename=paged) }">${ item.description }</a>
 </%def>
 
 <%def name="toclink(path, description=None)" filter="trim">
     <%
-        toc = requestattr['toc']
         item = toc.get_by_path(path)
         if description is None:
             if item:
@@ -16,12 +15,12 @@
             else:
                 description = path
         if item:
-            anchor = not requestattr['paged'] or item.depth > 1
+            anchor = not paged or item.depth > 1
         else: 
             anchor = False
     %>
     % if item:
-        <a href="${ item.get_link(extension=requestattr['extension'], anchor=anchor, usefilename=requestattr['paged']) }">${ description }</a>
+        <a href="${ item.get_link(extension=extension, anchor=anchor, usefilename=paged) }">${ description }</a>
     % else:
         <b>${ description }</b>
     % endif
@@ -39,7 +38,7 @@
         ${pagenav(item)}
     </div>
 
-    <h3><a href="index.${ requestattr['extension'] }">Table of Contents</a></h3>
+    <h3><a href="index.${ extension }">Table of Contents</a></h3>
     <br/>
 	${itemlink(item=item, anchor=True)}
 	
@@ -49,11 +48,11 @@
 
 <%def name="pagenav(item)">
     % if item.previous is not None:
-        Previous: ${itemlink(item=item.previous, anchor=not requestattr['paged'])}
+        Previous: ${itemlink(item=item.previous, anchor=not paged)}
     % endif
 
     % if item.next is not None:
         ${item.previous is not None and "|" or ""}
-        Next: ${itemlink(item=item.next, anchor=not requestattr['paged'])}
+        Next: ${itemlink(item=item.next, anchor=not paged)}
     % endif
 </%def>
diff --git a/doc/build/templates/toc.html b/doc/build/templates/toc.html
index 1fcde011a7c23065f3a07cf369a94f36aa3310f3..87f256ecb84c3e37c001148e893c32927c3c70ef 100644
--- a/doc/build/templates/toc.html
+++ b/doc/build/templates/toc.html
@@ -6,7 +6,7 @@
 	<a name="full_index"></a>
 	<h3>Table of Contents</h3>
 	
-	${printtoc(root=requestattr['toc'],current=None,full=True,children=True,anchor_toplevel=False)}
+	${printtoc(root=context.get('toc'),current=None,full=True,children=True,anchor_toplevel=False)}
 
 	</div>
 </%def>
@@ -15,7 +15,7 @@
 <%def name="printtoc(root,current=None,full=False,children=True,anchor_toplevel=False)">
     <ul>
     % for item in root.children:
-        <li><A style="${item is current and "font-weight:bold;" or "" }" href="${item.get_link(extension=requestattr['extension'],anchor=anchor_toplevel, usefilename=paged) }">${item.description}</a></li>
+        <li><A style="${item is current and "font-weight:bold;" or "" }" href="${item.get_link(extension=extension,anchor=anchor_toplevel, usefilename=paged) }">${item.description}</a></li>
         
         % if children:
             ${printtoc(item, current=current, full=full,children=True,anchor_toplevel=True)}
diff --git a/lib/mako/ast.py b/lib/mako/ast.py
index c2e039479295a0867d07f14401964fcfa2cb91a1..e44e5a8ff3b35a353b8a27390fe1edd8cd9aa2ca 100644
--- a/lib/mako/ast.py
+++ b/lib/mako/ast.py
@@ -145,7 +145,7 @@ class walker(visitor.ASTVisitor):
         
 class FunctionDecl(object):
     """function declaration"""
-    def __init__(self, code, lineno, pos, filename):
+    def __init__(self, code, lineno, pos, filename, allow_kwargs=True):
         self.code = code
         expr = parse(code, "exec", lineno, pos, filename)
         class ParseFunc(object):
@@ -160,6 +160,9 @@ class FunctionDecl(object):
         visitor.walk(expr, f)
         if not hasattr(self, 'funcname'):
             raise exceptions.CompileException("Code '%s' is not a function declaration" % code, lineno, pos, filename)
+        if not allow_kwargs and self.kwargs:
+            raise exceptions.CompileException("'**%s' keyword argument not allowed here" % self.argnames[-1], lineno, pos, filename)
+            
     def get_argument_expressions(self, include_defaults=True):
         """return the argument declarations of this FunctionDecl as a printable list."""
         namedecls = []
@@ -186,8 +189,8 @@ class FunctionDecl(object):
 
 class FunctionArgs(FunctionDecl):
     """the argument portion of a function declaration"""
-    def __init__(self, code, lineno, pos, filename):
-        super(FunctionArgs, self).__init__("def ANON(%s):pass" % code, lineno, pos, filename)
+    def __init__(self, code, lineno, pos, filename, **kwargs):
+        super(FunctionArgs, self).__init__("def ANON(%s):pass" % code, lineno, pos, filename, **kwargs)
         
             
 class ExpressionGenerator(object):
diff --git a/lib/mako/codegen.py b/lib/mako/codegen.py
index e744ee7d2d971d370110393d1a1bb377edaec9c3..0c538cde9b04a1d39b512cfdeadc00739dbb61db 100644
--- a/lib/mako/codegen.py
+++ b/lib/mako/codegen.py
@@ -47,16 +47,20 @@ class _GenerateRenderMethod(object):
         else:
             (pagetag, defs) = self.write_toplevel()
             name = "render_body"
-            args = None
+            if pagetag is not None:
+                args = pagetag.body_decl.get_argument_expressions()
+                if not pagetag.body_decl.kwargs:
+                    args += ['**_extra_pageargs']
+                cached = eval(pagetag.attributes.get('cached', 'False'))
+            else:
+                args = ['**_extra_pageargs']
+                cached = False
             buffered = filtered = False
             self.compiler.pagetag = pagetag
-            cached = pagetag is not None and eval(pagetag.attributes.get('cached', 'False'))
         if args is None:
             args = ['context']
         else:
             args = [a for a in ['context'] + args]
-        if not self.in_def:
-            args.append('**kwargs')
             
         self.write_render_callable(pagetag or node, name, args, buffered, filtered, cached)
         
@@ -137,10 +141,8 @@ class _GenerateRenderMethod(object):
 
         self.identifier_stack.append(self.compiler.identifiers.branch(self.node))
 
-        if not self.in_def:
-            self.printer.writeline("context = context.locals_(kwargs)")
-        if not self.in_def and len(self.identifiers.locally_assigned) > 0:
-            self.printer.writeline("__locals = {}")
+        if not self.in_def and (len(self.identifiers.locally_assigned) > 0 or len(self.identifiers.argument_declared)>0):
+            self.printer.writeline("__locals = dict(%s)" % ','.join("%s=%s" % (x, x) for x in self.identifiers.argument_declared))
 
         self.write_variable_declares(self.identifiers, toplevel=True)
 
@@ -244,7 +246,7 @@ class _GenerateRenderMethod(object):
         # (this is used for the caching decorator)
         if limit is not None:
             to_write = to_write.intersection(limit)
-            
+        
         if toplevel and getattr(self.compiler, 'has_ns_imports', False):
             self.printer.writeline("_import_ns = {}")
             self.compiler.has_imports = True
@@ -278,7 +280,7 @@ class _GenerateRenderMethod(object):
         funcname = node.function_decl.funcname
         namedecls = node.function_decl.get_argument_expressions()
         nameargs = node.function_decl.get_argument_expressions(include_defaults=False)
-        if not self.in_def and len(self.identifiers.locally_assigned) > 0:
+        if not self.in_def and (len(self.identifiers.locally_assigned) > 0 or len(self.identifiers.argument_declared) > 0):
             nameargs.insert(0, 'context.locals_(__locals)')
         else:
             nameargs.insert(0, 'context')
@@ -568,7 +570,10 @@ class _Identifiers(object):
     def visitIncludeTag(self, node):
         self.check_declared(node)
     def visitPageTag(self, node):
-        self.check_declared(node)            
+        for ident in node.declared_identifiers():
+            self.argument_declared.add(ident)
+        self.check_declared(node)
+                    
     def visitCallTag(self, node):
         if node is self.node:
             for ident in node.undeclared_identifiers():
diff --git a/lib/mako/exceptions.py b/lib/mako/exceptions.py
index 15e77d33e04ac545d01de3cfdcce84d68212a634..064ce3f7f53ef378db2f774093acabe8fd7a760e 100644
--- a/lib/mako/exceptions.py
+++ b/lib/mako/exceptions.py
@@ -75,7 +75,7 @@ class RichTraceback(object):
         self.reverse_records.reverse()
     def _get_reformatted_records(self, records):
         for rec in records:
-            if rec[6]:
+            if rec[6] is not None:
                 yield (rec[4], rec[5], rec[2], rec[6])
             else:
                 yield tuple(rec[0:4])
@@ -97,7 +97,7 @@ class RichTraceback(object):
         rawrecords = traceback.extract_tb(trcback)
         new_trcback = []
         for filename, lineno, function, line in rawrecords:
-            #print "TB", filename, lineno, function, line
+            print "TB", filename, lineno, function, line
             try:
                 (line_map, template_lines) = mods[filename]
             except KeyError:
@@ -129,6 +129,7 @@ class RichTraceback(object):
             else:
                 template_line = None
             new_trcback.append((filename, lineno, function, line, template_filename, template_ln, template_line, template_source))
+            print "AND THE TB IS", new_trcback[-1]
         if not self.source:
             for l in range(len(new_trcback)-1, 0, -1):
                 if new_trcback[l][5]:
diff --git a/lib/mako/parsetree.py b/lib/mako/parsetree.py
index 99cb9dc392cd8bb3952a556639bacc72d8e6149f..fd4741d0c2d01f11b7a3a117873a9a992866e151 100644
--- a/lib/mako/parsetree.py
+++ b/lib/mako/parsetree.py
@@ -274,5 +274,9 @@ class InheritTag(Tag):
 class PageTag(Tag):
     __keyword__ = 'page'
     def __init__(self, keyword, attributes, **kwargs):
-        super(PageTag, self).__init__(keyword, attributes, ('cached', 'cache_key', 'cache_timeout', 'cache_type', 'cache_dir'), (), (), **kwargs)
+        super(PageTag, self).__init__(keyword, attributes, ('cached', 'cache_key', 'cache_timeout', 'cache_type', 'cache_dir', 'args'), (), (), **kwargs)
+        self.body_decl = ast.FunctionArgs(attributes.get('args', ''), self.lineno, self.pos, self.filename)
+    def declared_identifiers(self):
+        return self.body_decl.argnames
+        
     
\ No newline at end of file
diff --git a/lib/mako/runtime.py b/lib/mako/runtime.py
index 254ddee2054bd464471fce68640caafef501662e..22851df8b9dd54ed877da6d9391151a609688b2b 100644
--- a/lib/mako/runtime.py
+++ b/lib/mako/runtime.py
@@ -14,6 +14,7 @@ class Context(object):
     def __init__(self, buffer, **data):
         self._buffer_stack = [buffer]
         self._data = data
+        self._kwargs = data.copy()
         self._with_template = None
         self.namespaces = {}
         
@@ -24,12 +25,11 @@ class Context(object):
         self.caller_stack = [Undefined]
         data['caller'] = _StackFacade(self.caller_stack)
     lookup = property(lambda self:self._with_template.lookup)
+    kwargs = property(lambda self:self._kwargs.copy())
     def keys(self):
         return self._data.keys()
     def __getitem__(self, key):
         return self._data[key]
-    def _put(self, key, value):
-        self._data[key] = value
     def push_buffer(self):
         """push a capturing buffer onto this Context."""
         self._buffer_stack.append(util.FastEncodingBuffer())
@@ -45,6 +45,7 @@ class Context(object):
         c = Context.__new__(Context)
         c._buffer_stack = self._buffer_stack
         c._data = self._data.copy()
+        c._kwargs = self._kwargs
         c._with_template = self._with_template
         c.namespaces = self.namespaces
         c.caller_stack = self.caller_stack
@@ -154,9 +155,6 @@ class Namespace(object):
                     yield (k, getattr(self.module, k))
                             
     def __getattr__(self, key):
-        return self._get_callable(key)
-        
-    def _get_callable(self, key):
         if self.callables is not None:
             try:
                 return self.callables[key]
diff --git a/test/def.py b/test/def.py
index 4214fc7035e6399a2bd793298ca4753e974e44a5..b9aad1bc686538109b94c6637f1c12c9c3ff7841 100644
--- a/test/def.py
+++ b/test/def.py
@@ -326,6 +326,7 @@ class ScopeTest(unittest.TestCase):
         
         l.put_string("main", """
             <%inherit file="base"/>
+            <%page args="x"/>
             this is main.  x is ${x}
             
             ${a()}
@@ -336,7 +337,7 @@ class ScopeTest(unittest.TestCase):
         """)
         
         # test via inheritance
-        #print l.get_template("main").code
+        print l.get_template("main").code
         assert result_lines(l.get_template("main").render()) == [
             "this is main. x is 12",
             "this is a, x is 12"
diff --git a/test/inheritance.py b/test/inheritance.py
index e3a59d411cbcbed3dcf09d3c493234fe1867abcc..096c7f651c32f48f9301bf1a139a4e50ed327288 100644
--- a/test/inheritance.py
+++ b/test/inheritance.py
@@ -181,6 +181,73 @@ ${next.body()}
          'c is: secondary_c. a is layout_a b is base_b d is secondary_d.'
          ]
 
+    def test_pageargs(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("base", """
+            this is the base.
+            
+            <%def name="foo()">
+                ${next.body(**context.kwargs)}
+            </%def>
+            
+            ${foo()}
+        """)
+        collection.put_string("index", """
+            <%inherit file="base"/>
+            <%page args="x, y, z=7"/>
+            print ${x}, ${y}, ${z}
+        """)
+        assert result_lines(collection.get_template('index').render(x=5,y=10)) == [
+            "this is the base.",
+            "print 5, 10, 7"
+        ]
+    def test_pageargs_2(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("base", """
+            this is the base.
+            
+            ${next.body(**context.kwargs)}
+            
+            <%def name="foo(**kwargs)">
+                ${next.body(**kwargs)}
+            </%def>
+
+            <%def name="bar(**otherargs)">
+                ${next.body(z=16, **context.kwargs)}
+            </%def>
+
+            ${foo(x=12, y=15, z=8)}
+            ${bar(x=19, y=17)}
+        """)
+        collection.put_string("index", """
+            <%inherit file="base"/>
+            <%page args="x, y, z=7"/>
+            pageargs: ${x}, ${y}, ${z}
+        """)
+        assert result_lines(collection.get_template('index').render(x=5,y=10)) == [
+            "this is the base.",
+            "pageargs: 5, 10, 7",
+            "pageargs: 12, 15, 8",
+            "pageargs: 5, 10, 16"
+        ]
+    
+    def test_pageargs_err(self):
+        collection = lookup.TemplateLookup()
+        collection.put_string("base", """
+            this is the base.
+            ${next.body()}
+        """)
+        collection.put_string("index", """
+            <%inherit file="base"/>
+            <%page args="x, y, z=7"/>
+            print ${x}, ${y}, ${z}
+        """)
+        try:
+            print collection.get_template('index').render(x=5,y=10)
+            assert False
+        except TypeError:
+            assert True
+            
     def test_dynamic(self):
         collection = lookup.TemplateLookup()
         collection.put_string("base", """
diff --git a/test/lexer.py b/test/lexer.py
index e51947ba1276552d1c2cfb2f3612d46999e8cc1a..04c157ddbbc897539bbdd8fb90f367dacdb8082d 100644
--- a/test/lexer.py
+++ b/test/lexer.py
@@ -132,6 +132,14 @@ class LexerTest(unittest.TestCase):
         #print nodes
         assert repr(nodes) == r"""TemplateNode({}, [Text('\n            ', (1, 1)), CallTag('call', {'expr': "foo>bar and 'lala' or 'hoho'"}, (2, 13), []), Text('\n            ', (2, 57)), CallTag('call', {'expr': 'foo<bar and hoho>lala and "x" + "y"'}, (3, 13), []), Text('\n        ', (3, 64))])"""
         
+    def test_pagetag(self):
+        template = """
+            <%page cached="True", args="a, b"/>
+            
+            some template
+        """    
+        nodes = Lexer(template).parse()
+        assert repr(nodes) == r"""TemplateNode({}, [Text('\n            ', (1, 1)), PageTag('page', {'cached': 'True', 'args': 'a, b'}, (2, 13), []), Text('\n            \n            some template\n        ', (2, 48))])"""
         
     def test_nesting(self):
         template = """
diff --git a/test/template.py b/test/template.py
index 543f35acfd90e3636be66dddc55f05fa79d6b0ff..00de06c5029c07d619a2806b72a8b2879a9b01ce 100644
--- a/test/template.py
+++ b/test/template.py
@@ -28,6 +28,40 @@ class EncodingTest(unittest.TestCase):
         val = "# -*- encoding: utf-8 -*-\n" + val.encode('utf-8')
         template = Template(val)
         assert template.render_unicode() == u"""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petit voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""
+
+    def test_encoding(self):
+        val = u"""Alors vous imaginez ma surprise, au lever du jour, quand une drôle de petit voix m’a réveillé. Elle disait: « S’il vous plaît… dessine-moi un mouton! »"""
+        template = Template(val, output_encoding='utf-8')
+        assert template.render() == val.encode('utf-8')
+
+class PageArgsTest(unittest.TestCase):
+    def test_basic(self):
+        template = Template("""
+            <%page args="x, y, z=7"/>
+            
+            this is page, ${x}, ${y}, ${z}
+""")
+
+        assert flatten_result(template.render(x=5, y=10)) == "this is page, 5, 10, 7"
+        assert flatten_result(template.render(x=5, y=10, z=32)) == "this is page, 5, 10, 32"
+        try:
+            template.render(y=10)
+            assert False
+        except TypeError, e:
+            assert True
+
+    def test_with_context(self):
+        template = Template("""
+            <%page args="x, y, z=7"/>
+
+            this is page, ${x}, ${y}, ${z}, ${w}
+""")
+
+        assert flatten_result(template.render(x=5, y=10, w=17)) == "this is page, 5, 10, 7, 17"
+
+
+        
+
         
 class ControlTest(unittest.TestCase):
     def test_control(self):