e||Math.abs(c.pageY-n)>e,o&&!d&&H("vmousecancel",b,f),H("vmousemove",b,f),F()}function M(a){if(r)return;C();var b=z(a.target),c;H("vmouseup",a,b);if(!o){var d=H("vclick",a,b);d&&d.isDefaultPrevented()&&(c=x(a).changedTouches[0],p.push({touchID:v,x:c.clientX,y:c.clientY}),q=!0)}H("vmouseout",a,b),o=!1,F()}function N(b){var c=a.data(b,e),d;if(c)for(d in c)if(c[d])return!0;return!1}function O(){}function P(b){var c=b.substr(1);return{setup:function(d,f){N(this)||a.data(this,e,{});var g=a.data(this,e);g[b]=!0,k[b]=(k[b]||0)+1,k[b]===1&&t.bind(c,I),a(this).bind(c,O),s&&(k.touchstart=(k.touchstart||0)+1,k.touchstart===1&&t.bind("touchstart",J).bind("touchend",M).bind("touchmove",L).bind("scroll",K))},teardown:function(d,f){--k[b],k[b]||t.unbind(c,I),s&&(--k.touchstart,k.touchstart||t.unbind("touchstart",J).unbind("touchmove",L).unbind("touchend",M).unbind("scroll",K));var g=a(this),h=a.data(this,e);h&&(h[b]=!1),g.unbind(c,O),N(this)||g.removeData(e)}}}var e="virtualMouseBindings",f="virtualTouchID",g="vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split(" "),h="clientX clientY pageX pageY screenX screenY".split(" "),i=a.event.mouseHooks?a.event.mouseHooks.props:[],j=a.event.props.concat(i),k={},l=0,m=0,n=0,o=!1,p=[],q=!1,r=!1,s="addEventListener"in c,t=a(c),u=1,v=0,w;a.vmouse={moveDistanceThreshold:10,clickDistanceThreshold:10,resetTimerDuration:1500};for(var Q=0;Q",{"class":"ui-selectmenu-list",id:l,role:"listbox","aria-labelledby":k}).attr("data-"+a.mobile.ns+"theme",d.options.theme).appendTo(n),p=a("
",{"class":"ui-title"}).appendTo(p),r,s,t;d.isMultiple&&(t=a("",{text:d.options.closeText,href:"#","class":"ui-btn-left"}).attr("data-"+a.mobile.ns+"iconpos","notext").attr("data-"+a.mobile.ns+"icon","delete").appendTo(p).buttonMarkup()),a.extend(d,{select:d.select,selectID:f,buttonId:k,menuId:l,thisPage:h,menuPage:m,label:g,selectOptions:i,isMultiple:j,theme:d.options.theme,listbox:n,list:o,header:p,headerTitle:q,headerClose:t,menuPageContent:r,menuPageClose:s,placeholder:"",build:function(){var b=this;b.refresh(),b.select.attr("tabindex","-1").focus(function(){a(this).blur(),b.button.focus()}),b.button.bind("vclick keydown",function(c){if(c.type==="vclick"||c.keyCode&&(c.keyCode===a.mobile.keyCode.ENTER||c.keyCode===a.mobile.keyCode.SPACE))b.open(),c.preventDefault()}),b.list.attr("role","listbox").bind("focusin",function(b){a(b.target).attr("tabindex","0").trigger("vmouseover")}).bind("focusout",function(b){a(b.target).attr("tabindex","-1").trigger("vmouseout")}).delegate("li:not(.ui-disabled, .ui-li-divider)","click",function(c){var e=b.select[0].selectedIndex,f=b.list.find("li:not(.ui-li-divider)").index(this),g=b._selectOptions().eq(f)[0];g.selected=b.isMultiple?!g.selected:!0,b.isMultiple&&a(this).find(".ui-icon").toggleClass("ui-icon-checkbox-on",g.selected).toggleClass("ui-icon-checkbox-off",!g.selected),(b.isMultiple||e!==f)&&b.select.trigger("change"),b.isMultiple?b.list.find("li:not(.ui-li-divider)").eq(f).addClass("ui-btn-down-"+d.options.theme).find("a").first().focus():b.close(),c.preventDefault()}).keydown(function(b){var c=a(b.target),e=c.closest("li"),f,g;switch(b.keyCode){case 38:return f=e.prev().not(".ui-selectmenu-placeholder"),f.is(".ui-li-divider")&&(f=f.prev()),f.length&&(c.blur().attr("tabindex","-1"),f.addClass("ui-btn-down-"+d.options.theme).find("a").first().focus()),!1;case 40:return g=e.next(),g.is(".ui-li-divider")&&(g=g.next()),g.length&&(c.blur().attr("tabindex","-1"),g.addClass("ui-btn-down-"+d.options.theme).find("a").first().focus()),!1;case 13:case 32:return c.trigger("click"),!1}}),b.menuPage.bind("pagehide",function(){b.list.appendTo(b.listbox),b._focusButton(),a.mobile._bindPageRemove.call(b.thisPage)}),b.listbox.bind("popupafterclose",function(a){b.close()}),b.isMultiple&&b.headerClose.click(function(){if(b.menuType==="overlay")return b.close(),!1}),b.thisPage.addDependents(this.menuPage)},_isRebuildRequired:function(){var a=this.list.find("li"),b=this._selectOptions();return b.text()!==a.text()},selected:function(){return this._selectOptions().filter(":selected:not( :jqmData(placeholder='true') )")},refresh:function(b,c){var d=this,e=this.element,f=this.isMultiple,g;(b||this._isRebuildRequired())&&d._buildList(),g=this.selectedIndices(),d.setButtonText(),d.setButtonCount(),d.list.find("li:not(.ui-li-divider)").removeClass(a.mobile.activeBtnClass).attr("aria-selected",!1).each(function(b){if(a.inArray(b,g)>-1){var c=a(this);c.attr("aria-selected",!0),d.isMultiple?c.find(".ui-icon").removeClass("ui-icon-checkbox-off").addClass("ui-icon-checkbox-on"):c.is(".ui-selectmenu-placeholder")?c.next().addClass(a.mobile.activeBtnClass):c.addClass(a.mobile.activeBtnClass)}})},close:function(){if(this.options.disabled||!this.isOpen)return;var b=this;b.menuType==="page"?a.mobile.back():(b.listbox.popup("close"),b.list.appendTo(b.listbox),b._focusButton()),b.isOpen=!1},open:function(){function o(){var b=c.list.find("."+a.mobile.activeBtnClass+" a");b.length===0&&(b=c.list.find("li.ui-btn:not( :jqmData(placeholder='true') ) a")),b.first().focus().closest("li").addClass("ui-btn-down-"+d.options.theme)}if(this.options.disabled)return;var c=this,e=a(b),f=c.list.parent(),g=f.outerHeight(),h=f.outerWidth(),i=a("."+a.mobile.activePageClass),j=e.scrollTop(),k=c.button.offset().top,l=e.height(),n=e.width();c.button.addClass(a.mobile.activeBtnClass),setTimeout(function(){c.button.removeClass(a.mobile.activeBtnClass)},300),g>l-80||!a.support.scrollTop?(c.menuPage.appendTo(a.mobile.pageContainer).page(),c.menuPageContent=m.find(".ui-content"),c.menuPageClose=m.find(".ui-header a"),c.thisPage.unbind("pagehide.remove"),j===0&&k>l&&c.thisPage.one("pagehide",function(){a(this).jqmData("lastScroll",k)}),c.menuPage.one("pageshow",function(){o(),c.isOpen=!0}),c.menuType="page",c.menuPageContent.append(c.list),c.menuPage.find("div .ui-title").text(c.label.text()),a.mobile.changePage(c.menuPage,{transition:a.mobile.defaultDialogTransition})):(c.menuType="overlay",c.listbox.one("popupafteropen",o).popup("open",{x:c.button.offset().left+c.button.outerWidth()/2,y:c.button.offset().top+c.button.outerHeight()/2}),c.isOpen=!0)},_buildList:function(){var b=this,d=this.options,e=this.placeholder,f=!0,g=[],h=[],i=b.isMultiple?"checkbox-off":"false";b.list.empty().filter(".ui-listview").listview("destroy");var j=b.select.find("option"),k=j.length,l=this.select[0],m="data-"+a.mobile.ns,n=m+"option-index",o=m+"icon",p=m+"role",q=m+"placeholder",r=c.createDocumentFragment(),s=!1,t;for(var u=0;u
tag
# - consists '|' -> table
# - consists other characters -> blockquote
- if ( lineno+1 >= strings_len or
- not (s.count('-') == len(s) and len(s)>3) ):
+ if (lineno+1 >= strings_len or
+ not(s.count('-') == len(s) and len(s)>3)):
return (s, mtag, lineno)
lineno+=1
@@ -1034,7 +1034,8 @@ def render(text,
while lineno < strings_len:
s = strings[lineno].strip()
if s[:1] == '=':
- if s.count('=')==len(s) and len(s)>3: # header or footer
+ # header or footer
+ if s.count('=')==len(s) and len(s)>3:
if not thead: # if thead list is empty:
thead = tout
else:
@@ -1054,16 +1055,16 @@ def render(text,
tr = ''
else:
tr = ' ' if rownum == 0 else ' '
- tout.append(tr+''.join([' '+pp)
+ tout.append(tr + ''.join(['%s '% \
- (' class="num"'
- if regex_num.match(f)
- else '',
- f.strip()
- ) for f in s.split('|')])+'%s ' % (
+ ' class="num"'
+ if regex_num.match(f) else '',
+ f.strip()
+ ) for f in s.split('|')])+''+pp)
rownum+=1
lineno+=1
- t_cls = ' class="%s%s"'%(class_prefix, t_cls) if t_cls and t_cls != 'id' else ''
+ t_cls = ' class="%s%s"'%(class_prefix, t_cls) \
+ if t_cls and t_cls != 'id' else ''
t_id = ' id="%s%s"'%(id_prefix, t_id) if t_id else ''
s = ''
if thead:
@@ -1080,7 +1081,7 @@ def render(text,
else:
# parse blockquote:
bq_begin=lineno
- t_mode = False # embidded table
+ t_mode = False # embedded table
t_cls = ''
t_id = ''
@@ -1090,13 +1091,15 @@ def render(text,
if not t_mode:
m = regex_tq.match(s)
if m:
- if lineno+1 == strings_len or '|' not in strings[lineno+1]:
+ if (lineno+1 == strings_len or
+ '|' not in strings[lineno+1]):
t_cls = m.group('c') or ''
t_id = m.group('p') or ''
break
if regex_bq_headline.match(s):
- if lineno+1 < strings_len and strings[lineno+1].strip():
+ if (lineno+1 < strings_len and
+ strings[lineno+1].strip()):
t_mode = True
lineno+=1
continue
@@ -1107,25 +1110,15 @@ def render(text,
lineno+=1
- t_cls = ' class="%s%s"'%(class_prefix,t_cls) if t_cls and t_cls != 'id' else ''
- t_id = ' id="%s%s"'%(id_prefix,t_id) if t_id else ''
+ t_cls = ' class="%s%s"'%(class_prefix,t_cls) \
+ if t_cls and t_cls != 'id' else ''
+ t_id = ' id="%s%s"'%(id_prefix,t_id) \
+ if t_id else ''
+
s = '%s
%s' \
% (t_cls,
t_id,
- render('\n'.join(strings[bq_begin:lineno]),
- extra,
- allowed,
- 'br',
- URL,
- environment,
- latex,
- autolinks,
- protolinks,
- class_prefix,
- id_prefix,
- pretty_print),
- pp
- )
+ '\n'.join(strings[bq_begin:lineno]),pp)
mtag='q'
else:
s = '
'
@@ -1440,4 +1433,4 @@ if __name__ == '__main__':
print " file.markmin [file.css] - process file.markmin + built in file.css (optional)"
print " file.markmin [@path_to/css] - process file.markmin + link path_to/css (optional)"
run_doctests()
-
+
diff --git a/gluon/dal.py b/gluon/dal.py
index 0739f582..9ad7bb17 100644
--- a/gluon/dal.py
+++ b/gluon/dal.py
@@ -194,7 +194,7 @@ CALLABLETYPES = (types.LambdaType, types.FunctionType,
TABLE_ARGS = set(
('migrate','primarykey','fake_migrate','format','redefine',
- 'singular','plural','trigger_name','sequence_name',
+ 'singular','plural','trigger_name','sequence_name','fields',
'common_filter','polymodel','table_class','on_define','actual_name'))
SELECT_ARGS = set(
@@ -253,7 +253,7 @@ REGEX_TYPE = re.compile('^([\w\_\:]+)')
REGEX_DBNAME = re.compile('^(\w+)(\:\w+)*')
REGEX_W = re.compile('^\w+$')
REGEX_TABLE_DOT_FIELD = re.compile('^(\w+)\.(\w+)$')
-REGEX_UPLOAD_PATTERN = re.compile('(?P[\w\-]+)\.(?P
[\w\-]+)\.(?P
Temporarily down for maintenance
")
+ elif request.is_local and exists(disabled):
+ data = dict([item.strip() for item in line.split(':',1)]
+ for line in open(disabled) if line.strip())
+ if data.get('disabled','True').lower() != 'false':
+ if 'redirect' in data:
+ redirect(data['redirect'])
+ if 'message' in data:
+ raise HTTP(503, data['message'])
+ raise HTTP(503, "Temporarily down for maintenance
")
# ##################################################
# build missing folders
@@ -544,7 +415,7 @@ def wsgibase(environ, responder):
# get the GET and POST data
# ##################################################
- parse_get_post_vars(request, environ)
+ #parse_get_post_vars(request, environ)
# ##################################################
# expose wsgi hooks for convenience
@@ -643,11 +514,17 @@ def wsgibase(environ, responder):
# on application error, rollback database
# ##################################################
- ticket = e.log(request) or 'unknown'
+ # log tickets before rollback if not in DB
+ if not request.tickets_db:
+ ticket = e.log(request) or 'unknown'
+ # rollback
if response._custom_rollback:
response._custom_rollback()
else:
BaseAdapter.close_all_instances('rollback')
+ # if tickets in db, reconnect and store it in db
+ if request.tickets_db:
+ ticket = e.log(request) or 'unknown'
http_response = \
HTTP(500, rwthread.routes.error_message_ticket %
diff --git a/gluon/restricted.py b/gluon/restricted.py
index 7d5ca513..4d113a09 100644
--- a/gluon/restricted.py
+++ b/gluon/restricted.py
@@ -48,11 +48,19 @@ class TicketStorage(Storage):
self._store_on_disk(request, ticket_id, ticket_data)
def _store_in_db(self, request, ticket_id, ticket_data):
- table = self._get_table(self.db, self.tablename, request.application)
- table.insert(ticket_id=ticket_id,
- ticket_data=cPickle.dumps(ticket_data),
- created_datetime=request.now)
- logger.error('In FILE: %(layer)s\n\n%(traceback)s\n' % ticket_data)
+ self.db._adapter.reconnect()
+ try:
+ table = self._get_table(self.db, self.tablename, request.application)
+ id = table.insert(ticket_id=ticket_id,
+ ticket_data=cPickle.dumps(ticket_data),
+ created_datetime=request.now)
+ self.db.commit()
+ message = 'In FILE: %(layer)s\n\n%(traceback)s\n'
+ except Exception, e:
+ self.db.rollback()
+ message =' Unable to store in FILE: %(layer)s\n\n%(traceback)s\n'
+ self.db.close()
+ logger.error(message % ticket_data)
def _store_on_disk(self, request, ticket_id, ticket_data):
ef = self._error_file(request, ticket_id, 'wb')
@@ -71,16 +79,13 @@ class TicketStorage(Storage):
def _get_table(self, db, tablename, app):
tablename = tablename + '_' + app
- table = db.get(tablename, None)
- if table is None:
- db.rollback() # not necessary but one day
- # any app may store tickets on DB
+ table = db.get(tablename)
+ if not table:
table = db.define_table(
tablename,
db.Field('ticket_id', length=100),
db.Field('ticket_data', 'text'),
- db.Field('created_datetime', 'datetime'),
- )
+ db.Field('created_datetime', 'datetime'))
return table
def load(
diff --git a/gluon/settings.py b/gluon/settings.py
index 76058408..92962570 100644
--- a/gluon/settings.py
+++ b/gluon/settings.py
@@ -36,3 +36,6 @@ global_settings.is_jython = \
'java' in sys.platform.lower() or \
hasattr(sys, 'JYTHON_JAR') or \
str(sys.copyright).find('Jython') > 0
+
+global_settings.is_source = os.path.exists(os.path.join(
+ global_settings.gluon_parent,'web2py.py'))
diff --git a/gluon/shell.py b/gluon/shell.py
index 54a52f47..c1d080be 100644
--- a/gluon/shell.py
+++ b/gluon/shell.py
@@ -24,7 +24,7 @@ from utils import web2py_uuid
from compileapp import build_environment, read_pyc, run_models_in
from restricted import RestrictedError
from globals import Request, Response, Session
-from storage import Storage
+from storage import Storage, List
from admin import w2p_unpack
from dal import BaseAdapter
@@ -38,7 +38,7 @@ def enable_autocomplete_and_history(adir,env):
except ImportError:
pass
else:
- readline.parse_and_bind("bind ^I rl_complete"
+ readline.parse_and_bind("bind ^I rl_complete"
if sys.platform == 'darwin'
else "tab: complete")
history_file = os.path.join(adir,'.pythonhistory')
@@ -71,7 +71,7 @@ def exec_environment(
"""
if request is None:
- request = Request()
+ request = Request({})
if response is None:
response = Response()
if session is None:
@@ -116,7 +116,7 @@ def env(
web2py environment.
"""
- request = Request()
+ request = Request({})
response = Response()
session = Session()
request.application = a
@@ -131,13 +131,21 @@ def env(
request.function = f or 'index'
response.view = '%s/%s.html' % (request.controller,
request.function)
- request.env.path_info = '/%s/%s/%s' % (a, c, f)
request.env.http_host = '127.0.0.1:8000'
request.env.remote_addr = '127.0.0.1'
request.env.web2py_runtime_gae = global_settings.web2py_runtime_gae
for k, v in extra_request.items():
request[k] = v
+
+ path_info = '/%s/%s/%s' % (a, c, f)
+ if request.args:
+ path_info = '%s/%s' % (path_info, '/'.join(request.args))
+ if request.vars:
+ vars = ['%s=%s' % (k,v) if v else '%s' % k
+ for (k,v) in request.vars.iteritems()]
+ path_info = '%s?%s' % (path_info, '&'.join(vars))
+ request.env.path_info = path_info
# Monkey patch so credentials checks pass.
@@ -178,7 +186,8 @@ def run(
import_models=False,
startfile=None,
bpython=False,
- python_code=False):
+ python_code=False,
+ cronjob=False):
"""
Start interactive shell or run Python script (startfile) in web2py
controller environment. appname is formatted like:
@@ -187,7 +196,7 @@ def run(
a/c exec the controller c into the application environment
"""
- (a, c, f) = parse_path_info(appname)
+ (a, c, f, args, vars) = parse_path_info(appname, av=True)
errmsg = 'invalid application name: %s' % appname
if not a:
die(errmsg)
@@ -219,18 +228,23 @@ def run(
if c:
import_models = True
- _env = env(a, c=c, f=f, import_models=import_models)
+ extra_request = {}
+ if args:
+ extra_request['args'] = args
+ if vars:
+ extra_request['vars'] = vars
+ _env = env(a, c=c, f=f, import_models=import_models, extra_request=extra_request)
if c:
- cfile = os.path.join('applications', a, 'controllers', c + '.py')
- if not os.path.isfile(cfile):
- cfile = os.path.join('applications', a, 'compiled',
+ pyfile = os.path.join('applications', a, 'controllers', c + '.py')
+ pycfile = os.path.join('applications', a, 'compiled',
"controllers_%s_%s.pyc" % (c, f))
- if not os.path.isfile(cfile):
- die(errmsg)
- else:
- exec read_pyc(cfile) in _env
+ if ((cronjob and os.path.isfile(pycfile))
+ or not os.path.isfile(pyfile)):
+ exec read_pyc(pycfile) in _env
+ elif os.path.isfile(pyfile):
+ execfile(pyfile, _env)
else:
- execfile(cfile, _env)
+ die(errmsg)
if f:
exec ('print %s()' % f, _env)
@@ -294,13 +308,25 @@ def run(
code.interact(local=_env)
-def parse_path_info(path_info):
+def parse_path_info(path_info, av=False):
"""
Parse path info formatted like a/c/f where c and f are optional
and a leading / accepted.
Return tuple (a, c, f). If invalid path_info a is set to None.
If c or f are omitted they are set to None.
+ If av=True, parse args and vars
"""
+ if av:
+ vars = None
+ if '?' in path_info:
+ path_info, query = path_info.split('?', 2)
+ vars = Storage()
+ for var in query.split('&'):
+ (var, val) = var.split('=', 2) if '=' in var else (var, None)
+ vars[var] = val
+ items = List(path_info.split('/'))
+ args = List(items[3:]) if len(items) > 3 else None
+ return (items(0), items(1), items(2), args, vars)
mo = re.match(r'^/?(?P\w+)(/(?P