better regex and improvements in compileapp, thank you Paolo Pastori

This commit is contained in:
mdipierro
2019-05-09 23:30:07 -07:00
parent f9c0c478df
commit caf3010408
4 changed files with 186 additions and 184 deletions
+183 -181
View File
@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
@@ -14,93 +13,43 @@ Note:
""" """
import re import re
import fnmatch
import os, sys
import copy
import random import random
from gluon._compat import builtin, PY2, unicodeT, to_native, to_bytes, iteritems, integer_types, basestring, reduce, xrange, long, reload
from gluon.storage import Storage, List
from gluon.template import parse_template
from gluon.restricted import restricted, compile2
from gluon.fileutils import mktree, listdir, read_file, write_file
from gluon.myregex import regex_expose, regex_longcomments
from gluon.languages import TranslatorFactory
from gluon.dal import DAL, Field
from gluon.validators import Validator
from pydal.base import BaseAdapter
from gluon.sqlhtml import SQLFORM, SQLTABLE
from gluon.cache import Cache
from gluon.globals import current, Response
from gluon import settings
from gluon.cfs import getcfs
from gluon import html
from gluon import validators
from gluon.http import HTTP, redirect
import marshal
import shutil
import imp
import logging
import types import types
import copy
from functools import reduce from functools import reduce
from gluon import rewrite
from gluon.custom_import import custom_import_install
import py_compile import py_compile
import os
from os.path import join as pjoin, exists
import sys
import imp
import marshal
import fnmatch
import shutil
logger = logging.getLogger("web2py") from gluon._compat import (builtin, PY2, unicodeT, to_native, to_bytes,
iteritems, integer_types, basestring, xrange, reload)
from gluon.storage import Storage, List
from gluon.globals import current, Response
from gluon import html, validators, rewrite
from gluon.http import HTTP, redirect
from gluon.dal import DAL, Field
from gluon.sqlhtml import SQLFORM, SQLTABLE
from gluon.languages import TranslatorFactory
from gluon.cache import Cache
from gluon.validators import Validator
from gluon.settings import global_settings
from pydal.base import BaseAdapter
from gluon.custom_import import custom_import_install
from gluon.fileutils import mktree, listdir, read_file, write_file, abspath
from gluon.template import parse_template
from gluon.cfs import getcfs
from gluon.restricted import restricted, compile2
from gluon.admin import add_path_first
is_pypy = settings.global_settings.is_pypy
is_gae = settings.global_settings.web2py_runtime_gae
is_jython = settings.global_settings.is_jython
pjoin = os.path.join
if PY2:
marshal_header_size = 8
else:
marshal_header_size = 16 if sys.version_info[1] >= 7 else 12
TEST_CODE = \
r"""
def _TEST():
import doctest, sys, cStringIO, types, cgi, gluon.fileutils
if not gluon.fileutils.check_credentials(request):
raise HTTP(401, web2py_error='invalid credentials')
stdout = sys.stdout
html = '<h2>Testing controller "%s.py" ... done.</h2><br/>\n' \
% request.controller
for key in sorted([key for key in globals() if not key in __symbols__+['_TEST']]):
eval_key = eval(key)
if type(eval_key) == types.FunctionType:
number_doctests = sum([len(ds.examples) for ds in doctest.DocTestFinder().find(eval_key)])
if number_doctests>0:
sys.stdout = cStringIO.StringIO()
name = '%s/controllers/%s.py in %s.__doc__' \
% (request.folder, request.controller, key)
doctest.run_docstring_examples(eval_key,
globals(), False, name=name)
report = sys.stdout.getvalue().strip()
if report:
pf = 'failed'
else:
pf = 'passed'
html += '<h3 class="%s">Function %s [%s]</h3>\n' \
% (pf, key, pf)
if report:
html += CODE(report, language='web2py', \
link='/examples/global/vars/').xml()
html += '<br/>\n'
else:
html += \
'<h3 class="nodoctests">Function %s [no doctests]</h3><br/>\n' \
% (key)
response._vars = html
sys.stdout = stdout
_TEST()
"""
CACHED_REGEXES = {} CACHED_REGEXES = {}
CACHED_REGEXES_MAX_SIZE = 1000 CACHED_REGEXES_MAX_SIZE = 1000
def re_compile(regex): def re_compile(regex):
try: try:
return CACHED_REGEXES[regex] return CACHED_REGEXES[regex]
@@ -111,22 +60,6 @@ def re_compile(regex):
return compiled_regex return compiled_regex
class mybuiltin(object):
"""
NOTE could simple use a dict and populate it,
NOTE not sure if this changes things though if monkey patching import.....
"""
# __builtins__
def __getitem__(self, key):
try:
return getattr(builtin, key)
except AttributeError:
raise KeyError(key)
def __setitem__(self, key, value):
setattr(self, key, value)
def LOAD(c=None, f='index', args=None, vars=None, def LOAD(c=None, f='index', args=None, vars=None,
extension=None, target=None, ajax=False, ajax_trap=False, extension=None, target=None, ajax=False, ajax_trap=False,
url=None, user_signature=False, timeout=None, times=1, url=None, user_signature=False, timeout=None, times=1,
@@ -140,10 +73,10 @@ def LOAD(c=None, f='index', args=None, vars=None,
vars(dict): vars vars(dict): vars
extension(str): extension extension(str): extension
target(str): id of the target target(str): id of the target
ajax(bool): True to enable AJAX bahaviour ajax(bool): True to enable AJAX behaviour
ajax_trap(bool): True if `ajax` is set to `True`, traps ajax_trap(bool): True if `ajax` is set to `True`, traps
both links and forms "inside" the target both links and forms "inside" the target
url(str): overrides `c`,`f`,`args` and `vars` url(str): overrides `c`, `f`, `args` and `vars`
user_signature(bool): adds hmac signature to all links user_signature(bool): adds hmac signature to all links
with a key that is different for every user with a key that is different for every user
timeout(int): in milliseconds, specifies the time to wait before timeout(int): in milliseconds, specifies the time to wait before
@@ -153,7 +86,6 @@ def LOAD(c=None, f='index', args=None, vars=None,
"infinity" or "continuous" are accepted to reload indefinitely the "infinity" or "continuous" are accepted to reload indefinitely the
component component
""" """
from gluon.html import TAG, DIV, URL, SCRIPT, XML
if args is None: if args is None:
args = [] args = []
vars = Storage(vars or {}) vars = Storage(vars or {})
@@ -163,19 +95,21 @@ def LOAD(c=None, f='index', args=None, vars=None,
if '.' in f: if '.' in f:
f, extension = f.rsplit('.', 1) f, extension = f.rsplit('.', 1)
if url or ajax: if url or ajax:
url = url or URL(request.application, c, f, r=request, url = url or html.URL(request.application, c, f, r=request,
args=args, vars=vars, extension=extension, args=args, vars=vars, extension=extension,
user_signature=user_signature) user_signature=user_signature)
# timing options # timing options
if isinstance(times, basestring): if isinstance(times, basestring):
if times.upper() in ("INFINITY", "CONTINUOUS"): if times.upper() in ("INFINITY", "CONTINUOUS"):
times = "Infinity" times = "Infinity"
else: else:
# FIXME: should be a ValueError
raise TypeError("Unsupported times argument %s" % times) raise TypeError("Unsupported times argument %s" % times)
elif isinstance(times, int): elif isinstance(times, int):
if times <= 0: if times <= 0:
raise ValueError("Times argument must be greater than zero, 'Infinity' or None") raise ValueError("Times argument must be greater than zero, 'Infinity' or None")
else: else:
# NOTE: why do not use ValueError only?
raise TypeError("Unsupported times argument type %s" % type(times)) raise TypeError("Unsupported times argument type %s" % type(times))
if timeout is not None: if timeout is not None:
if not isinstance(timeout, integer_types): if not isinstance(timeout, integer_types):
@@ -191,7 +125,7 @@ def LOAD(c=None, f='index', args=None, vars=None,
statement = "$.web2py.component('%s','%s');" % (url, target) statement = "$.web2py.component('%s','%s');" % (url, target)
attr['_data-w2p_remote'] = url attr['_data-w2p_remote'] = url
if target is not None: if target is not None:
return DIV(content, **attr) return html.DIV(content, **attr)
else: else:
if not isinstance(args, (list, tuple)): if not isinstance(args, (list, tuple)):
@@ -211,7 +145,7 @@ def LOAD(c=None, f='index', args=None, vars=None,
'/'.join([request.application, c, f] + '/'.join([request.application, c, f] +
[str(a) for a in other_request.args]) [str(a) for a in other_request.args])
other_request.env.query_string = \ other_request.env.query_string = \
vars and URL(vars=vars).split('?')[1] or '' vars and html.URL(vars=vars).split('?')[1] or ''
other_request.env.http_web2py_component_location = \ other_request.env.http_web2py_component_location = \
request.env.path_info request.env.path_info
other_request.cid = target other_request.cid = target
@@ -220,7 +154,7 @@ def LOAD(c=None, f='index', args=None, vars=None,
# A bit nasty but needed to use LOAD on action decorates with @request.restful() # A bit nasty but needed to use LOAD on action decorates with @request.restful()
other_response.view = '%s/%s.%s' % (c, f, other_request.extension) other_response.view = '%s/%s.%s' % (c, f, other_request.extension)
other_environment = copy.copy(current.globalenv) # NASTY other_environment = copy.copy(current.globalenv) # FIXME: NASTY
other_response._view_environment = other_environment other_response._view_environment = other_environment
other_response.generic_patterns = \ other_response.generic_patterns = \
@@ -241,12 +175,12 @@ def LOAD(c=None, f='index', args=None, vars=None,
current.request, current.response = original_request, original_response current.request, current.response = original_request, original_response
js = None js = None
if ajax_trap: if ajax_trap:
link = URL(request.application, c, f, r=request, link = html.URL(request.application, c, f, r=request,
args=args, vars=vars, extension=extension, args=args, vars=vars, extension=extension,
user_signature=user_signature) user_signature=user_signature)
js = "$.web2py.trap_form('%s','%s');" % (link, target) js = "$.web2py.trap_form('%s','%s');" % (link, target)
script = js and SCRIPT(js, _type="text/javascript") or '' script = js and html.SCRIPT(js, _type="text/javascript") or ''
return TAG[''](DIV(XML(page), **attr), script) return html.TAG[''](html.DIV(html.XML(page), **attr), script)
class LoadFactory(object): class LoadFactory(object):
@@ -262,7 +196,6 @@ class LoadFactory(object):
if args is None: if args is None:
args = [] args = []
vars = Storage(vars or {}) vars = Storage(vars or {})
from . import globals
target = target or 'c' + str(random.random())[2:] target = target or 'c' + str(random.random())[2:]
attr['_id'] = target attr['_id'] = target
request = current.request request = current.request
@@ -289,7 +222,7 @@ class LoadFactory(object):
other_request.vars = vars other_request.vars = vars
other_request.get_vars = vars other_request.get_vars = vars
other_request.post_vars = Storage() other_request.post_vars = Storage()
other_response = globals.Response() other_response = Response()
other_request.env.path_info = '/' + \ other_request.env.path_info = '/' + \
'/'.join([request.application, c, f] + '/'.join([request.application, c, f] +
[str(a) for a in other_request.args]) [str(a) for a in other_request.args])
@@ -354,37 +287,36 @@ def local_import_aux(name, reload_force=False, app='welcome'):
if reload_force: if reload_force:
reload(module) reload(module)
return module return module
#
# OLD IMPLEMENTATION:
#
# items = name.replace('/','.').split('.')
# filename, modulepath = items[-1], pjoin(apath,'modules',*items[:-1])
# imp.acquire_lock()
# try:
# file=None
# (file,path,desc) = imp.find_module(filename,[modulepath]+sys.path)
# if not path in sys.modules or reload:
# if is_gae:
# module={}
# execfile(path,{},module)
# module=Storage(module)
# else:
# module = imp.load_module(path,file,path,desc)
# sys.modules[path] = module
# else:
# module = sys.modules[path]
# except Exception, e:
# module = None
# if file:
# file.close()
# imp.release_lock()
# if not module:
# raise ImportError, "cannot find module %s in %s" % (
# filename, modulepath)
# return module
"""
OLD IMPLEMENTATION:
items = name.replace('/','.').split('.')
filename, modulepath = items[-1], pjoin(apath,'modules',*items[:-1])
imp.acquire_lock()
try:
file=None
(file,path,desc) = imp.find_module(filename,[modulepath]+sys.path)
if not path in sys.modules or reload:
if is_gae:
module={}
execfile(path,{},module)
module=Storage(module)
else:
module = imp.load_module(path,file,path,desc)
sys.modules[path] = module
else:
module = sys.modules[path]
except Exception, e:
module = None
if file:
file.close()
imp.release_lock()
if not module:
raise ImportError, "cannot find module %s in %s" % (
filename, modulepath)
return module
"""
_base_environment_ = dict((k, getattr(html, k)) for k in html.__all__) _base_environment_ = dict((k, getattr(html, k)) for k in html.__all__)
_base_environment_.update( _base_environment_.update(
(k, getattr(validators, k)) for k in validators.__all__) (k, getattr(validators, k)) for k in validators.__all__)
@@ -424,7 +356,7 @@ def build_environment(request, response, session, store_current=True):
r'^%s/%s/\w+\.py$' % (request.controller, request.function) r'^%s/%s/\w+\.py$' % (request.controller, request.function)
] ]
T = environment['T'] = TranslatorFactory(os.path.join(request.folder, 'languages'), T = environment['T'] = TranslatorFactory(pjoin(request.folder, 'languages'),
request.env.http_accept_language) request.env.http_accept_language)
c = environment['cache'] = Cache(request) c = environment['cache'] = Cache(request)
@@ -439,7 +371,23 @@ def build_environment(request, response, session, store_current=True):
current.T = T current.T = T
current.cache = c current.cache = c
if is_jython: # jython hack if global_settings.is_jython:
# jython hack
class mybuiltin(object):
"""
NOTE could simple use a dict and populate it,
NOTE not sure if this changes things though if monkey patching import.....
"""
# __builtins__
def __getitem__(self, key):
try:
return getattr(builtin, key)
except AttributeError:
raise KeyError(key)
def __setitem__(self, key, value):
setattr(self, key, value)
global __builtins__ global __builtins__
__builtins__ = mybuiltin() __builtins__ = mybuiltin()
@@ -462,6 +410,11 @@ def save_pyc(filename):
py_compile.compile(filename, cfile=cfile) py_compile.compile(filename, cfile=cfile)
if PY2:
MARSHAL_HEADER_SIZE = 8
else:
MARSHAL_HEADER_SIZE = 16 if sys.version_info[1] >= 7 else 12
def read_pyc(filename): def read_pyc(filename):
""" """
Read the code inside a bytecode compiled file if the MAGIC number is Read the code inside a bytecode compiled file if the MAGIC number is
@@ -471,44 +424,49 @@ def read_pyc(filename):
a code object a code object
""" """
data = read_file(filename, 'rb') data = read_file(filename, 'rb')
if not is_gae and data[:4] != imp.get_magic(): if not global_settings.web2py_runtime_gae and \
not data.startswith(imp.get_magic()):
raise SystemError('compiled code is incompatible') raise SystemError('compiled code is incompatible')
return marshal.loads(data[marshal_header_size:]) return marshal.loads(data[MARSHAL_HEADER_SIZE:])
REGEX_PATH_CLASS = r"[\w%s-]" % os.sep if os.sep != '\\' else r'[\w\\-]'
REGEX_VIEW_PATH = r"%s+(?:\.\w+)*$" % REGEX_PATH_CLASS
def compile_views(folder, skip_failed_views=False): def compile_views(folder, skip_failed_views=False):
""" """
Compiles all the views in the application specified by `folder` Compiles all the views in the application specified by `folder`
""" """
path = pjoin(folder, 'views') path = pjoin(folder, 'views')
failed_views = [] failed_views = []
for fname in listdir(path, '^[\w/\-]+(\.\w+)*$'): for fname in listdir(path, REGEX_VIEW_PATH):
try: try:
data = parse_template(fname, path) data = parse_template(fname, path)
except Exception as e: except Exception as e:
if skip_failed_views: if skip_failed_views:
failed_views.append(fname) failed_views.append(fname)
else: else:
# FIXME: should raise something more specific than Exception
raise Exception("%s in %s" % (e, fname)) raise Exception("%s in %s" % (e, fname))
else: else:
filename = 'views.%s.py' % fname.replace(os.path.sep, '.') filename = 'views.%s.py' % fname.replace(os.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)
os.unlink(filename) os.unlink(filename)
return failed_views if failed_views else None return failed_views or None
REGEX_MODEL_PATH = r"%s+\.py$" % REGEX_PATH_CLASS
def compile_models(folder): def compile_models(folder):
""" """
Compiles all the models in the application specified by `folder` Compiles all the models in the application specified by `folder`
""" """
path = pjoin(folder, 'models') path = pjoin(folder, 'models')
for fname in listdir(path, '.+\.py$'): for fname in listdir(path, REGEX_MODEL_PATH):
data = read_file(pjoin(path, fname)) data = read_file(pjoin(path, fname))
modelfile = 'models.'+fname.replace(os.path.sep, '.') modelfile = 'models.'+fname.replace(os.sep, '.')
filename = pjoin(folder, 'compiled', modelfile) filename = pjoin(folder, 'compiled', modelfile)
mktree(filename) mktree(filename)
write_file(filename, data) write_file(filename, data)
@@ -516,19 +474,22 @@ def compile_models(folder):
os.unlink(filename) os.unlink(filename)
def find_exposed_functions(data): REGEX_LONG_STRING = re.compile('(""".*?"""|' "'''.*?''')", re.DOTALL)
data = regex_longcomments.sub('', data) REGEX_EXPOSED = re.compile(r'^def\s+(_?[a-zA-Z0-9]\w*)\( *\)\s*:', re.MULTILINE)
return regex_expose.findall(data)
def find_exposed_functions(data):
data = REGEX_LONG_STRING.sub('', data)
return REGEX_EXPOSED.findall(data)
REGEX_CONTROLLER = r'[\w-]+\.py$'
def compile_controllers(folder): def compile_controllers(folder):
""" """
Compiles all the controllers in the application specified by `folder` Compiles all the controllers in the application specified by `folder`
""" """
path = pjoin(folder, 'controllers') path = pjoin(folder, 'controllers')
for fname in listdir(path, '.+\.py$'): for fname in listdir(path, REGEX_CONTROLLER):
### why is this here? save_pyc(pjoin(path, file))
data = read_file(pjoin(path, fname)) data = read_file(pjoin(path, fname))
exposed = find_exposed_functions(data) exposed = find_exposed_functions(data)
for function in exposed: for function in exposed:
@@ -541,20 +502,22 @@ def compile_controllers(folder):
os.unlink(filename) os.unlink(filename)
def model_cmp(a, b, sep='.'): if PY2:
return cmp(a.count(sep), b.count(sep)) or cmp(a, b) def model_cmp(a, b, sep='.'):
return cmp(a.count(sep), b.count(sep)) or cmp(a, b)
def model_cmp_sep(a, b, sep=os.sep):
return model_cmp(a, b, sep)
def model_cmp_sep(a, b, sep=os.path.sep): REGEX_COMPILED_MODEL = r'models[_.][\w.-]+\.pyc$'
return model_cmp(a, b, sep) REGEX_MODEL = r'[\w-]+\.py$'
def run_models_in(environment): def run_models_in(environment):
""" """
Runs all models (in the app specified by the current folder) Runs all models (in the app specified by the current folder)
It tries pre-compiled models first before compiling them. It tries pre-compiled models first before compiling them.
""" """
request = current.request request = current.request
folder = request.folder folder = request.folder
c = request.controller c = request.controller
@@ -563,19 +526,21 @@ def run_models_in(environment):
path = pjoin(folder, 'models') path = pjoin(folder, 'models')
cpath = pjoin(folder, 'compiled') cpath = pjoin(folder, 'compiled')
compiled = os.path.exists(cpath) compiled = exists(cpath)
if PY2: if PY2:
if compiled: if compiled:
models = sorted(listdir(cpath, '^models[_.][\w.]+\.pyc$', 0), model_cmp) models = sorted(listdir(cpath, REGEX_COMPILED_MODEL, 0),
model_cmp)
else: else:
models = sorted(listdir(path, '^\w+\.py$', 0, sort=False), model_cmp_sep) models = sorted(listdir(path, REGEX_MODEL, 0, sort=False),
model_cmp_sep)
else: else:
if compiled: if compiled:
models = sorted(listdir(cpath, '^models[_.][\w.]+\.pyc$', 0), models = sorted(listdir(cpath, REGEX_COMPILED_MODEL, 0),
key=lambda f: '{0:03d}'.format(f.count('.')) + f) key=lambda f: '{0:03d}'.format(f.count('.')) + f)
else: else:
models = sorted(listdir(path, '^\w+\.py$', 0, sort=False), models = sorted(listdir(path, REGEX_MODEL, 0, sort=False),
key=lambda f: '{0:03d}'.format(f.count(os.path.sep)) + f) key=lambda f: '{0:03d}'.format(f.count(os.sep)) + f)
models_to_run = None models_to_run = None
for model in models: for model in models:
@@ -589,7 +554,7 @@ def run_models_in(environment):
fname = model[n:-4].replace('.', '/')+'.py' fname = model[n:-4].replace('.', '/')+'.py'
else: else:
n = len(path)+1 n = len(path)+1
fname = model[n:].replace(os.path.sep, '/') fname = model[n:].replace(os.sep, '/')
if not regex.search(fname) and c != 'appadmin': if not regex.search(fname) and c != 'appadmin':
continue continue
elif compiled: elif compiled:
@@ -600,19 +565,56 @@ def run_models_in(environment):
restricted(ccode, environment, layer=model) restricted(ccode, environment, layer=model)
TEST_CODE = r"""
def _TEST():
import doctest, sys, cStringIO, types, cgi, gluon.fileutils
if not gluon.fileutils.check_credentials(request):
raise HTTP(401, web2py_error='invalid credentials')
stdout = sys.stdout
html = '<h2>Testing controller "%s.py" ... done.</h2><br/>\n' \
% request.controller
for key in sorted([key for key in globals() if not key in __symbols__+['_TEST']]):
eval_key = eval(key)
if type(eval_key) == types.FunctionType:
number_doctests = sum([len(ds.examples) for ds in doctest.DocTestFinder().find(eval_key)])
if number_doctests>0:
sys.stdout = cStringIO.StringIO()
name = '%s/controllers/%s.py in %s.__doc__' \
% (request.folder, request.controller, key)
doctest.run_docstring_examples(eval_key,
globals(), False, name=name)
report = sys.stdout.getvalue().strip()
if report:
pf = 'failed'
else:
pf = 'passed'
html += '<h3 class="%s">Function %s [%s]</h3>\n' \
% (pf, key, pf)
if report:
html += CODE(report, language='web2py', \
link='/examples/global/vars/').xml()
html += '<br/>\n'
else:
html += \
'<h3 class="nodoctests">Function %s [no doctests]</h3><br/>\n' \
% (key)
response._vars = html
sys.stdout = stdout
_TEST()
"""
def run_controller_in(controller, function, environment): def run_controller_in(controller, function, environment):
""" """
Runs the controller.function() (for the app specified by Runs the controller.function() (for the app specified by
the current folder). 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! # if compiled should run compiled!
folder = current.request.folder folder = current.request.folder
cpath = pjoin(folder, 'compiled') cpath = pjoin(folder, 'compiled')
badc = 'invalid controller (%s/%s)' % (controller, function) badc = 'invalid controller (%s/%s)' % (controller, function)
badf = 'invalid function (%s/%s)' % (controller, function) badf = 'invalid function (%s/%s)' % (controller, function)
if os.path.exists(cpath): if exists(cpath):
filename = pjoin(cpath, 'controllers.%s.%s.pyc' % (controller, function)) filename = pjoin(cpath, 'controllers.%s.%s.pyc' % (controller, function))
try: try:
ccode = getcfs(filename, filename, lambda: read_pyc(filename)) ccode = getcfs(filename, filename, lambda: read_pyc(filename))
@@ -622,8 +624,6 @@ def run_controller_in(controller, function, environment):
web2py_error=badf) web2py_error=badf)
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.admin import abspath, add_path_first
paths = (global_settings.gluon_parent, abspath( paths = (global_settings.gluon_parent, abspath(
'site-packages', gluon=True), abspath('gluon', gluon=True), '') 'site-packages', gluon=True), abspath('gluon', gluon=True), '')
[add_path_first(path) for path in paths] [add_path_first(path) for path in paths]
@@ -631,7 +631,7 @@ def run_controller_in(controller, function, environment):
filename = pjoin(folder, 'controllers/%s.py' filename = pjoin(folder, 'controllers/%s.py'
% controller) % controller)
if not os.path.exists(filename): if not exists(filename):
raise HTTP(404, raise HTTP(404,
rewrite.THREAD_LOCAL.routes.error_message % badc, rewrite.THREAD_LOCAL.routes.error_message % badc,
web2py_error=badc) web2py_error=badc)
@@ -696,12 +696,12 @@ def run_view_in(environment):
layer = 'file stream' layer = 'file stream'
else: else:
filename = pjoin(folder, 'views', view) filename = pjoin(folder, 'views', view)
if os.path.exists(cpath): # compiled views if exists(cpath): # compiled views
x = view.replace('/', '.') x = view.replace('/', '.')
files = ['views.%s.pyc' % x] files = ['views.%s.pyc' % x]
is_compiled = os.path.exists(pjoin(cpath, files[0])) is_compiled = exists(pjoin(cpath, files[0]))
# Don't use a generic view if the non-compiled view exists. # 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 is_compiled or (not is_compiled and not exists(filename)):
if allow_generic: if allow_generic:
files.append('views.generic.%s.pyc' % request.extension) files.append('views.generic.%s.pyc' % request.extension)
# for backward compatibility # for backward compatibility
@@ -712,16 +712,16 @@ def run_view_in(environment):
# end backward compatibility code # end backward compatibility code
for f in files: for f in files:
compiled = pjoin(cpath, f) compiled = pjoin(cpath, f)
if os.path.exists(compiled): if exists(compiled):
ccode = getcfs(compiled, compiled, lambda: read_pyc(compiled)) ccode = getcfs(compiled, compiled, lambda: read_pyc(compiled))
layer = compiled layer = compiled
break break
# if the view is not compiled # if the view is not compiled
if not layer: if not layer:
if not os.path.exists(filename) and allow_generic: if not exists(filename) and allow_generic:
view = 'generic.' + request.extension view = 'generic.' + request.extension
filename = pjoin(folder, 'views', view) filename = pjoin(folder, 'views', view)
if not os.path.exists(filename): if not exists(filename):
raise HTTP(404, raise HTTP(404,
rewrite.THREAD_LOCAL.routes.error_message % badv, rewrite.THREAD_LOCAL.routes.error_message % badv,
web2py_error=badv) web2py_error=badv)
@@ -737,6 +737,8 @@ def run_view_in(environment):
return environment['response'].body.getvalue() return environment['response'].body.getvalue()
REGEX_COMPILED_CONTROLLER = r'[\w-]+\.pyc$'
def remove_compiled_application(folder): def remove_compiled_application(folder):
""" """
Deletes the folder `compiled` containing the compiled application. Deletes the folder `compiled` containing the compiled application.
@@ -744,7 +746,7 @@ def remove_compiled_application(folder):
try: try:
shutil.rmtree(pjoin(folder, 'compiled')) shutil.rmtree(pjoin(folder, 'compiled'))
path = pjoin(folder, 'controllers') path = pjoin(folder, 'controllers')
for file in listdir(path, '.*\.pyc$', drop=False): for file in listdir(path, REGEX_COMPILED_CONTROLLER, drop=False):
os.unlink(file) os.unlink(file)
except OSError: except OSError:
pass pass
+1 -1
View File
@@ -531,7 +531,7 @@ def load_config(config_file, opt_map):
""" """
REGEX_ASSIGN_EXP = re.compile(r'\s*=\s*(.+)') REGEX_ASSIGN_EXP = re.compile(r'\s*=\s*(.+)')
map_items = opt_map.items() map_items = opt_map.items()
# preserve the order of loaded options even if this is not needed # preserve the order of loaded options even though this is not needed
pl = OrderedDict() pl = OrderedDict()
config_encoding = get_pep263_encoding(config_file) config_encoding = get_pep263_encoding(config_file)
# NOTE: assume 'ascii' encoding when not explicitly stated (Python 2), # NOTE: assume 'ascii' encoding when not explicitly stated (Python 2),