better regex and improvements in compileapp, thank you Paolo Pastori
This commit is contained in:
+183
-181
@@ -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
@@ -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),
|
||||||
|
|||||||
+1
-1
Submodule gluon/packages/dal updated: 2dca2fd72b...cd1b2ed6d9
+1
-1
Submodule gluon/packages/yatl updated: 97ce196d2c...dd96936526
Reference in New Issue
Block a user