TemplateNotFound(template) with Google App Engine & Jinja2
I'm getting a TemplateNotFound error on Google App Engine with Jinja2 (complete stack trace below.)

What I expect to see is the index.html with the "greet" variable passed to the index.html template file.  What I don't understand is why I get the template not found error when the path to index.html in the TraceBack is correct.

What I've tried...

- tried a relative path by taking out "os.path.dirname(__file__)" in template path.
- using "template" instead of themes as a directory name.


Here is my code.

**app.yaml**

    application: codemywayout
    version: 1
    runtime: python27
    api_version: 1
    threadsafe: true
    
    handlers:
    
    - url: /admin/.*
      script: admin.app
      login: admin
    
    - url: /static/([^/]+)/(.*)
      static_files: template/\1/static/\2
      upload: static/.*
    
    - url: /favicon\.ico
      static_files: favicon.ico
      upload: favicon\.ico
    
    - url: .*
      script: static.app
    
    builtins:
    - remote_api: on
    
    libraries:
    - name: webapp2
      version: "2.5.1"
    - name: jinja2
      version: latest

**admin.py**

    from google.appengine.ext import db
    import webapp2
    import jinja2
    import os
    import config
    
    
    def render_template(template_name, template_vals=None, theme=None):
        template_path = os.path.join(os.path.dirname(__file__) , \
                "themes", theme or config.theme, template_name)
        env = jinja2.Environment(
            loader=jinja2.FileSystemLoader(template_path))
        return env.get_template(template_path, template_vals or {})
        
    class BlogPost(db.Model):
        title = db.StringProperty()
        body = db.StringProperty()
    
    def render(self):
        greet = "greet"
        template_vals = {
            'config': config,
            'post': self,
            'greet': greet,
        }
        return render_template("post.html", template_vals)
    
    class BaseHandler(webapp2.RequestHandler):
        def render_to_response(self, template_name, \
                template_vals=None, theme=None):
            template_name = os.path.join("admin", template_name)
            self.response.out.write(render_template(template_name,\
                template_vals, theme))
    
    class AdminHandler(BaseHandler):
        def get(self):
          offset = int(self.request.get('start', 0))
          count = int(self.request.get('count', 20))
          posts = BlogPost.all().fetch(count, offset)
          template_vals = {
              'offset': offset,
              'count': count,
              'last_post': offset + len(posts) - 1,
              'prev_offset': max(0, offset - count),
              'next_offset': offset + count,
              'posts': posts,
          }
          self.render_to_response("index.html", template_vals)
    
    app = webapp2.WSGIApplication([('/admin/', AdminHandler)],debug=True)

**config.py**

    # Name of the blog
    blog_name = 'My Blog'
    
    # Selects the theme to use. Theme names correspond to directories under
    # the 'themes' directory, containing templates and static content.
    theme = 'default'
    
    # Defines the URL organization to use for blog postings. Valid substitutions:
    #   slug - the identifier for the post, derived from the title
    #   year - the year the post was published in
    #   month - the month the post was published in
    #   day - the day the post was published in
    
    # URL Options
    #   post_path_format = '/%(year)d/%(month)02d/%(slug)s'
    post_path_format = '/%(slug)s'

**TraceBack**

    Traceback (most recent call last):
      File "C:\Users\john\webdev\google\lib\webapp2\webapp2.py", line 1536, in __call__
        rv = self.handle_exception(request, response, e)
      File "C:\Users\john\webdev\google\lib\webapp2\webapp2.py", line 1530, in __call__
        rv = self.router.dispatch(request, response)
      File "C:\Users\john\webdev\google\lib\webapp2\webapp2.py", line 1278, in default_dispatcher
        return route.handler_adapter(request, response)
      File "C:\Users\john\webdev\google\lib\webapp2\webapp2.py", line 1102, in __call__
        return handler.dispatch()
      File "C:\Users\john\webdev\google\lib\webapp2\webapp2.py", line 572, in dispatch
        return self.handle_exception(e, self.app.debug)
      File "C:\Users\john\webdev\google\lib\webapp2\webapp2.py", line 570, in dispatch
        return method(*args, **kwargs)
      File "C:\Users\john\webdev\workspace\codemywayout\admin.py", line 49, in get
        self.render_to_response("index.html", template_vals)
      File "C:\Users\john\webdev\workspace\codemywayout\admin.py", line 34, in render_to_response
        template_vals, theme))
      File "C:\Users\john\webdev\workspace\codemywayout\admin.py", line 14, in render_template
        return env.get_template(template_path, template_vals or {})
      File "C:\Users\john\webdev\google\lib\jinja2\jinja2\environment.py", line 719, in get_template
        return self._load_template(name, self.make_globals(globals))
      File "C:\Users\john\webdev\google\lib\jinja2\jinja2\environment.py", line 693, in _load_template
        template = self.loader.load(self, name, globals)
      File "C:\Users\john\webdev\google\lib\jinja2\jinja2\loaders.py", line 115, in load
        source, filename, uptodate = self.get_source(environment, name)
      File "C:\Users\john\webdev\google\lib\jinja2\jinja2\loaders.py", line 162, in get_source
        pieces = split_template_path(template)
      File "C:\Users\john\webdev\google\lib\jinja2\jinja2\loaders.py", line 33, in split_template_path
        raise TemplateNotFound(template)
    TemplateNotFound: C:\Users\john\webdev\workspace\codemywayout\themes\default\admin\index.html


