Repository: web2py/web2py

Issue:
compiled app's views aren't executed
This PR https://github.com/web2py/web2py/pull/1194 broke compiled apps. 
Before reverting and releasing, I propose a reassessment of the whole compileapp.py (seems that we can order both code and "thoughs" once and for all). I opened a relevant discussion on web2py-developers



Discussion:

Resolving patch:
diff --git a/gluon/compileapp.py b/gluon/compileapp.py
--- a/gluon/compileapp.py
+++ b/gluon/compileapp.py
@@ -594,7 +594,7 @@ def run_controller_in(controller, function, environment):
     """
     Runs the controller.function() (for the app specified by
     the current folder).
-    It tries pre-compiled controller_function.pyc first before compiling it.
+    It tries pre-compiled controller.function.pyc first before compiling it.
     """
 
     # if compiled should run compiled!
@@ -606,20 +606,15 @@ def run_controller_in(controller, function, environment):
         filename = pjoin(path, 'controllers.%s.%s.pyc'
                          % (controller, function))
         if not os.path.exists(filename):
-            ### for backward compatibility
-            filename = pjoin(path, 'controllers_%s_%s.pyc'
-                             % (controller, function))
-            ### end for backward compatibility
-            if not os.path.exists(filename):
-                raise HTTP(404,
-                           rewrite.THREAD_LOCAL.routes.error_message % badf,
-                           web2py_error=badf)
+            raise HTTP(404,
+                       rewrite.THREAD_LOCAL.routes.error_message % badf,
+                       web2py_error=badf)
         code = getcfs(filename, filename, lambda: read_pyc(filename))
         restricted(code, environment, layer=filename)
     elif function == '_TEST':
         # TESTING: adjust the path to include site packages
-        from settings import global_settings
-        from admin import abspath, add_path_first
+        from gluon.settings import global_settings
+        from gluon.admin import abspath, add_path_first
         paths = (global_settings.gluon_parent, abspath(
             'site-packages', gluon=True), abspath('gluon', gluon=True), '')
         [add_path_first(path) for path in paths]
@@ -642,7 +637,7 @@ def run_controller_in(controller, function, environment):
             raise HTTP(404,
                        rewrite.THREAD_LOCAL.routes.error_message % badc,
                        web2py_error=badc)
-        code = read_file(filename)
+        code = getcfs(filename, filename, lambda: read_file(filename))
         exposed = find_exposed_functions(code)
         if not function in exposed:
             raise HTTP(404,
@@ -669,7 +664,7 @@ def run_view_in(environment):
     Executes the view for the requested action.
     The view is the one specified in `response.view` or determined by the url
     or `view/generic.extension`
-    It tries the pre-compiled views_controller_function.pyc before compiling it.
+    It tries the pre-compiled views.controller.function.pyc before compiling it.
     """
     request = current.request
     response = current.response
@@ -691,18 +686,18 @@ def run_view_in(environment):
     else:
         filename = pjoin(folder, 'views', view)
         if os.path.exists(path): # compiled views
-            x = view.replace('/', '_')
-            files = ['views_%s.pyc' % x]
+            x = view.replace('/', '.')
+            files = ['views.%s.pyc' % x]
             is_compiled = os.path.exists(pjoin(path, files[0]))
             # Don't use a generic view if the non-compiled view exists.
             if is_compiled or (not is_compiled and not os.path.exists(filename)):
                 if allow_generic:
-                    files.append('views_generic.%s.pyc' % request.extension)
+                    files.append('views.generic.%s.pyc' % request.extension)
                 # for backward compatibility
                 if request.extension == 'html':
-                    files.append('views_%s.pyc' % x[:-5])
+                    files.append('views.%s.pyc' % x[:-5])
                     if allow_generic:
-                        files.append('views_generic.pyc')
+                        files.append('views.generic.pyc')
                 # end backward compatibility code
                 for f in files:
                     compiled = pjoin(path, f)
diff --git a/gluon/template.py b/gluon/template.py
--- a/gluon/template.py
+++ b/gluon/template.py
@@ -24,6 +24,9 @@
     # have web2py
     from gluon.restricted import RestrictedError
     from gluon.globals import current
+    from gluon.cfs import getcfs
+    from gluon.fileutils import read_file
+    HAS_CFS = True
 except ImportError:
     # do not have web2py
     current = None
@@ -426,7 +429,7 @@ def _get_file_text(self, filename):
 
         # Allow Views to include other views dynamically
         context = self.context
-        if current and not "response" in context:
+        if current and "response" not in context:
             context["response"] = getattr(current, 'response', None)
 
         # Get the filename; filename looks like ``"template.html"``.
@@ -779,12 +782,15 @@ def parse_template(filename,
 
     # First, if we have a str try to open the file
     if isinstance(filename, str):
-        try:
-            fp = open(os.path.join(path, filename), 'rb')
-            text = fp.read()
-            fp.close()
-        except IOError:
-            raise RestrictedError(filename, '', 'Unable to find the file')
+        fname = os.path.join(path, filename)
+        if HAS_CFS:
+            text = getcfs(fname, fname, lambda: read_file(fname))
+        else:
+            try:
+                with open(fname, 'rb') as fp:
+                    text = fp.read()
+            except IOError:
+                raise RestrictedError(filename, '', 'Unable to find the file')
     else:
         text = filename.read()
     text = to_native(text)
@@ -890,7 +896,7 @@ def render(content="hello world",
         Response = DummyResponse
 
         # Add it to the context so we can use it.
-        if not 'NOESCAPE' in context:
+        if 'NOESCAPE' not in context:
             context['NOESCAPE'] = NOESCAPE
 
     if isinstance(content, unicodeT):
@@ -936,8 +942,3 @@ def render(content="hello world",
     if old_response_body is not None:
         context['response'].body = old_response_body
     return text
-
-
-if __name__ == '__main__':
-    import doctest
-    doctest.testmod()


Test patch: