Merge pull request #1470 from ilvalle/compileapp_getcfs

cache (and compile) views, models and controllers
This commit is contained in:
mdipierro
2016-09-27 16:36:32 -05:00
committed by GitHub
8 changed files with 44 additions and 75 deletions
@@ -4,10 +4,8 @@ import os
import re import re
import gzip import gzip
import tarfile import tarfile
from gluon._compat import StringIO
from xmlrpclib import ProtocolError
from gluon.contrib.simplejsonrpc import ServerProxy from gluon.contrib.simplejsonrpc import ServerProxy
from gluon._compat import StringIO, ProtocolError
def deploy(): def deploy():
response.title = T('Deploy to pythonanywhere') response.title = T('Deploy to pythonanywhere')
+1 -1
View File
@@ -409,7 +409,7 @@ def ccache():
import copy import copy
import time import time
import math import math
from gluon import portalocker from pydal.contrib import portalocker
ram = { ram = {
'entries': 0, 'entries': 0,
+2
View File
@@ -31,6 +31,7 @@ if PY2:
from types import ClassType from types import ClassType
import cgi import cgi
import cookielib import cookielib
from xmlrpclib import ProtocolError
BytesIO = StringIO BytesIO = StringIO
reduce = reduce reduce = reduce
hashlib_md5 = hashlib.md5 hashlib_md5 = hashlib.md5
@@ -94,6 +95,7 @@ else:
from urllib.request import FancyURLopener, urlopen from urllib.request import FancyURLopener, urlopen
from urllib.parse import quote as urllib_quote, unquote as urllib_unquote, urlencode from urllib.parse import quote as urllib_quote, unquote as urllib_unquote, urlencode
from http import cookiejar as cookielib from http import cookiejar as cookielib
from xmlrpc.client import ProtocolError
import html # warning, this is the python3 module and not the web2py html module import html # warning, this is the python3 module and not the web2py html module
hashlib_md5 = lambda s: hashlib.md5(bytes(s, 'utf8')) hashlib_md5 = lambda s: hashlib.md5(bytes(s, 'utf8'))
iterkeys = lambda d: iter(d.keys()) iterkeys = lambda d: iter(d.keys())
+18 -51
View File
@@ -430,13 +430,10 @@ def build_environment(request, response, session, store_current=True):
current.T = t current.T = t
current.cache = c current.cache = c
global __builtins__
if is_jython: # jython hack if is_jython: # jython hack
global __builtins__
__builtins__ = mybuiltin() __builtins__ = mybuiltin()
elif is_pypy: # apply the same hack to pypy too
__builtins__ = mybuiltin()
elif PY2:
__builtins__['__import__'] = builtin.__import__ # WHY?
environment['request'] = request environment['request'] = request
environment['response'] = response environment['response'] = response
environment['session'] = session environment['session'] = session
@@ -444,7 +441,6 @@ def build_environment(request, response, session, store_current=True):
lambda name, reload=False, app=request.application:\ lambda name, reload=False, app=request.application:\
local_import_aux(name, reload, app) local_import_aux(name, reload, app)
BaseAdapter.set_folder(pjoin(request.folder, 'databases')) BaseAdapter.set_folder(pjoin(request.folder, 'databases'))
response._view_environment = copy.copy(environment)
custom_import_install() custom_import_install()
return environment return environment
@@ -487,7 +483,7 @@ def compile_views(folder, skip_failed_views=False):
else: else:
raise Exception("%s in %s" % (e, fname)) raise Exception("%s in %s" % (e, fname))
else: else:
filename = ('views/%s.py' % fname).replace('/', '_').replace('\\', '_') filename = 'views.%s.py' % fname.replace(os.path.sep, '.')
filename = pjoin(folder, 'compiled', filename) filename = pjoin(folder, 'compiled', filename)
write_file(filename, data) write_file(filename, data)
save_pyc(filename) save_pyc(filename)
@@ -503,7 +499,7 @@ def compile_models(folder):
path = pjoin(folder, 'models') path = pjoin(folder, 'models')
for fname in listdir(path, '.+\.py$'): for fname in listdir(path, '.+\.py$'):
data = read_file(pjoin(path, fname)) data = read_file(pjoin(path, fname))
modelfile = 'models.'+fname.replace(os.path.sep,'.') modelfile = 'models.'+fname.replace(os.path.sep, '.')
filename = pjoin(folder, 'compiled', modelfile) filename = pjoin(folder, 'compiled', modelfile)
mktree(filename) mktree(filename)
write_file(filename, data) write_file(filename, data)
@@ -582,11 +578,10 @@ def run_models_in(environment):
continue continue
elif compiled: elif compiled:
code = getcfs(model, model, lambda: read_pyc(model)) code = getcfs(model, model, lambda: read_pyc(model))
elif is_gae: else:
code = getcfs(model, model, code = getcfs(model, model,
lambda: compile2(read_file(model), model)) lambda: compile2(read_file(model), model))
else:
code = getcfs(model, model, None)
restricted(code, environment, layer=model) restricted(code, environment, layer=model)
@@ -610,7 +605,6 @@ def run_controller_in(controller, function, environment):
rewrite.THREAD_LOCAL.routes.error_message % badf, rewrite.THREAD_LOCAL.routes.error_message % badf,
web2py_error=badf) web2py_error=badf)
code = getcfs(filename, filename, lambda: read_pyc(filename)) code = getcfs(filename, filename, lambda: read_pyc(filename))
restricted(code, environment, layer=filename)
elif function == '_TEST': elif function == '_TEST':
# TESTING: adjust the path to include site packages # TESTING: adjust the path to include site packages
from gluon.settings import global_settings from gluon.settings import global_settings
@@ -629,7 +623,6 @@ def run_controller_in(controller, function, environment):
environment['__symbols__'] = environment.keys() environment['__symbols__'] = environment.keys()
code = read_file(filename) code = read_file(filename)
code += TEST_CODE code += TEST_CODE
restricted(code, environment, layer=filename)
else: else:
filename = pjoin(folder, 'controllers/%s.py' filename = pjoin(folder, 'controllers/%s.py'
% controller) % controller)
@@ -644,10 +637,10 @@ def run_controller_in(controller, function, environment):
rewrite.THREAD_LOCAL.routes.error_message % badf, rewrite.THREAD_LOCAL.routes.error_message % badf,
web2py_error=badf) web2py_error=badf)
code = "%s\nresponse._vars=response._caller(%s)\n" % (code, function) code = "%s\nresponse._vars=response._caller(%s)\n" % (code, function)
if is_gae: layer = filename + ':' + function
layer = filename + ':' + function code = getcfs(layer, filename, lambda: compile2(code, layer))
code = getcfs(layer, filename, lambda: compile2(code, layer))
restricted(code, environment, filename) restricted(code, environment, layer=filename)
response = current.response response = current.response
vars = response._vars vars = response._vars
if response.postprocessing: if response.postprocessing:
@@ -682,7 +675,7 @@ def run_view_in(environment):
if not isinstance(view, str): if not isinstance(view, str):
ccode = parse_template(view, pjoin(folder, 'views'), ccode = parse_template(view, pjoin(folder, 'views'),
context=environment) context=environment)
restricted(ccode, environment, 'file stream') layer = 'file stream'
else: else:
filename = pjoin(folder, 'views', view) filename = pjoin(folder, 'views', view)
if os.path.exists(path): # compiled views if os.path.exists(path): # compiled views
@@ -713,16 +706,13 @@ def run_view_in(environment):
rewrite.THREAD_LOCAL.routes.error_message % badv, rewrite.THREAD_LOCAL.routes.error_message % badv,
web2py_error=badv) web2py_error=badv)
layer = filename layer = filename
if is_gae: # Cache the compiled template
ccode = getcfs(layer, filename, ccode = getcfs(layer, filename,
lambda: compile2(parse_template(view, lambda: compile2(parse_template(view,
pjoin(folder, 'views'), pjoin(folder, 'views'),
context=environment), layer)) context=environment),
else: layer))
ccode = parse_template(view, restricted(ccode, environment, layer=layer)
pjoin(folder, 'views'),
context=environment)
restricted(ccode, environment, layer)
def remove_compiled_application(folder): def remove_compiled_application(folder):
@@ -748,26 +738,3 @@ def compile_application(folder, skip_failed_views=False):
compile_controllers(folder) compile_controllers(folder)
failed_views = compile_views(folder, skip_failed_views) failed_views = compile_views(folder, skip_failed_views)
return failed_views return failed_views
def test():
"""
Example::
>>> import traceback, types
>>> environment={'x':1}
>>> open('a.py', 'w').write('print 1/x')
>>> save_pyc('a.py')
>>> os.unlink('a.py')
>>> if type(read_pyc('a.pyc'))==types.CodeType: print 'code'
code
>>> exec read_pyc('a.pyc') in environment
1
"""
return
if __name__ == '__main__':
import doctest
doctest.testmod()
+8 -3
View File
@@ -17,12 +17,17 @@ __copyright__ = "Copyright (C) 2011 Mariano Reingart"
__license__ = "LGPL 3.0" __license__ = "LGPL 3.0"
__version__ = "0.05" __version__ = "0.05"
import sys
PY2 = sys.version_info[0] == 2
import urllib import urllib
from xmlrpclib import Transport, SafeTransport if PY2:
from cStringIO import StringIO from xmlrpclib import Transport, SafeTransport
from cStringIO import StringIO
else:
from xmlrpc.client import Transport, SafeTransport
from io import StringIO
import random import random
import sys
import json import json
+2 -6
View File
@@ -202,7 +202,7 @@ def compile2(code, layer):
return compile(code, layer, 'exec') return compile(code, layer, 'exec')
def restricted(code, environment=None, layer='Unknown'): def restricted(ccode, environment=None, layer='Unknown'):
""" """
Runs code in environment and returns the output. If an exception occurs Runs code in environment and returns the output. If an exception occurs
in code it raises a RestrictedError containing the traceback. Layer is in code it raises a RestrictedError containing the traceback. Layer is
@@ -213,10 +213,6 @@ def restricted(code, environment=None, layer='Unknown'):
environment['__file__'] = layer environment['__file__'] = layer
environment['__name__'] = '__restricted__' environment['__name__'] = '__restricted__'
try: try:
if isinstance(code, types.CodeType):
ccode = code
else:
ccode = compile2(code, layer)
exec(ccode, environment) exec(ccode, environment)
except HTTP: except HTTP:
raise raise
@@ -231,7 +227,7 @@ def restricted(code, environment=None, layer='Unknown'):
sys.excepthook(etype, evalue, tb) sys.excepthook(etype, evalue, tb)
del tb del tb
output = "%s %s" % (etype, evalue) output = "%s %s" % (etype, evalue)
raise RestrictedError(layer, code, output, environment) raise RestrictedError(layer, ccode, output, environment)
def snapshot(info=None, context=5, code=None, environment=None): def snapshot(info=None, context=5, code=None, environment=None):
+5 -11
View File
@@ -24,9 +24,6 @@ try:
# have web2py # have web2py
from gluon.restricted import RestrictedError from gluon.restricted import RestrictedError
from gluon.globals import current from gluon.globals import current
from gluon.cfs import getcfs
from gluon.fileutils import read_file
HAS_CFS = True
except ImportError: except ImportError:
# do not have web2py # do not have web2py
current = None current = None
@@ -783,14 +780,11 @@ def parse_template(filename,
# First, if we have a str try to open the file # First, if we have a str try to open the file
if isinstance(filename, str): if isinstance(filename, str):
fname = os.path.join(path, filename) fname = os.path.join(path, filename)
if HAS_CFS: try:
text = getcfs(fname, fname, lambda: read_file(fname)) with open(fname, 'rb') as fp:
else: text = fp.read()
try: except IOError:
with open(fname, 'rb') as fp: raise RestrictedError(filename, '', 'Unable to find the file')
text = fp.read()
except IOError:
raise RestrictedError(filename, '', 'Unable to find the file')
else: else:
text = filename.read() text = filename.read()
text = to_native(text) text = to_native(text)
+7
View File
@@ -16,6 +16,7 @@ from gluon.storage import Storage, List
from gluon import fileutils from gluon import fileutils
from gluon.dal import DAL, Field, Table from gluon.dal import DAL, Field, Table
from gluon.http import HTTP from gluon.http import HTTP
from gluon.fileutils import open_file
DEFAULT_URI = os.getenv('DB', 'sqlite:memory') DEFAULT_URI = os.getenv('DB', 'sqlite:memory')
@@ -76,12 +77,18 @@ class TestAppAdmin(unittest.TestCase):
def run_view(self): def run_view(self):
return run_view_in(self.env) return run_view_in(self.env)
def run_view_file_stream(self):
view_path = os.path.join(self.env['request'].folder, 'views', 'appadmin.html')
self.env['response'].view = open_file(view_path, 'r')
return run_view_in(self.env)
def _test_index(self): def _test_index(self):
result = self.run_function() result = self.run_function()
self.assertTrue('db' in result['databases']) self.assertTrue('db' in result['databases'])
self.env.update(result) self.env.update(result)
try: try:
self.run_view() self.run_view()
self.run_view_file_stream()
except Exception as e: except Exception as e:
print(e.message) print(e.message)
self.fail('Could not make the view') self.fail('Could not make the view')