TemplateNotFound(template) with Google App Engine & Jinja2
===

I'm getting a TemplateNotFound error on Google App Engine with Jinja2 (complete stack trace below.)

What I expect to see is the index.html with the "greet" variable passed to the index.html template file.  What I don't understand is why I get the template not found error when the path to index.html in the TraceBack is correct.

What I've tried...

- tried a relative path by taking out "os.path.dirname(__file__)" in template path.
- using "template" instead of themes as a directory name.


Here is my code.

**app.yaml**

    application: codemywayout
    version: 1
    runtime: python27
    api_version: 1
    threadsafe: true
    
    handlers:
    
    - url: /admin/.*
      script: admin.app
      login: admin
    
    - url: /static/([^/]+)/(.*)
      static_files: template/\1/static/\2
      upload: static/.*
    
    - url: /favicon\.ico
      static_files: favicon.ico
      upload: favicon\.ico
    
    - url: .*
      script: static.app
    
    builtins:
    - remote_api: on
    
    libraries:
    - name: webapp2
      version: "2.5.1"
    - name: jinja2
      version: latest

**admin.py**

    from google.appengine.ext import db
    import webapp2
    import jinja2
    import os
    import config
    
    
    def render_template(template_name, template_vals=None, theme=None):
        template_path = os.path.join(os.path.dirname(__file__) , \
                "themes", theme or config.theme, template_name)
        env = jinja2.Environment(
            loader=jinja2.FileSystemLoader(template_path))
        return env.get_template(template_path, template_vals or {})
        
    class BlogPost(db.Model):
        title = db.StringProperty()
        body = db.StringProperty()
    
    def render(self):
        greet = "greet"
        template_vals = {
            'config': config,
            'post': self,
            'greet': greet,
        }
        return render_template("post.html", template_vals)
    
    class BaseHandler(webapp2.RequestHandler):
        def render_to_response(self, template_name, \
                template_vals=None, theme=None):
            template_name = os.path.join("admin", template_name)
            self.response.out.write(render_template(template_name,\
                template_vals, theme))
    
    class AdminHandler(BaseHandler):
        def get(self):
          offset = int(self.request.get('start', 0))
          count = int(self.request.get('count', 20))
          posts = BlogPost.all().fetch(count, offset)
          template_vals = {
              'offset': offset,
              'count': count,
              'last_post': offset + len(posts) - 1,
              'prev_offset': max(0, offset - count),
              'next_offset': offset + count,
              'posts': posts,
          }
          self.render_to_response("index.html", template_vals)
    
    app = webapp2.WSGIApplication([('/admin/', AdminHandler)],debug=True)

**config.py**

    # Name of the blog
    blog_name = 'My Blog'
    
    # Selects the theme to use. Theme names correspond to directories under
    # the 'themes' directory, containing templates and static content.
    theme = 'default'
    
    # Defines the URL organization to use for blog postings. Valid substitutions:
    #   slug - the identifier for the post, derived from the title
    #   year - the year the post was published in
    #   month - the month the post was published in
    #   day - the day the post was published in
    
    # URL Options
    #   post_path_format = '/%(year)d/%(month)02d/%(slug)s'
    post_path_format = '/%(slug)s'

**TraceBack**

    Traceback (most recent call last):
      File "C:\Users\john\webdev\google\lib\webapp2\webapp2.py", line 1536, in __call__
        rv = self.handle_exception(request, response, e)
      File "C:\Users\john\webdev\google\lib\webapp2\webapp2.py", line 1530, in __call__
        rv = self.router.dispatch(request, response)
      File "C:\Users\john\webdev\google\lib\webapp2\webapp2.py", line 1278, in default_dispatcher
        return route.handler_adapter(request, response)
      File "C:\Users\john\webdev\google\lib\webapp2\webapp2.py", line 1102, in __call__
        return handler.dispatch()
      File "C:\Users\john\webdev\google\lib\webapp2\webapp2.py", line 572, in dispatch
        return self.handle_exception(e, self.app.debug)
      File "C:\Users\john\webdev\google\lib\webapp2\webapp2.py", line 570, in dispatch
        return method(*args, **kwargs)
      File "C:\Users\john\webdev\workspace\codemywayout\admin.py", line 49, in get
        self.render_to_response("index.html", template_vals)
      File "C:\Users\john\webdev\workspace\codemywayout\admin.py", line 34, in render_to_response
        template_vals, theme))
      File "C:\Users\john\webdev\workspace\codemywayout\admin.py", line 14, in render_template
        return env.get_template(template_path, template_vals or {})
      File "C:\Users\john\webdev\google\lib\jinja2\jinja2\environment.py", line 719, in get_template
        return self._load_template(name, self.make_globals(globals))
      File "C:\Users\john\webdev\google\lib\jinja2\jinja2\environment.py", line 693, in _load_template
        template = self.loader.load(self, name, globals)
      File "C:\Users\john\webdev\google\lib\jinja2\jinja2\loaders.py", line 115, in load
        source, filename, uptodate = self.get_source(environment, name)
      File "C:\Users\john\webdev\google\lib\jinja2\jinja2\loaders.py", line 162, in get_source
        pieces = split_template_path(template)
      File "C:\Users\john\webdev\google\lib\jinja2\jinja2\loaders.py", line 33, in split_template_path
        raise TemplateNotFound(template)
    TemplateNotFound: C:\Users\john\webdev\workspace\codemywayout\themes\default\admin\index.html

