Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2802e29945 | ||
|
|
e9eb8cbfc7 | ||
|
|
d343d8380c | ||
|
|
02906fa39f | ||
|
|
c1e797fe24 | ||
|
|
d7a42d8445 | ||
|
|
4f82bed52e | ||
|
|
84365f6721 | ||
|
|
e209dcc8d3 | ||
|
|
cd15a0f983 | ||
|
|
eb435e785c | ||
|
|
f03e521120 | ||
|
|
883909af4b | ||
|
|
13d66433e7 | ||
|
|
c44cfcb27c | ||
|
|
c14e5cbae5 | ||
|
|
f09e0b4205 | ||
|
|
ad72cea9a6 | ||
|
|
c289bc4239 | ||
|
|
733fa01b7e | ||
|
|
4d03460944 | ||
|
|
b3ba5d9eaa | ||
|
|
9e8ef3585e | ||
|
|
5c9cf44720 | ||
|
|
05a0d19ee9 | ||
|
|
d38adbe6ca | ||
|
|
871981cec7 | ||
|
|
8a54001e11 | ||
|
|
1e59f6e8be | ||
|
|
0e1eb5b56e | ||
|
|
e43df945b4 | ||
|
|
c23706b794 | ||
|
|
98cd10c6f5 | ||
|
|
55b92e854c | ||
|
|
0c926d60b8 | ||
|
|
d4d91fd003 | ||
|
|
89c4efbac3 | ||
|
|
3a5a34da0a | ||
|
|
cf3992545d | ||
|
|
0b7f663d43 | ||
|
|
abd72f8df0 | ||
|
|
1abdf72a04 | ||
|
|
7c536b66d0 | ||
|
|
cc1c019216 | ||
|
|
d20f231b34 | ||
|
|
8b03bf5fd9 | ||
|
|
af4025731a |
+3
-7
@@ -22,13 +22,9 @@ before_script:
|
|||||||
- if [[ $DB == mysql* ]]; then mysql -e 'create database test_w2p;'; fi
|
- if [[ $DB == mysql* ]]; then mysql -e 'create database test_w2p;'; fi
|
||||||
- if [[ $DB == postgres* ]]; then psql -c 'create database test_w2p;' -U postgres; fi
|
- if [[ $DB == postgres* ]]; then psql -c 'create database test_w2p;' -U postgres; fi
|
||||||
|
|
||||||
# Install last sdk for app engine
|
# Install last sdk for app engine (update only whenever a new release is available)
|
||||||
- if [[ $DB == google* ]]; then wget http://googleappengine.googlecode.com/svn/trunk/python/VERSION -O ./GAEVERSION; fi
|
- if [[ $DB == google* ]]; then wget http://googleappengine.googlecode.com/files/google_appengine_1.8.9.zip -nv; fi
|
||||||
- if [[ $DB == google* ]]; then GAERELEASE=$(cat ./GAEVERSION | grep -i release); fi
|
- if [[ $DB == google* ]]; then unzip -q google_appengine_1.8.9.zip; fi
|
||||||
- if [[ $DB == google* ]]; then GAERELEASE=${GAERELEASE#*\"}; fi
|
|
||||||
- if [[ $DB == google* ]]; then GAERELEASE=${GAERELEASE%\"}; fi
|
|
||||||
- if [[ $DB == google* ]]; then wget http://googleappengine.googlecode.com/files/google_appengine_$GAERELEASE.zip -nv; fi
|
|
||||||
- if [[ $DB == google* ]]; then unzip -q google_appengine_$GAERELEASE.zip; fi
|
|
||||||
- if [[ $DB == google* ]]; then mv -f ./google_appengine/google ./google; fi
|
- if [[ $DB == google* ]]; then mv -f ./google_appengine/google ./google; fi
|
||||||
|
|
||||||
- if [[ $DB == mongodb* ]]; then pip install pymongo; fi
|
- if [[ $DB == mongodb* ]]; then pip install pymongo; fi
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
## 2.9.1 - 2.9.3
|
## 2.9.1 - 2.9.5
|
||||||
|
|
||||||
|
- many small but important bug fixes
|
||||||
- jquery 1.11
|
- jquery 1.11
|
||||||
- codemirror 3.21, thanks Paolo Valleri
|
- codemirror 3.21, thanks Paolo Valleri
|
||||||
- fixed security issue with sessions in database, thanks Nathan Humphreys
|
- fixed security issue with sessions in database, thanks Nathan Humphreys
|
||||||
@@ -20,7 +21,6 @@
|
|||||||
- invalidate function in web2py.js, thanks Paolo
|
- invalidate function in web2py.js, thanks Paolo
|
||||||
- DAL(...,adapter_args=dict(engine='MyISAM'))
|
- DAL(...,adapter_args=dict(engine='MyISAM'))
|
||||||
- todolist panel in admin editor, thanks Paolo Valleri
|
- todolist panel in admin editor, thanks Paolo Valleri
|
||||||
- enable killing processed in windows, thanks Yair
|
|
||||||
|
|
||||||
## 2.8.1
|
## 2.8.1
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ update:
|
|||||||
echo "remember that pymysql was tweaked"
|
echo "remember that pymysql was tweaked"
|
||||||
src:
|
src:
|
||||||
### Use semantic versioning
|
### Use semantic versioning
|
||||||
echo 'Version 2.9.3-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
echo 'Version 2.9.5-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
||||||
### rm -f all junk files
|
### rm -f all junk files
|
||||||
make clean
|
make clean
|
||||||
### clean up baisc apps
|
### clean up baisc apps
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Version 2.9.3-stable+timestamp.2014.03.03.08.49.54
|
Version 2.9.5-stable+timestamp.2014.03.15.21.24.06
|
||||||
|
|||||||
@@ -1937,7 +1937,7 @@ def install_plugin():
|
|||||||
session.flash = T('New plugin installed: %s', filename)
|
session.flash = T('New plugin installed: %s', filename)
|
||||||
else:
|
else:
|
||||||
session.flash = \
|
session.flash = \
|
||||||
T('unable to create application "%s"', filename)
|
T('unable to install plugin "%s"', filename)
|
||||||
redirect(URL(f="plugins", args=[app,]))
|
redirect(URL(f="plugins", args=[app,]))
|
||||||
return dict(form=form, app=app, plugin=plugin, source=source)
|
return dict(form=form, app=app, plugin=plugin, source=source)
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li><a target="_blank" href="http://www.metacryption.com">MetaCryption, LLC</a> (USA)</li>
|
<li><a target="_blank" href="http://www.metacryption.com">MetaCryption, LLC</a> (USA)</li>
|
||||||
|
<li><a target="_blank" href="http://www.planethost.com">PlanetHost</a> (USA)</li>
|
||||||
<li><a target="_blank" href="http://www.secution.com">Secution, Inc</a> (USA)</li>
|
<li><a target="_blank" href="http://www.secution.com">Secution, Inc</a> (USA)</li>
|
||||||
<li><a target="_blank" href="http://www.wadecybertech.com">Wade Cybertech</a> (Canada)</li>
|
<li><a target="_blank" href="http://www.wadecybertech.com">Wade Cybertech</a> (Canada)</li>
|
||||||
<li><a target="_blank" href="http://www.formatics.nl">Formatics</a> (Netherlands)</li>
|
<li><a target="_blank" href="http://www.formatics.nl">Formatics</a> (Netherlands)</li>
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ response.subtitle = ''
|
|||||||
|
|
||||||
## read more at http://dev.w3.org/html5/markup/meta.name.html
|
## read more at http://dev.w3.org/html5/markup/meta.name.html
|
||||||
response.meta.author = 'Your Name <you@example.com>'
|
response.meta.author = 'Your Name <you@example.com>'
|
||||||
response.meta.description = 'a cool new app'
|
|
||||||
response.meta.keywords = 'web2py, python, framework'
|
response.meta.keywords = 'web2py, python, framework'
|
||||||
response.meta.generator = 'Web2py Web Framework'
|
response.meta.generator = 'Web2py Web Framework'
|
||||||
|
|
||||||
|
|||||||
@@ -17,15 +17,19 @@ class MemcacheClient(object):
|
|||||||
|
|
||||||
client = Client()
|
client = Client()
|
||||||
|
|
||||||
def __init__(self, request):
|
def __init__(self, request, default_time_expire = 300):
|
||||||
self.request = request
|
self.request = request
|
||||||
|
self.default_time_expire = default_time_expire
|
||||||
|
|
||||||
def __call__(
|
def __call__(
|
||||||
self,
|
self,
|
||||||
key,
|
key,
|
||||||
f,
|
f,
|
||||||
time_expire=300,
|
time_expire=None,
|
||||||
):
|
):
|
||||||
|
if time_expire is None:
|
||||||
|
time_expire = self.default_time_expire
|
||||||
|
|
||||||
key = '%s/%s' % (self.request.application, key)
|
key = '%s/%s' % (self.request.application, key)
|
||||||
value = None
|
value = None
|
||||||
obj = self.client.get(key)
|
obj = self.client.get(key)
|
||||||
|
|||||||
@@ -172,9 +172,9 @@ server for requests. It can be used for the optional"scope" parameters for Face
|
|||||||
if open_url:
|
if open_url:
|
||||||
try:
|
try:
|
||||||
data = open_url.read()
|
data = open_url.read()
|
||||||
resp_type = open_url.info().get('Content-Type')
|
resp_type = open_url.info().gettype()
|
||||||
# try json style first
|
# try json style first
|
||||||
if not resp_type or resp_type == 'application/json':
|
if not resp_type or resp_type[:16] == 'application/json':
|
||||||
try:
|
try:
|
||||||
tokendata = json.loads(data)
|
tokendata = json.loads(data)
|
||||||
current.session.token = tokendata
|
current.session.token = tokendata
|
||||||
|
|||||||
@@ -292,8 +292,11 @@ class Table(DALStorage):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self._tablename
|
return self._tablename
|
||||||
|
|
||||||
def __call__(self, id):
|
def __call__(self, id, **kwargs):
|
||||||
return self.get(id)
|
record = self.get(id)
|
||||||
|
if kwargs and any(record[key]!=kwargs[key] for key in kwargs):
|
||||||
|
return None
|
||||||
|
return record
|
||||||
|
|
||||||
class Expression(object):
|
class Expression(object):
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ class MockTable(object):
|
|||||||
self.session_expiry = session_expiry
|
self.session_expiry = session_expiry
|
||||||
self.with_lock = with_lock
|
self.with_lock = with_lock
|
||||||
|
|
||||||
def __call__(self, record_id):
|
def __call__(self, record_id, unique_key=None):
|
||||||
# Support DAL shortcut query: table(record_id)
|
# Support DAL shortcut query: table(record_id)
|
||||||
|
|
||||||
q = self.id # This will call the __getattr__ below
|
q = self.id # This will call the __getattr__ below
|
||||||
@@ -120,6 +120,7 @@ class MockTable(object):
|
|||||||
# Instructs MockQuery, to behave as db(table.id == record_id)
|
# Instructs MockQuery, to behave as db(table.id == record_id)
|
||||||
q.op = 'eq'
|
q.op = 'eq'
|
||||||
q.value = record_id
|
q.value = record_id
|
||||||
|
q.unique_key = unique_key
|
||||||
|
|
||||||
row = q.select()
|
row = q.select()
|
||||||
return row[0] if row else Storage()
|
return row[0] if row else Storage()
|
||||||
@@ -129,7 +130,7 @@ class MockTable(object):
|
|||||||
#return a fake query. We need to query it just by id for normal operations
|
#return a fake query. We need to query it just by id for normal operations
|
||||||
self.query = MockQuery(field='id', db=self.r_server,
|
self.query = MockQuery(field='id', db=self.r_server,
|
||||||
prefix=self.keyprefix, session_expiry=self.session_expiry,
|
prefix=self.keyprefix, session_expiry=self.session_expiry,
|
||||||
with_lock=self.with_lock)
|
with_lock=self.with_lock, unique_key=self.unique_key)
|
||||||
return self.query
|
return self.query
|
||||||
elif key == '_db':
|
elif key == '_db':
|
||||||
#needed because of the calls in sessions2trash.py and globals.py
|
#needed because of the calls in sessions2trash.py and globals.py
|
||||||
@@ -162,7 +163,7 @@ class MockQuery(object):
|
|||||||
and listing all keys. No other operation is supported
|
and listing all keys. No other operation is supported
|
||||||
"""
|
"""
|
||||||
def __init__(self, field=None, db=None, prefix=None, session_expiry=False,
|
def __init__(self, field=None, db=None, prefix=None, session_expiry=False,
|
||||||
with_lock=False):
|
with_lock=False, unique_key=None):
|
||||||
self.field = field
|
self.field = field
|
||||||
self.value = None
|
self.value = None
|
||||||
self.db = db
|
self.db = db
|
||||||
@@ -170,6 +171,7 @@ class MockQuery(object):
|
|||||||
self.op = None
|
self.op = None
|
||||||
self.session_expiry = session_expiry
|
self.session_expiry = session_expiry
|
||||||
self.with_lock = with_lock
|
self.with_lock = with_lock
|
||||||
|
self.unique_key = unique_key
|
||||||
|
|
||||||
def __eq__(self, value, op='eq'):
|
def __eq__(self, value, op='eq'):
|
||||||
self.value = value
|
self.value = value
|
||||||
@@ -187,7 +189,12 @@ class MockQuery(object):
|
|||||||
acquire_lock(self.db, key + ':lock', self.value)
|
acquire_lock(self.db, key + ':lock', self.value)
|
||||||
rtn = self.db.hgetall(key)
|
rtn = self.db.hgetall(key)
|
||||||
if rtn:
|
if rtn:
|
||||||
rtn['update_record'] = self.update # update record support
|
if self.unique_key:
|
||||||
|
#make sure the id and unique_key are correct
|
||||||
|
if rtn['unique_key'] == self.unique_key:
|
||||||
|
rtn['update_record'] = self.update # update record support
|
||||||
|
else:
|
||||||
|
rtn = None
|
||||||
return [Storage(rtn)] if rtn else []
|
return [Storage(rtn)] if rtn else []
|
||||||
elif self.op == 'ge' and self.field == 'id' and self.value == 0:
|
elif self.op == 'ge' and self.field == 'id' and self.value == 0:
|
||||||
#means that someone wants the complete list
|
#means that someone wants the complete list
|
||||||
|
|||||||
@@ -81,12 +81,13 @@ class JSONSafeTransport(JSONTransportMixin, SafeTransport):
|
|||||||
class ServerProxy(object):
|
class ServerProxy(object):
|
||||||
"JSON RPC Simple Client Service Proxy"
|
"JSON RPC Simple Client Service Proxy"
|
||||||
|
|
||||||
def __init__(self, uri, transport=None, encoding=None, verbose=0):
|
def __init__(self, uri, transport=None, encoding=None, verbose=0,version=None):
|
||||||
self.location = uri # server location (url)
|
self.location = uri # server location (url)
|
||||||
self.trace = verbose # show debug messages
|
self.trace = verbose # show debug messages
|
||||||
self.exceptions = True # raise errors? (JSONRPCError)
|
self.exceptions = True # raise errors? (JSONRPCError)
|
||||||
self.timeout = None
|
self.timeout = None
|
||||||
self.json_request = self.json_response = ''
|
self.json_request = self.json_response = ''
|
||||||
|
self.version = version # '2.0' for jsonrpc2
|
||||||
|
|
||||||
type, uri = urllib.splittype(uri)
|
type, uri = urllib.splittype(uri)
|
||||||
if type not in ("http", "https"):
|
if type not in ("http", "https"):
|
||||||
@@ -112,6 +113,8 @@ class ServerProxy(object):
|
|||||||
# build data sent to the service
|
# build data sent to the service
|
||||||
request_id = random.randint(0, sys.maxint)
|
request_id = random.randint(0, sys.maxint)
|
||||||
data = {'id': request_id, 'method': method, 'params': args, }
|
data = {'id': request_id, 'method': method, 'params': args, }
|
||||||
|
if self.version:
|
||||||
|
data['jsonrpc'] = self.version #mandatory key/value for jsonrpc2 validation else err -32600
|
||||||
request = json.dumps(data)
|
request = json.dumps(data)
|
||||||
|
|
||||||
# make HTTP request (retry if connection is lost)
|
# make HTTP request (retry if connection is lost)
|
||||||
@@ -130,14 +133,13 @@ class ServerProxy(object):
|
|||||||
# {'version': '1.1', 'id': id, 'result': result, 'error': None}
|
# {'version': '1.1', 'id': id, 'result': result, 'error': None}
|
||||||
response = json.loads(response)
|
response = json.loads(response)
|
||||||
|
|
||||||
if response['id'] != request_id:
|
|
||||||
raise JSONRPCError(0, "JSON Request ID != Response ID")
|
|
||||||
|
|
||||||
self.error = response.get('error', {})
|
self.error = response.get('error', {})
|
||||||
if self.error and self.exceptions:
|
if self.error and self.exceptions:
|
||||||
raise JSONRPCError(self.error.get('code', 0),
|
raise JSONRPCError(self.error.get('code', 0),
|
||||||
self.error.get('message', ''),
|
self.error.get('message', ''),
|
||||||
self.error.get('data', None))
|
self.error.get('data', None))
|
||||||
|
if response['id'] != request_id:
|
||||||
|
raise JSONRPCError(0, "JSON Request ID != Response ID")
|
||||||
|
|
||||||
return response.get('result')
|
return response.get('result')
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
translitcodec was originally written by Jason Kirtland in 2008.
|
|
||||||
|
|
||||||
Contributors are:
|
|
||||||
|
|
||||||
- Jason Kirtland <jek@discorporate.us>
|
|
||||||
- Craig Dennis <craig@idealist.org>
|
|
||||||
|
|
||||||
The translitcodec source distribution includes the 'transtab' package
|
|
||||||
by Markus Kuhn <mkuhn@acm.org>.
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
=====================
|
|
||||||
translitcodec Changes
|
|
||||||
=====================
|
|
||||||
|
|
||||||
0.3
|
|
||||||
---
|
|
||||||
|
|
||||||
Released on February 14, 2011
|
|
||||||
|
|
||||||
- Fixes to the transtab table rebuilding tool.
|
|
||||||
|
|
||||||
- Added translitcodec.__version__
|
|
||||||
|
|
||||||
0.2
|
|
||||||
---
|
|
||||||
|
|
||||||
Released on January 27, 2011
|
|
||||||
|
|
||||||
- Resolves issue of "TypeError: character mapping must return integer,
|
|
||||||
None or unicode" when a blank value (eg: \N{ZERO WIDTH SPACE} \u200B)
|
|
||||||
was encoded. Unicode blanks are now returned.
|
|
||||||
|
|
||||||
- Characters in the ASCII range are no longer included in the translation
|
|
||||||
tables.
|
|
||||||
|
|
||||||
0.1
|
|
||||||
---
|
|
||||||
|
|
||||||
Released on December 28, 2008
|
|
||||||
|
|
||||||
- Initial packaged release.
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
Copyright (c) 2008 Jason Kirtland <jek at discorporate us>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included
|
|
||||||
in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
-*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
Unicode to 8-bit charset transliteration codec.
|
|
||||||
|
|
||||||
This package contains codecs for transliterating ISO 10646 texts into
|
|
||||||
best-effort representations using smaller coded character sets (ASCII,
|
|
||||||
ISO 8859, etc.). The translation tables used by the codecs are from
|
|
||||||
the ``transtab`` collection by Markus Kuhn.
|
|
||||||
|
|
||||||
Three types of transliterating codecs are provided:
|
|
||||||
|
|
||||||
"long", using as many characters as needed to make a natural
|
|
||||||
replacement. For example, \u00e4 LATIN SMALL LETTER A WITH
|
|
||||||
DIAERESIS ``ä`` will be replaced with ``ae``.
|
|
||||||
|
|
||||||
"short", using the minimum number of characters to make a
|
|
||||||
replacement. For example, \u00e4 LATIN SMALL LETTER A WITH
|
|
||||||
DIAERESIS ``ä`` will be replaced with ``a``.
|
|
||||||
|
|
||||||
"one", only performing single character replacements. Characters
|
|
||||||
that can not be transliterated with a single character are passed
|
|
||||||
through unchanged. For example, \u2639 WHITE FROWNING FACE ``☹``
|
|
||||||
will be passed through unchanged.
|
|
||||||
|
|
||||||
Using the codecs is simple::
|
|
||||||
|
|
||||||
>>> import translitcodec
|
|
||||||
>>> u'fácil € ☺'.encode('translit/long')
|
|
||||||
u'facil EUR :-)'
|
|
||||||
>>> u'fácil € ☺'.encode('translit/short')
|
|
||||||
u'facil E :-)'
|
|
||||||
|
|
||||||
The codecs return Unicode by default. To receive a bytestring back,
|
|
||||||
either chain the output of encode() to another codec, or append the
|
|
||||||
name of the desired byte encoding to the codec name::
|
|
||||||
|
|
||||||
>>> u'fácil € ☺'.encode('translit/one').encode('ascii', 'replace')
|
|
||||||
'facil E ?'
|
|
||||||
>>> u'fácil € ☺'.encode('translit/one/ascii', 'replace')
|
|
||||||
'facil E ?'
|
|
||||||
|
|
||||||
The package also supplies a 'transliterate' codec, an alias for
|
|
||||||
'translit/long'.
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
+44
-4
@@ -1480,7 +1480,7 @@ class BaseAdapter(ConnectionPool):
|
|||||||
return '(%s)' % ' || '.join(self.expand(x,'string') for x in items)
|
return '(%s)' % ' || '.join(self.expand(x,'string') for x in items)
|
||||||
|
|
||||||
def ADD(self, first, second):
|
def ADD(self, first, second):
|
||||||
if self.is_numerical_type(first.type) or isinstance(first.type, gluon.dal.Field):
|
if self.is_numerical_type(first.type) or isinstance(first.type, Field):
|
||||||
return '(%s + %s)' % (self.expand(first),
|
return '(%s + %s)' % (self.expand(first),
|
||||||
self.expand(second, first.type))
|
self.expand(second, first.type))
|
||||||
else:
|
else:
|
||||||
@@ -9153,8 +9153,17 @@ class Table(object):
|
|||||||
record = self(_key)
|
record = self(_key)
|
||||||
|
|
||||||
if not response.errors and record:
|
if not response.errors and record:
|
||||||
row = self._db(self._id ==_key)
|
if '_id' in self:
|
||||||
response.id = row.update(**fields)
|
myset = self._db(self._id == record[self._id.name])
|
||||||
|
else:
|
||||||
|
query = None
|
||||||
|
for key, value in _key.iteritems():
|
||||||
|
if query is None:
|
||||||
|
query = getattr(self, key) == value
|
||||||
|
else:
|
||||||
|
query = query & (getattr(self, key) == value)
|
||||||
|
myset = self._db(query)
|
||||||
|
response.id = myset.update(**fields)
|
||||||
else:
|
else:
|
||||||
response.id = None
|
response.id = None
|
||||||
return response
|
return response
|
||||||
@@ -9173,6 +9182,37 @@ class Table(object):
|
|||||||
newid = self.insert(**values)
|
newid = self.insert(**values)
|
||||||
return newid
|
return newid
|
||||||
|
|
||||||
|
def validate_and_update_or_insert(self, _key=DEFAULT, **fields):
|
||||||
|
if _key is DEFAULT or _key == '':
|
||||||
|
primary_keys = {}
|
||||||
|
for key, value in fields.iteritems():
|
||||||
|
if key in self._primarykey:
|
||||||
|
primary_keys[key] = value
|
||||||
|
if primary_keys != {}:
|
||||||
|
record = self(**primary_keys)
|
||||||
|
_key = primary_keys
|
||||||
|
else:
|
||||||
|
required_keys = {}
|
||||||
|
for key, value in fields.iteritems():
|
||||||
|
if getattr(self, key).required:
|
||||||
|
required_keys[key] = value
|
||||||
|
record = self(**required_keys)
|
||||||
|
_key = required_keys
|
||||||
|
elif isinstance(_key, dict):
|
||||||
|
record = self(**_key)
|
||||||
|
else:
|
||||||
|
record = self(_key)
|
||||||
|
|
||||||
|
if record:
|
||||||
|
response = self.validate_and_update(_key, **fields)
|
||||||
|
primary_keys = {}
|
||||||
|
for key in self._primarykey:
|
||||||
|
primary_keys[key] = getattr(record, key)
|
||||||
|
response.id = primary_keys
|
||||||
|
else:
|
||||||
|
response = self.validate_and_insert(**fields)
|
||||||
|
return response
|
||||||
|
|
||||||
def bulk_insert(self, items):
|
def bulk_insert(self, items):
|
||||||
"""
|
"""
|
||||||
here items is a list of dictionaries
|
here items is a list of dictionaries
|
||||||
@@ -11074,7 +11114,7 @@ class Rows(object):
|
|||||||
if field.type=='blob' and not value is None:
|
if field.type=='blob' and not value is None:
|
||||||
value = base64.b64encode(value)
|
value = base64.b64encode(value)
|
||||||
elif represent and field.represent:
|
elif represent and field.represent:
|
||||||
value = field.represent(value)
|
value = field.represent(value,record)
|
||||||
row.append(none_exception(value))
|
row.append(none_exception(value))
|
||||||
writer.writerow(row)
|
writer.writerow(row)
|
||||||
|
|
||||||
|
|||||||
+302
-232
@@ -2,9 +2,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This file is part of the web2py Web Framework
|
| This file is part of the web2py Web Framework
|
||||||
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||||
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||||
|
|
||||||
|
Template helpers
|
||||||
|
--------------------------------------------
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import cgi
|
import cgi
|
||||||
@@ -109,10 +112,11 @@ __all__ = [
|
|||||||
|
|
||||||
def xmlescape(data, quote=True):
|
def xmlescape(data, quote=True):
|
||||||
"""
|
"""
|
||||||
returns an escaped string of the provided data
|
Returns an escaped string of the provided data
|
||||||
|
|
||||||
:param data: the data to be escaped
|
Args:
|
||||||
:param quote: optional (default False)
|
data: the data to be escaped
|
||||||
|
quote: optional (default False)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# first try the xml function
|
# first try the xml function
|
||||||
@@ -164,80 +168,92 @@ def URL(
|
|||||||
language=None,
|
language=None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
generate a URL
|
|
||||||
|
|
||||||
example::
|
|
||||||
|
|
||||||
>>> str(URL(a='a', c='c', f='f', args=['x', 'y', 'z'],
|
|
||||||
... vars={'p':1, 'q':2}, anchor='1'))
|
|
||||||
'/a/c/f/x/y/z?p=1&q=2#1'
|
|
||||||
|
|
||||||
>>> str(URL(a='a', c='c', f='f', args=['x', 'y', 'z'],
|
|
||||||
... vars={'p':(1,3), 'q':2}, anchor='1'))
|
|
||||||
'/a/c/f/x/y/z?p=1&p=3&q=2#1'
|
|
||||||
|
|
||||||
>>> str(URL(a='a', c='c', f='f', args=['x', 'y', 'z'],
|
|
||||||
... vars={'p':(3,1), 'q':2}, anchor='1'))
|
|
||||||
'/a/c/f/x/y/z?p=3&p=1&q=2#1'
|
|
||||||
|
|
||||||
>>> str(URL(a='a', c='c', f='f', anchor='1+2'))
|
|
||||||
'/a/c/f#1%2B2'
|
|
||||||
|
|
||||||
>>> str(URL(a='a', c='c', f='f', args=['x', 'y', 'z'],
|
|
||||||
... vars={'p':(1,3), 'q':2}, anchor='1', hmac_key='key'))
|
|
||||||
'/a/c/f/x/y/z?p=1&p=3&q=2&_signature=a32530f0d0caa80964bb92aad2bedf8a4486a31f#1'
|
|
||||||
|
|
||||||
>>> str(URL(a='a', c='c', f='f', args=['w/x', 'y/z']))
|
|
||||||
'/a/c/f/w/x/y/z'
|
|
||||||
|
|
||||||
>>> str(URL(a='a', c='c', f='f', args=['w/x', 'y/z'], encode_embedded_slash=True))
|
|
||||||
'/a/c/f/w%2Fx/y%2Fz'
|
|
||||||
|
|
||||||
>>> str(URL(a='a', c='c', f='f', args=['%(id)d'], url_encode=False))
|
|
||||||
'/a/c/f/%(id)d'
|
|
||||||
|
|
||||||
>>> str(URL(a='a', c='c', f='f', args=['%(id)d'], url_encode=True))
|
|
||||||
'/a/c/f/%25%28id%29d'
|
|
||||||
|
|
||||||
>>> str(URL(a='a', c='c', f='f', vars={'id' : '%(id)d' }, url_encode=False))
|
|
||||||
'/a/c/f?id=%(id)d'
|
|
||||||
|
|
||||||
>>> str(URL(a='a', c='c', f='f', vars={'id' : '%(id)d' }, url_encode=True))
|
|
||||||
'/a/c/f?id=%25%28id%29d'
|
|
||||||
|
|
||||||
>>> str(URL(a='a', c='c', f='f', anchor='%(id)d', url_encode=False))
|
|
||||||
'/a/c/f#%(id)d'
|
|
||||||
|
|
||||||
>>> str(URL(a='a', c='c', f='f', anchor='%(id)d', url_encode=True))
|
|
||||||
'/a/c/f#%25%28id%29d'
|
|
||||||
|
|
||||||
generates a url '/a/c/f' corresponding to application a, controller c
|
generates a url '/a/c/f' corresponding to application a, controller c
|
||||||
and function f. If r=request is passed, a, c, f are set, respectively,
|
and function f. If r=request is passed, a, c, f are set, respectively,
|
||||||
to r.application, r.controller, r.function.
|
to r.application, r.controller, r.function.
|
||||||
|
|
||||||
The more typical usage is:
|
The more typical usage is:
|
||||||
|
|
||||||
URL(r=request, f='index') that generates a url for the index function
|
URL('index')
|
||||||
|
|
||||||
|
that generates a url for the index function
|
||||||
within the present application and controller.
|
within the present application and controller.
|
||||||
|
|
||||||
:param a: application (default to current if r is given)
|
Args:
|
||||||
:param c: controller (default to current if r is given)
|
a: application (default to current if r is given)
|
||||||
:param f: function (default to current if r is given)
|
c: controller (default to current if r is given)
|
||||||
:param r: request (optional)
|
f: function (default to current if r is given)
|
||||||
:param args: any arguments (optional)
|
r: request (optional)
|
||||||
:param vars: any variables (optional)
|
args: any arguments (optional). Additional "path" elements
|
||||||
:param anchor: anchorname, without # (optional)
|
vars: any variables (optional). Querystring elements
|
||||||
:param hmac_key: key to use when generating hmac signature (optional)
|
anchor: anchorname, without # (optional)
|
||||||
:param hash_vars: which of the vars to include in our hmac signature
|
extension: force an extension
|
||||||
True (default) - hash all vars, False - hash none of the vars,
|
hmac_key: key to use when generating hmac signature (optional)
|
||||||
iterable - hash only the included vars ['key1','key2']
|
hash_vars: which of the vars to include in our hmac signature
|
||||||
:param scheme: URI scheme (True, 'http' or 'https', etc); forces absolute URL (optional)
|
True (default) - hash all vars, False - hash none of the vars,
|
||||||
:param host: string to force absolute URL with host (True means http_host)
|
iterable - hash only the included vars ['key1','key2']
|
||||||
:param port: optional port number (forces absolute URL)
|
salt: salt hashing with this string
|
||||||
|
user_signature: signs automatically the URL in such way that only the
|
||||||
|
user can access the URL (use with `URL.verify` or
|
||||||
|
`auth.requires_signature()`)
|
||||||
|
scheme: URI scheme (True, 'http' or 'https', etc); forces absolute URL (optional)
|
||||||
|
host: string to force absolute URL with host (True means http_host)
|
||||||
|
port: optional port number (forces absolute URL)
|
||||||
|
encode_embedded_slash: encode slash characters included in args
|
||||||
|
url_encode: encode characters included in vars
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
SyntaxError: when no application, controller or function is available
|
||||||
|
or when a CRLF is found in the generated url
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
>>> str(URL(a='a', c='c', f='f', args=['x', 'y', 'z'],
|
||||||
|
... vars={'p':1, 'q':2}, anchor='1'))
|
||||||
|
'/a/c/f/x/y/z?p=1&q=2#1'
|
||||||
|
|
||||||
|
>>> str(URL(a='a', c='c', f='f', args=['x', 'y', 'z'],
|
||||||
|
... vars={'p':(1,3), 'q':2}, anchor='1'))
|
||||||
|
'/a/c/f/x/y/z?p=1&p=3&q=2#1'
|
||||||
|
|
||||||
|
>>> str(URL(a='a', c='c', f='f', args=['x', 'y', 'z'],
|
||||||
|
... vars={'p':(3,1), 'q':2}, anchor='1'))
|
||||||
|
'/a/c/f/x/y/z?p=3&p=1&q=2#1'
|
||||||
|
|
||||||
|
>>> str(URL(a='a', c='c', f='f', anchor='1+2'))
|
||||||
|
'/a/c/f#1%2B2'
|
||||||
|
|
||||||
|
>>> str(URL(a='a', c='c', f='f', args=['x', 'y', 'z'],
|
||||||
|
... vars={'p':(1,3), 'q':2}, anchor='1', hmac_key='key'))
|
||||||
|
'/a/c/f/x/y/z?p=1&p=3&q=2&_signature=a32530f0d0caa80964bb92aad2bedf8a4486a31f#1'
|
||||||
|
|
||||||
|
>>> str(URL(a='a', c='c', f='f', args=['w/x', 'y/z']))
|
||||||
|
'/a/c/f/w/x/y/z'
|
||||||
|
|
||||||
|
>>> str(URL(a='a', c='c', f='f', args=['w/x', 'y/z'], encode_embedded_slash=True))
|
||||||
|
'/a/c/f/w%2Fx/y%2Fz'
|
||||||
|
|
||||||
|
>>> str(URL(a='a', c='c', f='f', args=['%(id)d'], url_encode=False))
|
||||||
|
'/a/c/f/%(id)d'
|
||||||
|
|
||||||
|
>>> str(URL(a='a', c='c', f='f', args=['%(id)d'], url_encode=True))
|
||||||
|
'/a/c/f/%25%28id%29d'
|
||||||
|
|
||||||
|
>>> str(URL(a='a', c='c', f='f', vars={'id' : '%(id)d' }, url_encode=False))
|
||||||
|
'/a/c/f?id=%(id)d'
|
||||||
|
|
||||||
|
>>> str(URL(a='a', c='c', f='f', vars={'id' : '%(id)d' }, url_encode=True))
|
||||||
|
'/a/c/f?id=%25%28id%29d'
|
||||||
|
|
||||||
|
>>> str(URL(a='a', c='c', f='f', anchor='%(id)d', url_encode=False))
|
||||||
|
'/a/c/f#%(id)d'
|
||||||
|
|
||||||
|
>>> str(URL(a='a', c='c', f='f', anchor='%(id)d', url_encode=True))
|
||||||
|
'/a/c/f#%25%28id%29d'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
:raises SyntaxError: when no application, controller or function is
|
|
||||||
available
|
|
||||||
:raises SyntaxError: when a CRLF is found in the generated url
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from rewrite import url_out # done here in case used not-in web2py
|
from rewrite import url_out # done here in case used not-in web2py
|
||||||
@@ -528,7 +544,7 @@ class XML(XmlComponent):
|
|||||||
use it to wrap a string that contains XML/HTML so that it will not be
|
use it to wrap a string that contains XML/HTML so that it will not be
|
||||||
escaped by the template
|
escaped by the template
|
||||||
|
|
||||||
example:
|
Examples:
|
||||||
|
|
||||||
>>> XML('<h1>Hello</h1>').xml()
|
>>> XML('<h1>Hello</h1>').xml()
|
||||||
'<h1>Hello</h1>'
|
'<h1>Hello</h1>'
|
||||||
@@ -564,19 +580,19 @@ class XML(XmlComponent):
|
|||||||
},
|
},
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
:param text: the XML text
|
Args:
|
||||||
:param sanitize: sanitize text using the permitted tags and allowed
|
text: the XML text
|
||||||
attributes (default False)
|
sanitize: sanitize text using the permitted tags and allowed
|
||||||
:param permitted_tags: list of permitted tags (default: simple list of
|
attributes (default False)
|
||||||
tags)
|
permitted_tags: list of permitted tags (default: simple list of
|
||||||
:param allowed_attributes: dictionary of allowed attributed (default
|
tags)
|
||||||
for A, IMG and BlockQuote).
|
allowed_attributes: dictionary of allowed attributed (default
|
||||||
The key is the tag; the value is a list of allowed attributes.
|
for A, IMG and BlockQuote).
|
||||||
|
The key is the tag; the value is a list of allowed attributes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if sanitize:
|
if sanitize:
|
||||||
text = sanitizer.sanitize(text, permitted_tags,
|
text = sanitizer.sanitize(text, permitted_tags, allowed_attributes)
|
||||||
allowed_attributes)
|
|
||||||
if isinstance(text, unicode):
|
if isinstance(text, unicode):
|
||||||
text = text.encode('utf8', 'xmlcharrefreplace')
|
text = text.encode('utf8', 'xmlcharrefreplace')
|
||||||
elif not isinstance(text, str):
|
elif not isinstance(text, str):
|
||||||
@@ -620,7 +636,8 @@ class XML(XmlComponent):
|
|||||||
|
|
||||||
def flatten(self, render=None):
|
def flatten(self, render=None):
|
||||||
"""
|
"""
|
||||||
return the text stored by the XML object rendered by the render function
|
returns the text stored by the XML object rendered
|
||||||
|
by the `render` function
|
||||||
"""
|
"""
|
||||||
if render:
|
if render:
|
||||||
return render(self.text, None, {})
|
return render(self.text, None, {})
|
||||||
@@ -628,8 +645,9 @@ class XML(XmlComponent):
|
|||||||
|
|
||||||
def elements(self, *args, **kargs):
|
def elements(self, *args, **kargs):
|
||||||
"""
|
"""
|
||||||
to be considered experimental since the behavior of this method is questionable
|
to be considered experimental since the behavior of this method
|
||||||
another options could be TAG(self.text).elements(*args,**kargs)
|
is questionable
|
||||||
|
another option could be `TAG(self.text).elements(*args,**kwargs)`
|
||||||
"""
|
"""
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@@ -653,15 +671,15 @@ class DIV(XmlComponent):
|
|||||||
Behaves like a dictionary regarding updating of attributes.
|
Behaves like a dictionary regarding updating of attributes.
|
||||||
Behaves like a list regarding inserting/appending components.
|
Behaves like a list regarding inserting/appending components.
|
||||||
|
|
||||||
example::
|
Examples:
|
||||||
|
|
||||||
>>> DIV('hello', 'world', _style='color:red;').xml()
|
>>> DIV('hello', 'world', _style='color:red;').xml()
|
||||||
'<div style=\"color:red;\">helloworld</div>'
|
'<div style=\"color:red;\">helloworld</div>'
|
||||||
|
|
||||||
all other HTML helpers are derived from DIV.
|
All other HTML helpers are derived from `DIV`.
|
||||||
|
|
||||||
_something=\"value\" attributes are transparently translated into
|
`_something="value"` attributes are transparently translated into
|
||||||
something=\"value\" HTML attributes
|
`something="value"` HTML attributes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# name of the tag, subclasses should update this
|
# name of the tag, subclasses should update this
|
||||||
@@ -671,10 +689,12 @@ class DIV(XmlComponent):
|
|||||||
|
|
||||||
def __init__(self, *components, **attributes):
|
def __init__(self, *components, **attributes):
|
||||||
"""
|
"""
|
||||||
:param *components: any components that should be nested in this element
|
Args:
|
||||||
:param **attributes: any attributes you want to give to this element
|
components: any components that should be nested in this element
|
||||||
|
attributes: any attributes you want to give to this element
|
||||||
|
|
||||||
:raises SyntaxError: when a stand alone tag receives components
|
Raises:
|
||||||
|
SyntaxError: when a stand alone tag receives components
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.tag[-1:] == '/' and components:
|
if self.tag[-1:] == '/' and components:
|
||||||
@@ -705,6 +725,8 @@ class DIV(XmlComponent):
|
|||||||
"""
|
"""
|
||||||
list style appending of components
|
list style appending of components
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
>>> a=DIV()
|
>>> a=DIV()
|
||||||
>>> a.append(SPAN('x'))
|
>>> a.append(SPAN('x'))
|
||||||
>>> print a
|
>>> print a
|
||||||
@@ -717,7 +739,9 @@ class DIV(XmlComponent):
|
|||||||
|
|
||||||
def insert(self, i, value):
|
def insert(self, i, value):
|
||||||
"""
|
"""
|
||||||
list style inserting of components
|
List-style inserting of components
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
>>> a=DIV()
|
>>> a=DIV()
|
||||||
>>> a.insert(0,SPAN('x'))
|
>>> a.insert(0,SPAN('x'))
|
||||||
@@ -731,12 +755,12 @@ class DIV(XmlComponent):
|
|||||||
|
|
||||||
def __getitem__(self, i):
|
def __getitem__(self, i):
|
||||||
"""
|
"""
|
||||||
gets attribute with name 'i' or component #i.
|
Gets attribute with name 'i' or component #i.
|
||||||
If attribute 'i' is not found returns None
|
If attribute 'i' is not found returns None
|
||||||
|
|
||||||
:param i: index
|
Args:
|
||||||
if i is a string: the name of the attribute
|
i: index. If i is a string: the name of the attribute
|
||||||
otherwise references to number of the component
|
otherwise references to number of the component
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if isinstance(i, str):
|
if isinstance(i, str):
|
||||||
@@ -749,12 +773,12 @@ class DIV(XmlComponent):
|
|||||||
|
|
||||||
def __setitem__(self, i, value):
|
def __setitem__(self, i, value):
|
||||||
"""
|
"""
|
||||||
sets attribute with name 'i' or component #i.
|
Sets attribute with name 'i' or component #i.
|
||||||
|
|
||||||
:param i: index
|
Args:
|
||||||
if i is a string: the name of the attribute
|
i: index. If i is a string: the name of the attribute
|
||||||
otherwise references to number of the component
|
otherwise references to number of the component
|
||||||
:param value: the new value
|
value: the new value
|
||||||
"""
|
"""
|
||||||
self._setnode(value)
|
self._setnode(value)
|
||||||
if isinstance(i, (str, unicode)):
|
if isinstance(i, (str, unicode)):
|
||||||
@@ -764,11 +788,11 @@ class DIV(XmlComponent):
|
|||||||
|
|
||||||
def __delitem__(self, i):
|
def __delitem__(self, i):
|
||||||
"""
|
"""
|
||||||
deletes attribute with name 'i' or component #i.
|
Deletes attribute with name 'i' or component #i.
|
||||||
|
|
||||||
:param i: index
|
Args:
|
||||||
if i is a string: the name of the attribute
|
i: index. If i is a string: the name of the attribute
|
||||||
otherwise references to number of the component
|
otherwise references to number of the component
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if isinstance(i, str):
|
if isinstance(i, str):
|
||||||
@@ -778,13 +802,13 @@ class DIV(XmlComponent):
|
|||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
"""
|
"""
|
||||||
returns the number of included components
|
Returns the number of included components
|
||||||
"""
|
"""
|
||||||
return len(self.components)
|
return len(self.components)
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __nonzero__(self):
|
||||||
"""
|
"""
|
||||||
always return True
|
Always returns True
|
||||||
"""
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -804,10 +828,11 @@ class DIV(XmlComponent):
|
|||||||
helper for _fixup. Checks if a component is in allowed_parents,
|
helper for _fixup. Checks if a component is in allowed_parents,
|
||||||
otherwise wraps it in wrap_parent
|
otherwise wraps it in wrap_parent
|
||||||
|
|
||||||
:param allowed_parents: (tuple) classes that the component should be an
|
Args:
|
||||||
instance of
|
allowed_parents: (tuple) classes that the component should be an
|
||||||
:param wrap_parent: the class to wrap the component in, if needed
|
instance of
|
||||||
:param wrap_lambda: lambda to use for wrapping, if needed
|
wrap_parent: the class to wrap the component in, if needed
|
||||||
|
wrap_lambda: lambda to use for wrapping, if needed
|
||||||
|
|
||||||
"""
|
"""
|
||||||
components = []
|
components = []
|
||||||
@@ -875,7 +900,7 @@ class DIV(XmlComponent):
|
|||||||
|
|
||||||
def _xml(self):
|
def _xml(self):
|
||||||
"""
|
"""
|
||||||
helper for xml generation. Returns separately:
|
Helper for xml generation. Returns separately:
|
||||||
- the component attributes
|
- the component attributes
|
||||||
- the generated xml of the inner components
|
- the generated xml of the inner components
|
||||||
|
|
||||||
@@ -883,7 +908,8 @@ class DIV(XmlComponent):
|
|||||||
do not have a False or None value. The underscore is removed.
|
do not have a False or None value. The underscore is removed.
|
||||||
A value of True is replaced with the attribute name.
|
A value of True is replaced with the attribute name.
|
||||||
|
|
||||||
:returns: tuple: (attributes, components)
|
Returns:
|
||||||
|
tuple: (attributes, components)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# get the attributes for this component
|
# get the attributes for this component
|
||||||
@@ -932,16 +958,18 @@ class DIV(XmlComponent):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""
|
"""
|
||||||
str(COMPONENT) returns equals COMPONENT.xml()
|
str(COMPONENT) returns COMPONENT.xml()
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return self.xml()
|
return self.xml()
|
||||||
|
|
||||||
def flatten(self, render=None):
|
def flatten(self, render=None):
|
||||||
"""
|
"""
|
||||||
return the text stored by the DIV object rendered by the render function
|
Returns the text stored by the DIV object rendered by the render function
|
||||||
the render function must take text, tagname, and attributes
|
the render function must take text, tagname, and attributes
|
||||||
render=None is equivalent to render=lambda text, tag, attr: text
|
`render=None` is equivalent to `render=lambda text, tag, attr: text`
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
>>> markdown = lambda text,tag=None,attributes={}: \
|
>>> markdown = lambda text,tag=None,attributes={}: \
|
||||||
{None: re.sub('\s+',' ',text), \
|
{None: re.sub('\s+',' ',text), \
|
||||||
@@ -972,11 +1000,13 @@ class DIV(XmlComponent):
|
|||||||
|
|
||||||
def elements(self, *args, **kargs):
|
def elements(self, *args, **kargs):
|
||||||
"""
|
"""
|
||||||
find all component that match the supplied attribute dictionary,
|
Find all components that match the supplied attribute dictionary,
|
||||||
or None if nothing could be found
|
or None if nothing could be found
|
||||||
|
|
||||||
All components of the components are searched.
|
All components of the components are searched.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
>>> a = DIV(DIV(SPAN('x'),3,DIV(SPAN('y'))))
|
>>> a = DIV(DIV(SPAN('x'),3,DIV(SPAN('y'))))
|
||||||
>>> for c in a.elements('span',first_only=True): c[0]='z'
|
>>> for c in a.elements('span',first_only=True): c[0]='z'
|
||||||
>>> print a
|
>>> print a
|
||||||
@@ -987,6 +1017,8 @@ class DIV(XmlComponent):
|
|||||||
|
|
||||||
It also supports a syntax compatible with jQuery
|
It also supports a syntax compatible with jQuery
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
>>> a=TAG('<div><span><a id="1-1" u:v=$>hello</a></span><p class="this is a test">world</p></div>')
|
>>> a=TAG('<div><span><a id="1-1" u:v=$>hello</a></span><p class="this is a test">world</p></div>')
|
||||||
>>> for e in a.elements('div a#1-1, p.is'): print e.flatten()
|
>>> for e in a.elements('div a#1-1, p.is'): print e.flatten()
|
||||||
hello
|
hello
|
||||||
@@ -995,7 +1027,6 @@ class DIV(XmlComponent):
|
|||||||
hello
|
hello
|
||||||
>>> a.elements('a[u:v=$]')[0].xml()
|
>>> a.elements('a[u:v=$]')[0].xml()
|
||||||
'<a id="1-1" u:v="$">hello</a>'
|
'<a id="1-1" u:v="$">hello</a>'
|
||||||
|
|
||||||
>>> a=FORM( INPUT(_type='text'), SELECT(range(1)), TEXTAREA() )
|
>>> a=FORM( INPUT(_type='text'), SELECT(range(1)), TEXTAREA() )
|
||||||
>>> for c in a.elements('input, select, textarea'): c['_disabled'] = 'disabled'
|
>>> for c in a.elements('input, select, textarea'): c['_disabled'] = 'disabled'
|
||||||
>>> a.xml()
|
>>> a.xml()
|
||||||
@@ -1005,6 +1036,8 @@ class DIV(XmlComponent):
|
|||||||
a "replace" argument (note, a list of the original matching elements
|
a "replace" argument (note, a list of the original matching elements
|
||||||
is still returned as usual).
|
is still returned as usual).
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
|
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
|
||||||
>>> b = a.elements('span.abc', replace=P('x', _class='xyz'))
|
>>> b = a.elements('span.abc', replace=P('x', _class='xyz'))
|
||||||
>>> print a
|
>>> print a
|
||||||
@@ -1013,6 +1046,8 @@ class DIV(XmlComponent):
|
|||||||
"replace" can be a callable, which will be passed the original element and
|
"replace" can be a callable, which will be passed the original element and
|
||||||
should return a new element to replace it.
|
should return a new element to replace it.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
|
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
|
||||||
>>> b = a.elements('span.abc', replace=lambda el: P(el[0], _class='xyz'))
|
>>> b = a.elements('span.abc', replace=lambda el: P(el[0], _class='xyz'))
|
||||||
>>> print a
|
>>> print a
|
||||||
@@ -1020,6 +1055,8 @@ class DIV(XmlComponent):
|
|||||||
|
|
||||||
If replace=None, matching elements will be removed completely.
|
If replace=None, matching elements will be removed completely.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
|
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
|
||||||
>>> b = a.elements('span', find='y', replace=None)
|
>>> b = a.elements('span', find='y', replace=None)
|
||||||
>>> print a
|
>>> print a
|
||||||
@@ -1030,6 +1067,8 @@ class DIV(XmlComponent):
|
|||||||
replaced (find_text is ignored if "replace" is not also specified).
|
replaced (find_text is ignored if "replace" is not also specified).
|
||||||
Like the "find" argument, "find_text" can be a string or a compiled regex.
|
Like the "find" argument, "find_text" can be a string or a compiled regex.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
|
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='abc'), SPAN('z', _class='abc'))))
|
||||||
>>> b = a.elements(find_text=re.compile('x|y|z'), replace='hello')
|
>>> b = a.elements(find_text=re.compile('x|y|z'), replace='hello')
|
||||||
>>> print a
|
>>> print a
|
||||||
@@ -1038,6 +1077,8 @@ class DIV(XmlComponent):
|
|||||||
If other attributes are specified along with find_text, then only components
|
If other attributes are specified along with find_text, then only components
|
||||||
that match the specified attributes will be searched for find_text.
|
that match the specified attributes will be searched for find_text.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='efg'), SPAN('z', _class='abc'))))
|
>>> a = DIV(DIV(SPAN('x', _class='abc'), DIV(SPAN('y', _class='efg'), SPAN('z', _class='abc'))))
|
||||||
>>> b = a.elements('span.efg', find_text=re.compile('x|y|z'), replace='hello')
|
>>> b = a.elements('span.efg', find_text=re.compile('x|y|z'), replace='hello')
|
||||||
>>> print a
|
>>> print a
|
||||||
@@ -1134,7 +1175,7 @@ class DIV(XmlComponent):
|
|||||||
|
|
||||||
def element(self, *args, **kargs):
|
def element(self, *args, **kargs):
|
||||||
"""
|
"""
|
||||||
find the first component that matches the supplied attribute dictionary,
|
Finds the first component that matches the supplied attribute dictionary,
|
||||||
or None if nothing could be found
|
or None if nothing could be found
|
||||||
|
|
||||||
Also the components of the components are searched.
|
Also the components of the components are searched.
|
||||||
@@ -1148,7 +1189,7 @@ class DIV(XmlComponent):
|
|||||||
|
|
||||||
def siblings(self, *args, **kargs):
|
def siblings(self, *args, **kargs):
|
||||||
"""
|
"""
|
||||||
find all sibling components that match the supplied argument list
|
Finds all sibling components that match the supplied argument list
|
||||||
and attribute dictionary, or None if nothing could be found
|
and attribute dictionary, or None if nothing could be found
|
||||||
"""
|
"""
|
||||||
sibs = [s for s in self.parent.components if not s == self]
|
sibs = [s for s in self.parent.components if not s == self]
|
||||||
@@ -1175,7 +1216,7 @@ class DIV(XmlComponent):
|
|||||||
|
|
||||||
def sibling(self, *args, **kargs):
|
def sibling(self, *args, **kargs):
|
||||||
"""
|
"""
|
||||||
find the first sibling component that match the supplied argument list
|
Finds the first sibling component that match the supplied argument list
|
||||||
and attribute dictionary, or None if nothing could be found
|
and attribute dictionary, or None if nothing could be found
|
||||||
"""
|
"""
|
||||||
kargs['first_only'] = True
|
kargs['first_only'] = True
|
||||||
@@ -1211,10 +1252,12 @@ copy_reg.pickle(__tag_div__, TAG_pickler, TAG_unpickler)
|
|||||||
class __TAG__(XmlComponent):
|
class __TAG__(XmlComponent):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
TAG factory example::
|
TAG factory
|
||||||
|
|
||||||
>>> print TAG.first(TAG.second('test'), _key = 3)
|
Examples:
|
||||||
<first key=\"3\"><second>test</second></first>
|
|
||||||
|
>>> print TAG.first(TAG.second('test'), _key = 3)
|
||||||
|
<first key=\"3\"><second>test</second></first>
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -1239,16 +1282,16 @@ class HTML(DIV):
|
|||||||
There are four predefined document type definitions.
|
There are four predefined document type definitions.
|
||||||
They can be specified in the 'doctype' parameter:
|
They can be specified in the 'doctype' parameter:
|
||||||
|
|
||||||
-'strict' enables strict doctype
|
- 'strict' enables strict doctype
|
||||||
-'transitional' enables transitional doctype (default)
|
- 'transitional' enables transitional doctype (default)
|
||||||
-'frameset' enables frameset doctype
|
- 'frameset' enables frameset doctype
|
||||||
-'html5' enables HTML 5 doctype
|
- 'html5' enables HTML 5 doctype
|
||||||
-any other string will be treated as user's own doctype
|
- any other string will be treated as user's own doctype
|
||||||
|
|
||||||
'lang' parameter specifies the language of the document.
|
'lang' parameter specifies the language of the document.
|
||||||
Defaults to 'en'.
|
Defaults to 'en'.
|
||||||
|
|
||||||
See also :class:`DIV`
|
See also `DIV`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tag = 'html'
|
tag = 'html'
|
||||||
@@ -1289,10 +1332,10 @@ class XHTML(DIV):
|
|||||||
There are three predefined document type definitions.
|
There are three predefined document type definitions.
|
||||||
They can be specified in the 'doctype' parameter:
|
They can be specified in the 'doctype' parameter:
|
||||||
|
|
||||||
-'strict' enables strict doctype
|
- 'strict' enables strict doctype
|
||||||
-'transitional' enables transitional doctype (default)
|
- 'transitional' enables transitional doctype (default)
|
||||||
-'frameset' enables frameset doctype
|
- 'frameset' enables frameset doctype
|
||||||
-any other string will be treated as user's own doctype
|
- any other string will be treated as user's own doctype
|
||||||
|
|
||||||
'lang' parameter specifies the language of the document and the xml document.
|
'lang' parameter specifies the language of the document and the xml document.
|
||||||
Defaults to 'en'.
|
Defaults to 'en'.
|
||||||
@@ -1300,7 +1343,7 @@ class XHTML(DIV):
|
|||||||
'xmlns' parameter specifies the xml namespace.
|
'xmlns' parameter specifies the xml namespace.
|
||||||
Defaults to 'http://www.w3.org/1999/xhtml'.
|
Defaults to 'http://www.w3.org/1999/xhtml'.
|
||||||
|
|
||||||
See also :class:`DIV`
|
See also `DIV`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tag = 'html'
|
tag = 'html'
|
||||||
@@ -1443,7 +1486,7 @@ class P(DIV):
|
|||||||
"""
|
"""
|
||||||
Will replace ``\\n`` by ``<br />`` if the `cr2br` attribute is provided.
|
Will replace ``\\n`` by ``<br />`` if the `cr2br` attribute is provided.
|
||||||
|
|
||||||
see also :class:`DIV`
|
see also `DIV`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tag = 'p'
|
tag = 'p'
|
||||||
@@ -1476,6 +1519,23 @@ class HR(DIV):
|
|||||||
|
|
||||||
|
|
||||||
class A(DIV):
|
class A(DIV):
|
||||||
|
"""
|
||||||
|
Generates an A() link.
|
||||||
|
A() in web2py is really important and with the included web2py.js
|
||||||
|
allows lots of Ajax interactions in the page
|
||||||
|
|
||||||
|
On top of "usual" `_attributes`, it takes
|
||||||
|
|
||||||
|
Args:
|
||||||
|
callback: an url to call but not redirect to
|
||||||
|
cid: if you want to load the _href into an element of the page (component)
|
||||||
|
pass its id (without the #) here
|
||||||
|
delete: element to delete after calling callback
|
||||||
|
target: same thing as cid
|
||||||
|
confirm: text to display upon a callback with a delete
|
||||||
|
noconfirm: don't display alert upon a callback with delete
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
tag = 'a'
|
tag = 'a'
|
||||||
|
|
||||||
@@ -1546,24 +1606,25 @@ class CENTER(DIV):
|
|||||||
class CODE(DIV):
|
class CODE(DIV):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
displays code in HTML with syntax highlighting.
|
Displays code in HTML with syntax highlighting.
|
||||||
|
|
||||||
:param attributes: optional attributes:
|
Args:
|
||||||
|
language: indicates the language, otherwise PYTHON is assumed
|
||||||
|
link: can provide a link
|
||||||
|
styles: for styles
|
||||||
|
|
||||||
- language: indicates the language, otherwise PYTHON is assumed
|
Examples:
|
||||||
- link: can provide a link
|
|
||||||
- styles: for styles
|
|
||||||
|
|
||||||
Example::
|
{{=CODE(\"print 'hello world'\", language='python', link=None,
|
||||||
|
counter=1, styles={}, highlight_line=None)}}
|
||||||
{{=CODE(\"print 'hello world'\", language='python', link=None,
|
|
||||||
counter=1, styles={}, highlight_line=None)}}
|
|
||||||
|
|
||||||
|
|
||||||
supported languages are \"python\", \"html_plain\", \"c\", \"cpp\",
|
supported languages are
|
||||||
\"web2py\", \"html\".
|
|
||||||
The \"html\" language interprets {{ and }} tags as \"web2py\" code,
|
"python", "html_plain", "c", "cpp", "web2py", "html"
|
||||||
\"html_plain\" doesn't.
|
|
||||||
|
The "html" language interprets {{ and }} tags as "web2py" code,
|
||||||
|
"html_plain" doesn't.
|
||||||
|
|
||||||
if a link='/examples/global/vars/' is provided web2py keywords are linked to
|
if a link='/examples/global/vars/' is provided web2py keywords are linked to
|
||||||
the online docs.
|
the online docs.
|
||||||
@@ -1607,7 +1668,6 @@ class UL(DIV):
|
|||||||
|
|
||||||
If subcomponents are not LI-components they will be wrapped in a LI
|
If subcomponents are not LI-components they will be wrapped in a LI
|
||||||
|
|
||||||
see also :class:`DIV`
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tag = 'ul'
|
tag = 'ul'
|
||||||
@@ -1637,7 +1697,6 @@ class TR(DIV):
|
|||||||
|
|
||||||
If subcomponents are not TD/TH-components they will be wrapped in a TD
|
If subcomponents are not TD/TH-components they will be wrapped in a TD
|
||||||
|
|
||||||
see also :class:`DIV`
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tag = 'tr'
|
tag = 'tr'
|
||||||
@@ -1652,7 +1711,6 @@ class __TRHEAD__(DIV):
|
|||||||
|
|
||||||
If subcomponents are not TD/TH-components they will be wrapped in a TH
|
If subcomponents are not TD/TH-components they will be wrapped in a TH
|
||||||
|
|
||||||
see also :class:`DIV`
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tag = 'tr'
|
tag = 'tr'
|
||||||
@@ -1702,7 +1760,6 @@ class TABLE(DIV):
|
|||||||
If subcomponents are not TR/TBODY/THEAD/TFOOT-components
|
If subcomponents are not TR/TBODY/THEAD/TFOOT-components
|
||||||
they will be wrapped in a TR
|
they will be wrapped in a TR
|
||||||
|
|
||||||
see also :class:`DIV`
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tag = 'table'
|
tag = 'table'
|
||||||
@@ -1724,34 +1781,36 @@ class IFRAME(DIV):
|
|||||||
class INPUT(DIV):
|
class INPUT(DIV):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
INPUT Component
|
INPUT Component
|
||||||
|
|
||||||
examples::
|
Takes two special attributes value= and requires=.
|
||||||
|
|
||||||
>>> INPUT(_type='text', _name='name', value='Max').xml()
|
Args:
|
||||||
'<input name=\"name\" type=\"text\" value=\"Max\" />'
|
value: used to pass the initial value for the input field.
|
||||||
|
|
||||||
>>> INPUT(_type='checkbox', _name='checkbox', value='on').xml()
|
|
||||||
'<input checked=\"checked\" name=\"checkbox\" type=\"checkbox\" value=\"on\" />'
|
|
||||||
|
|
||||||
>>> INPUT(_type='radio', _name='radio', _value='yes', value='yes').xml()
|
|
||||||
'<input checked=\"checked\" name=\"radio\" type=\"radio\" value=\"yes\" />'
|
|
||||||
|
|
||||||
>>> INPUT(_type='radio', _name='radio', _value='no', value='yes').xml()
|
|
||||||
'<input name=\"radio\" type=\"radio\" value=\"no\" />'
|
|
||||||
|
|
||||||
the input helper takes two special attributes value= and requires=.
|
|
||||||
|
|
||||||
:param value: used to pass the initial value for the input field.
|
|
||||||
value differs from _value because it works for checkboxes, radio,
|
value differs from _value because it works for checkboxes, radio,
|
||||||
textarea and select/option too.
|
textarea and select/option too.
|
||||||
|
For a checkbox value should be '' or 'on'.
|
||||||
|
For a radio or select/option value should be the _value
|
||||||
|
of the checked/selected item.
|
||||||
|
|
||||||
- for a checkbox value should be '' or 'on'.
|
requires: should be None, or a validator or a list of validators
|
||||||
- for a radio or select/option value should be the _value
|
|
||||||
of the checked/selected item.
|
|
||||||
|
|
||||||
:param requires: should be None, or a validator or a list of validators
|
|
||||||
for the value of the field.
|
for the value of the field.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
>>> INPUT(_type='text', _name='name', value='Max').xml()
|
||||||
|
'<input name=\"name\" type=\"text\" value=\"Max\" />'
|
||||||
|
|
||||||
|
>>> INPUT(_type='checkbox', _name='checkbox', value='on').xml()
|
||||||
|
'<input checked=\"checked\" name=\"checkbox\" type=\"checkbox\" value=\"on\" />'
|
||||||
|
|
||||||
|
>>> INPUT(_type='radio', _name='radio', _value='yes', value='yes').xml()
|
||||||
|
'<input checked=\"checked\" name=\"radio\" type=\"radio\" value=\"yes\" />'
|
||||||
|
|
||||||
|
>>> INPUT(_type='radio', _name='radio', _value='no', value='yes').xml()
|
||||||
|
'<input name=\"radio\" type=\"radio\" value=\"no\" />'
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tag = 'input/'
|
tag = 'input/'
|
||||||
@@ -1847,11 +1906,12 @@ class INPUT(DIV):
|
|||||||
class TEXTAREA(INPUT):
|
class TEXTAREA(INPUT):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
example::
|
Examples::
|
||||||
|
|
||||||
TEXTAREA(_name='sometext', value='blah '*100, requires=IS_NOT_EMPTY())
|
TEXTAREA(_name='sometext', value='blah ' * 100, requires=IS_NOT_EMPTY())
|
||||||
|
|
||||||
'blah blah blah ...' will be the content of the textarea field.
|
'blah blah blah ...' will be the content of the textarea field.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tag = 'textarea'
|
tag = 'textarea'
|
||||||
@@ -1898,12 +1958,12 @@ class OPTGROUP(DIV):
|
|||||||
class SELECT(INPUT):
|
class SELECT(INPUT):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
example::
|
Examples:
|
||||||
|
|
||||||
>>> from validators import IS_IN_SET
|
>>> from validators import IS_IN_SET
|
||||||
>>> SELECT('yes', 'no', _name='selector', value='yes',
|
>>> SELECT('yes', 'no', _name='selector', value='yes',
|
||||||
... requires=IS_IN_SET(['yes', 'no'])).xml()
|
... requires=IS_IN_SET(['yes', 'no'])).xml()
|
||||||
'<select name=\"selector\"><option selected=\"selected\" value=\"yes\">yes</option><option value=\"no\">no</option></select>'
|
'<select name=\"selector\"><option selected=\"selected\" value=\"yes\">yes</option><option value=\"no\">no</option></select>'
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -1962,12 +2022,13 @@ class LEGEND(DIV):
|
|||||||
class FORM(DIV):
|
class FORM(DIV):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
example::
|
Examples:
|
||||||
|
|
||||||
|
>>> from validators import IS_NOT_EMPTY
|
||||||
|
>>> form=FORM(INPUT(_name="test", requires=IS_NOT_EMPTY()))
|
||||||
|
>>> form.xml()
|
||||||
|
'<form action=\"#\" enctype=\"multipart/form-data\" method=\"post\"><input name=\"test\" type=\"text\" /></form>'
|
||||||
|
|
||||||
>>> from validators import IS_NOT_EMPTY
|
|
||||||
>>> form=FORM(INPUT(_name="test", requires=IS_NOT_EMPTY()))
|
|
||||||
>>> form.xml()
|
|
||||||
'<form action=\"#\" enctype=\"multipart/form-data\" method=\"post\"><input name=\"test\" type=\"text\" /></form>'
|
|
||||||
|
|
||||||
a FORM is container for INPUT, TEXTAREA, SELECT and other helpers
|
a FORM is container for INPUT, TEXTAREA, SELECT and other helpers
|
||||||
|
|
||||||
@@ -2107,12 +2168,12 @@ class FORM(DIV):
|
|||||||
you can use it instead of directly form.accepts.
|
you can use it instead of directly form.accepts.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
In controller
|
In controller::
|
||||||
|
|
||||||
def action():
|
def action():
|
||||||
form=FORM(INPUT(_name=\"test\", requires=IS_NOT_EMPTY()))
|
form=FORM(INPUT(_name=\"test\", requires=IS_NOT_EMPTY()))
|
||||||
form.validate() #you can pass some args here - see below
|
form.validate() #you can pass some args here - see below
|
||||||
return dict(form=form)
|
return dict(form=form)
|
||||||
|
|
||||||
This can receive a bunch of arguments
|
This can receive a bunch of arguments
|
||||||
|
|
||||||
@@ -2190,29 +2251,31 @@ class FORM(DIV):
|
|||||||
"""
|
"""
|
||||||
Perform the .validate() method but returns the form
|
Perform the .validate() method but returns the form
|
||||||
|
|
||||||
Usage in controllers:
|
Usage in controllers::
|
||||||
# directly on return
|
|
||||||
def action():
|
|
||||||
#some code here
|
|
||||||
return dict(form=FORM(...).process(...))
|
|
||||||
|
|
||||||
You can use it with FORM, SQLFORM or FORM based plugins
|
# directly on return
|
||||||
|
def action():
|
||||||
|
#some code here
|
||||||
|
return dict(form=FORM(...).process(...))
|
||||||
|
|
||||||
Examples:
|
You can use it with FORM, SQLFORM or FORM based plugins::
|
||||||
#response.flash messages
|
|
||||||
def action():
|
# response.flash messages
|
||||||
form = SQLFORM(db.table).process(message_onsuccess='Sucess!')
|
def action():
|
||||||
retutn dict(form=form)
|
form = SQLFORM(db.table).process(message_onsuccess='Sucess!')
|
||||||
|
return dict(form=form)
|
||||||
|
|
||||||
|
# callback function
|
||||||
|
# callback receives True or False as first arg, and a list of args.
|
||||||
|
def my_callback(status, msg):
|
||||||
|
response.flash = "Success! "+msg if status else "Errors occured"
|
||||||
|
|
||||||
|
# after argument can be 'flash' to response.flash messages
|
||||||
|
# or a function name to use as callback or None to do nothing.
|
||||||
|
def action():
|
||||||
|
return dict(form=SQLFORM(db.table).process(onsuccess=my_callback)
|
||||||
|
|
||||||
# callback function
|
|
||||||
# callback receives True or False as first arg, and a list of args.
|
|
||||||
def my_callback(status, msg):
|
|
||||||
response.flash = "Success! "+msg if status else "Errors occured"
|
|
||||||
|
|
||||||
# after argument can be 'flash' to response.flash messages
|
|
||||||
# or a function name to use as callback or None to do nothing.
|
|
||||||
def action():
|
|
||||||
return dict(form=SQLFORM(db.table).process(onsuccess=my_callback)
|
|
||||||
"""
|
"""
|
||||||
kwargs['dbio'] = kwargs.get('dbio', True)
|
kwargs['dbio'] = kwargs.get('dbio', True)
|
||||||
# necessary for SQLHTML forms
|
# necessary for SQLHTML forms
|
||||||
@@ -2313,16 +2376,20 @@ class FORM(DIV):
|
|||||||
class BEAUTIFY(DIV):
|
class BEAUTIFY(DIV):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
example::
|
Turns any list, dictionary, etc into decent looking html.
|
||||||
|
|
||||||
>>> BEAUTIFY(['a', 'b', {'hello': 'world'}]).xml()
|
|
||||||
'<div><table><tr><td><div>a</div></td></tr><tr><td><div>b</div></td></tr><tr><td><div><table><tr><td style="font-weight:bold;vertical-align:top;">hello</td><td style="vertical-align:top;">:</td><td><div>world</div></td></tr></table></div></td></tr></table></div>'
|
|
||||||
|
|
||||||
turns any list, dictionary, etc into decent looking html.
|
|
||||||
Two special attributes are
|
Two special attributes are
|
||||||
:sorted: a function that takes the dict and returned sorted keys
|
|
||||||
:keyfilter: a funciton that takes a key and returns its representation
|
- sorted: a function that takes the dict and returned sorted keys
|
||||||
or None if the key is to be skipped. By default key[:1]=='_' is skipped.
|
- keyfilter: a function that takes a key and returns its representation or
|
||||||
|
None if the key is to be skipped.
|
||||||
|
By default key[:1]=='_' is skipped.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
>>> BEAUTIFY(['a', 'b', {'hello': 'world'}]).xml()
|
||||||
|
'<div><table><tr><td><div>a</div></td></tr><tr><td><div>b</div></td></tr><tr><td><div><table><tr><td style="font-weight:bold;vertical-align:top;">hello</td><td style="vertical-align:top;">:</td><td><div>world</div></td></tr></table></div></td></tr></table></div>'
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tag = 'div'
|
tag = 'div'
|
||||||
@@ -2394,16 +2461,18 @@ class MENU(DIV):
|
|||||||
"""
|
"""
|
||||||
Used to build menus
|
Used to build menus
|
||||||
|
|
||||||
Optional arguments
|
Args:
|
||||||
_class: defaults to 'web2py-menu web2py-menu-vertical'
|
_class: defaults to 'web2py-menu web2py-menu-vertical'
|
||||||
ul_class: defaults to 'web2py-menu-vertical'
|
ul_class: defaults to 'web2py-menu-vertical'
|
||||||
li_class: defaults to 'web2py-menu-expand'
|
li_class: defaults to 'web2py-menu-expand'
|
||||||
li_first: defaults to 'web2py-menu-first'
|
li_first: defaults to 'web2py-menu-first'
|
||||||
li_last: defaults to 'web2py-menu-last'
|
li_last: defaults to 'web2py-menu-last'
|
||||||
|
|
||||||
|
Use like::
|
||||||
|
|
||||||
Example:
|
|
||||||
menu = MENU([['name', False, URL(...), [submenu]], ...])
|
menu = MENU([['name', False, URL(...), [submenu]], ...])
|
||||||
{{=menu}}
|
{{=menu}}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
tag = 'ul'
|
tag = 'ul'
|
||||||
@@ -2503,9 +2572,10 @@ def embed64(
|
|||||||
"""
|
"""
|
||||||
helper to encode the provided (binary) data into base64.
|
helper to encode the provided (binary) data into base64.
|
||||||
|
|
||||||
:param filename: if provided, opens and reads this file in 'rb' mode
|
Args:
|
||||||
:param file: if provided, reads this file
|
filename: if provided, opens and reads this file in 'rb' mode
|
||||||
:param data: if provided, uses the provided data
|
file: if provided, reads this file
|
||||||
|
data: if provided, uses the provided data
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if filename and os.path.exists(file):
|
if filename and os.path.exists(file):
|
||||||
|
|||||||
+26
-3
@@ -2,9 +2,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This file is part of the web2py Web Framework
|
| This file is part of the web2py Web Framework
|
||||||
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||||
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||||
|
|
||||||
|
HTTP statuses helpers
|
||||||
|
--------------------------------------------
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
@@ -58,6 +61,18 @@ defined_status = {
|
|||||||
regex_status = re.compile('^\d{3} [0-9A-Z ]+$')
|
regex_status = re.compile('^\d{3} [0-9A-Z ]+$')
|
||||||
|
|
||||||
class HTTP(Exception):
|
class HTTP(Exception):
|
||||||
|
"""Raises an HTTP response
|
||||||
|
|
||||||
|
Args:
|
||||||
|
status: usually an integer. If it's a well known status code, the ERROR
|
||||||
|
message will be automatically added. A string can also be passed
|
||||||
|
as `510 Foo Bar` and in that case the status code and the error
|
||||||
|
message will be parsed accordingly
|
||||||
|
body: what to return as body. If left as is, will return the error code
|
||||||
|
and the status message in the body itself
|
||||||
|
cookies: pass cookies along (usually not needed)
|
||||||
|
headers: pass headers as usual dict mapping
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -136,6 +151,14 @@ class HTTP(Exception):
|
|||||||
|
|
||||||
|
|
||||||
def redirect(location='', how=303, client_side=False):
|
def redirect(location='', how=303, client_side=False):
|
||||||
|
"""Raises a redirect (303)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
location: the url where to redirect
|
||||||
|
how: what HTTP status code to use when redirecting
|
||||||
|
client_side: if set to True, it triggers a reload of the entire page
|
||||||
|
when the fragment has been loaded as a component
|
||||||
|
"""
|
||||||
if location:
|
if location:
|
||||||
from gluon import current
|
from gluon import current
|
||||||
loc = location.replace('\r', '%0D').replace('\n', '%0A')
|
loc = location.replace('\r', '%0D').replace('\n', '%0A')
|
||||||
|
|||||||
+118
-92
@@ -2,12 +2,13 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This file is part of the web2py Web Framework
|
| This file is part of the web2py Web Framework
|
||||||
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||||
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||||
|
| Plural subsystem is created by Vladyslav Kozlovskyy (Ukraine) <dbdevelop@gmail.com>
|
||||||
|
|
||||||
Plural subsystem is created by Vladyslav Kozlovskyy (Ukraine)
|
Translation system
|
||||||
<dbdevelop@gmail.com>
|
--------------------------------------------
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@@ -27,7 +28,6 @@ from gluon.portalocker import read_locked, LockedFile
|
|||||||
from utf8 import Utf8
|
from utf8 import Utf8
|
||||||
|
|
||||||
from gluon.fileutils import listdir
|
from gluon.fileutils import listdir
|
||||||
import gluon.settings as settings
|
|
||||||
from gluon.cfs import getcfs
|
from gluon.cfs import getcfs
|
||||||
from gluon.html import XML, xmlescape
|
from gluon.html import XML, xmlescape
|
||||||
from gluon.contrib.markmin.markmin2html import render, markmin_escape
|
from gluon.contrib.markmin.markmin2html import render, markmin_escape
|
||||||
@@ -41,7 +41,6 @@ pjoin = os.path.join
|
|||||||
pexists = os.path.exists
|
pexists = os.path.exists
|
||||||
pdirname = os.path.dirname
|
pdirname = os.path.dirname
|
||||||
isdir = os.path.isdir
|
isdir = os.path.isdir
|
||||||
is_gae = False # settings.global_settings.web2py_runtime_gae
|
|
||||||
|
|
||||||
DEFAULT_LANGUAGE = 'en'
|
DEFAULT_LANGUAGE = 'en'
|
||||||
DEFAULT_LANGUAGE_NAME = 'English'
|
DEFAULT_LANGUAGE_NAME = 'English'
|
||||||
@@ -76,6 +75,10 @@ regex_plural_tuple = re.compile(
|
|||||||
'^{(?P<w>[^[\]()]+)(?:\[(?P<i>\d+)\])?}$') # %%{word[index]} or %%{word}
|
'^{(?P<w>[^[\]()]+)(?:\[(?P<i>\d+)\])?}$') # %%{word[index]} or %%{word}
|
||||||
regex_plural_file = re.compile('^plural-[a-zA-Z]{2}(-[a-zA-Z]{2})?\.py$')
|
regex_plural_file = re.compile('^plural-[a-zA-Z]{2}(-[a-zA-Z]{2})?\.py$')
|
||||||
|
|
||||||
|
def is_writable():
|
||||||
|
""" returns True if and only if the filesystem is writable """
|
||||||
|
from gluon.settings import global_settings
|
||||||
|
return not global_settings.web2py_runtime_gae
|
||||||
|
|
||||||
def safe_eval(text):
|
def safe_eval(text):
|
||||||
if text.strip():
|
if text.strip():
|
||||||
@@ -165,7 +168,7 @@ def read_dict_aux(filename):
|
|||||||
|
|
||||||
|
|
||||||
def read_dict(filename):
|
def read_dict(filename):
|
||||||
""" return dictionary with translation messages
|
""" Returns dictionary with translation messages
|
||||||
"""
|
"""
|
||||||
return getcfs('lang:' + filename, filename,
|
return getcfs('lang:' + filename, filename,
|
||||||
lambda: read_dict_aux(filename))
|
lambda: read_dict_aux(filename))
|
||||||
@@ -173,8 +176,8 @@ def read_dict(filename):
|
|||||||
|
|
||||||
def read_possible_plural_rules():
|
def read_possible_plural_rules():
|
||||||
"""
|
"""
|
||||||
create list of all possible plural rules files
|
Creates list of all possible plural rules files
|
||||||
result is cached in PLURAL_RULES dictionary to increase speed
|
The result is cached in PLURAL_RULES dictionary to increase speed
|
||||||
"""
|
"""
|
||||||
plurals = {}
|
plurals = {}
|
||||||
try:
|
try:
|
||||||
@@ -294,41 +297,49 @@ def read_plural_dict(filename):
|
|||||||
def write_plural_dict(filename, contents):
|
def write_plural_dict(filename, contents):
|
||||||
if '__corrupted__' in contents:
|
if '__corrupted__' in contents:
|
||||||
return
|
return
|
||||||
|
fp = None
|
||||||
try:
|
try:
|
||||||
fp = LockedFile(filename, 'w')
|
fp = LockedFile(filename, 'w')
|
||||||
fp.write('#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n{\n# "singular form (0)": ["first plural form (1)", "second plural form (2)", ...],\n')
|
fp.write('#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n{\n# "singular form (0)": ["first plural form (1)", "second plural form (2)", ...],\n')
|
||||||
for key in sorted(contents, lambda x, y: cmp(unicode(x, 'utf-8').lower(), unicode(y, 'utf-8').lower())):
|
for key in sorted(contents, sort_function):
|
||||||
forms = '[' + ','.join([repr(Utf8(form))
|
forms = '[' + ','.join([repr(Utf8(form))
|
||||||
for form in contents[key]]) + ']'
|
for form in contents[key]]) + ']'
|
||||||
fp.write('%s: %s,\n' % (repr(Utf8(key)), forms))
|
fp.write('%s: %s,\n' % (repr(Utf8(key)), forms))
|
||||||
fp.write('}\n')
|
fp.write('}\n')
|
||||||
except (IOError, OSError):
|
except (IOError, OSError):
|
||||||
if not is_gae:
|
if is_writable():
|
||||||
logging.warning('Unable to write to file %s' % filename)
|
logging.warning('Unable to write to file %s' % filename)
|
||||||
return
|
return
|
||||||
finally:
|
finally:
|
||||||
fp.close()
|
if fp:
|
||||||
|
fp.close()
|
||||||
|
|
||||||
|
def sort_function(x,y):
|
||||||
|
return cmp(unicode(x, 'utf-8').lower(), unicode(y, 'utf-8').lower())
|
||||||
|
|
||||||
def write_dict(filename, contents):
|
def write_dict(filename, contents):
|
||||||
if '__corrupted__' in contents:
|
if '__corrupted__' in contents:
|
||||||
return
|
return
|
||||||
|
fp = None
|
||||||
try:
|
try:
|
||||||
fp = LockedFile(filename, 'w')
|
fp = LockedFile(filename, 'w')
|
||||||
|
fp.write('# -*- coding: utf-8 -*-\n{\n')
|
||||||
|
for key in sorted(contents, sort_function):
|
||||||
|
fp.write('%s: %s,\n' % (repr(Utf8(key)),
|
||||||
|
repr(Utf8(contents[key]))))
|
||||||
|
fp.write('}\n')
|
||||||
except (IOError, OSError):
|
except (IOError, OSError):
|
||||||
if not settings.global_settings.web2py_runtime_gae:
|
if is_writable():
|
||||||
logging.warning('Unable to write to file %s' % filename)
|
logging.warning('Unable to write to file %s' % filename)
|
||||||
return
|
return
|
||||||
fp.write('# -*- coding: utf-8 -*-\n{\n')
|
finally:
|
||||||
for key in sorted(contents, lambda x, y: cmp(unicode(x, 'utf-8').lower(), unicode(y, 'utf-8').lower())):
|
if fp:
|
||||||
fp.write('%s: %s,\n' % (repr(Utf8(key)), repr(Utf8(contents[key]))))
|
fp.close()
|
||||||
fp.write('}\n')
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
|
|
||||||
class lazyT(object):
|
class lazyT(object):
|
||||||
"""
|
"""
|
||||||
never to be called explicitly, returned by
|
Never to be called explicitly, returned by
|
||||||
translator.__call__() or translator.M()
|
translator.__call__() or translator.M()
|
||||||
"""
|
"""
|
||||||
m = s = T = f = t = None
|
m = s = T = f = t = None
|
||||||
@@ -428,28 +439,27 @@ copy_reg.pickle(lazyT, pickle_lazyT)
|
|||||||
|
|
||||||
class translator(object):
|
class translator(object):
|
||||||
"""
|
"""
|
||||||
this class is instantiated by gluon.compileapp.build_environment
|
This class is instantiated by gluon.compileapp.build_environment
|
||||||
as the T object
|
as the T object
|
||||||
::
|
|
||||||
|
Example:
|
||||||
|
|
||||||
T.force(None) # turns off translation
|
T.force(None) # turns off translation
|
||||||
T.force('fr, it') # forces web2py to translate using fr.py or it.py
|
T.force('fr, it') # forces web2py to translate using fr.py or it.py
|
||||||
|
|
||||||
T(\"Hello World\") # translates \"Hello World\" using the selected file
|
T("Hello World") # translates "Hello World" using the selected file
|
||||||
|
|
||||||
notice 1: there is no need to force since, by default, T uses
|
Note:
|
||||||
http_accept_language to determine a translation file.
|
- there is no need to force since, by default, T uses
|
||||||
notice 2:
|
http_accept_language to determine a translation file.
|
||||||
en and en-en are considered different languages!
|
- en and en-en are considered different languages!
|
||||||
notice 3:
|
- if language xx-yy is not found force() probes other similar languages
|
||||||
if language xx-yy is not found force() probes other similar
|
using such algorithm: `xx-yy.py -> xx.py -> xx-yy*.py -> xx*.py`
|
||||||
languages using such algorithm:
|
|
||||||
xx-yy.py -> xx.py -> xx-yy*.py -> xx*.py
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, langpath, http_accept_language):
|
def __init__(self, langpath, http_accept_language):
|
||||||
self.langpath = langpath
|
self.langpath = langpath
|
||||||
self.http_accept_language = http_accept_language
|
self.http_accept_language = http_accept_language
|
||||||
self.is_writable = not is_gae
|
|
||||||
# filled in self.force():
|
# filled in self.force():
|
||||||
#------------------------
|
#------------------------
|
||||||
# self.cache
|
# self.cache
|
||||||
@@ -473,25 +483,26 @@ class translator(object):
|
|||||||
self.otherTs = {}
|
self.otherTs = {}
|
||||||
self.filter = markmin
|
self.filter = markmin
|
||||||
self.ftag = 'markmin'
|
self.ftag = 'markmin'
|
||||||
|
|
||||||
self.ns = None
|
self.ns = None
|
||||||
|
|
||||||
def get_possible_languages_info(self, lang=None):
|
def get_possible_languages_info(self, lang=None):
|
||||||
"""
|
"""
|
||||||
return info for selected language or dictionary with all
|
Returns info for selected language or dictionary with all
|
||||||
possible languages info from APP/languages/*.py
|
possible languages info from `APP/languages/*.py`
|
||||||
args:
|
It Returns:
|
||||||
*lang* (str): language
|
|
||||||
returns:
|
- a tuple containing::
|
||||||
if *lang* is defined:
|
|
||||||
return tuple(langcode, langname, langfile_mtime,
|
langcode, langname, langfile_mtime,
|
||||||
pluraldict_fname, pluraldict_mtime,
|
pluraldict_fname, pluraldict_mtime,
|
||||||
prules_langcode, nplurals,
|
prules_langcode, nplurals,
|
||||||
get_plural_id, construct_plural_form)
|
get_plural_id, construct_plural_form
|
||||||
or None
|
|
||||||
|
or None
|
||||||
|
|
||||||
|
- if *lang* is NOT defined a dictionary with all possible
|
||||||
|
languages::
|
||||||
|
|
||||||
if *lang* is NOT defined:
|
|
||||||
returns dictionary with all possible languages:
|
|
||||||
{ langcode(from filename):
|
{ langcode(from filename):
|
||||||
( langcode, # language code from !langcode!
|
( langcode, # language code from !langcode!
|
||||||
langname,
|
langname,
|
||||||
@@ -504,6 +515,10 @@ class translator(object):
|
|||||||
get_plural_id, # get_plural_id() for current language
|
get_plural_id, # get_plural_id() for current language
|
||||||
construct_plural_form) # construct_plural_form() for current language
|
construct_plural_form) # construct_plural_form() for current language
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lang (str): language
|
||||||
|
|
||||||
"""
|
"""
|
||||||
info = read_possible_languages(self.langpath)
|
info = read_possible_languages(self.langpath)
|
||||||
if lang:
|
if lang:
|
||||||
@@ -511,19 +526,18 @@ class translator(object):
|
|||||||
return info
|
return info
|
||||||
|
|
||||||
def get_possible_languages(self):
|
def get_possible_languages(self):
|
||||||
""" get list of all possible languages for current applications """
|
""" Gets list of all possible languages for current application """
|
||||||
return list(set(self.current_languages +
|
return list(set(self.current_languages +
|
||||||
[lang for lang in read_possible_languages(self.langpath).iterkeys()
|
[lang for lang in read_possible_languages(self.langpath).iterkeys()
|
||||||
if lang != 'default']))
|
if lang != 'default']))
|
||||||
|
|
||||||
def set_current_languages(self, *languages):
|
def set_current_languages(self, *languages):
|
||||||
"""
|
"""
|
||||||
set current AKA "default" languages
|
Sets current AKA "default" languages
|
||||||
setting one of this languages makes force() function
|
Setting one of this languages makes the force() function to turn
|
||||||
turn translation off to use default language
|
translation off
|
||||||
"""
|
"""
|
||||||
if len(languages) == 1 and isinstance(
|
if len(languages) == 1 and isinstance(languages[0], (tuple, list)):
|
||||||
languages[0], (tuple, list)):
|
|
||||||
languages = languages[0]
|
languages = languages[0]
|
||||||
if not languages or languages[0] is None:
|
if not languages or languages[0] is None:
|
||||||
# set default language from default.py/DEFAULT_LANGUAGE
|
# set default language from default.py/DEFAULT_LANGUAGE
|
||||||
@@ -543,17 +557,19 @@ class translator(object):
|
|||||||
self.force(self.http_accept_language)
|
self.force(self.http_accept_language)
|
||||||
|
|
||||||
def plural(self, word, n):
|
def plural(self, word, n):
|
||||||
""" get plural form of word for number *n*
|
""" Gets plural form of word for number *n*
|
||||||
NOTE: *word" MUST be defined in current language
|
invoked from T()/T.M() in `%%{}` tag
|
||||||
(T.accepted_language)
|
|
||||||
|
|
||||||
invoked from T()/T.M() in %%{} tag
|
Args:
|
||||||
args:
|
word (str): word in singular
|
||||||
word (str): word in singular
|
n (numeric): number plural form created for
|
||||||
n (numeric): number plural form created for
|
|
||||||
|
Returns:
|
||||||
|
word (str): word in appropriate singular/plural form
|
||||||
|
|
||||||
|
Note:
|
||||||
|
"word" MUST be defined in current language (T.accepted_language)
|
||||||
|
|
||||||
returns:
|
|
||||||
(str): word in appropriate singular/plural form
|
|
||||||
"""
|
"""
|
||||||
if int(n) == 1:
|
if int(n) == 1:
|
||||||
return word
|
return word
|
||||||
@@ -574,7 +590,7 @@ class translator(object):
|
|||||||
form = self.construct_plural_form(word, id)
|
form = self.construct_plural_form(word, id)
|
||||||
forms[id - 1] = form
|
forms[id - 1] = form
|
||||||
self.plural_dict[word] = forms
|
self.plural_dict[word] = forms
|
||||||
if self.is_writable and self.plural_file:
|
if is_writable() and self.plural_file:
|
||||||
write_plural_dict(self.plural_file,
|
write_plural_dict(self.plural_file,
|
||||||
self.plural_dict)
|
self.plural_dict)
|
||||||
return form
|
return form
|
||||||
@@ -582,11 +598,10 @@ class translator(object):
|
|||||||
|
|
||||||
def force(self, *languages):
|
def force(self, *languages):
|
||||||
"""
|
"""
|
||||||
|
Selects language(s) for translation
|
||||||
select language(s) for translation
|
|
||||||
|
|
||||||
if a list of languages is passed as a parameter,
|
if a list of languages is passed as a parameter,
|
||||||
first language from this list that matches the ones
|
the first language from this list that matches the ones
|
||||||
from the possible_languages dictionary will be
|
from the possible_languages dictionary will be
|
||||||
selected
|
selected
|
||||||
|
|
||||||
@@ -742,7 +757,7 @@ class translator(object):
|
|||||||
def M(self, message, symbols={}, language=None,
|
def M(self, message, symbols={}, language=None,
|
||||||
lazy=None, filter=None, ftag=None, ns=None):
|
lazy=None, filter=None, ftag=None, ns=None):
|
||||||
"""
|
"""
|
||||||
get cached translated markmin-message with inserted parametes
|
Gets cached translated markmin-message with inserted parametes
|
||||||
if lazy==True lazyT object is returned
|
if lazy==True lazyT object is returned
|
||||||
"""
|
"""
|
||||||
if lazy is None:
|
if lazy is None:
|
||||||
@@ -760,16 +775,16 @@ class translator(object):
|
|||||||
|
|
||||||
def get_t(self, message, prefix=''):
|
def get_t(self, message, prefix=''):
|
||||||
"""
|
"""
|
||||||
user ## to add a comment into a translation string
|
Use ## to add a comment into a translation string
|
||||||
the comment can be useful do discriminate different possible
|
the comment can be useful do discriminate different possible
|
||||||
translations for the same string (for example different locations)
|
translations for the same string (for example different locations)::
|
||||||
|
|
||||||
T(' hello world ') -> ' hello world '
|
T(' hello world ') -> ' hello world '
|
||||||
T(' hello world ## token') -> ' hello world '
|
T(' hello world ## token') -> ' hello world '
|
||||||
T('hello ## world## token') -> 'hello ## world'
|
T('hello ## world## token') -> 'hello ## world'
|
||||||
|
|
||||||
the ## notation is ignored in multiline strings and strings that
|
the ## notation is ignored in multiline strings and strings that
|
||||||
start with ##. this is to allow markmin syntax to be translated
|
start with ##. This is needed to allow markmin syntax to be translated
|
||||||
"""
|
"""
|
||||||
if isinstance(message, unicode):
|
if isinstance(message, unicode):
|
||||||
message = message.encode('utf8')
|
message = message.encode('utf8')
|
||||||
@@ -786,32 +801,38 @@ class translator(object):
|
|||||||
# guess translation same as original
|
# guess translation same as original
|
||||||
self.t[key] = mt = self.default_t.get(key, message)
|
self.t[key] = mt = self.default_t.get(key, message)
|
||||||
# update language file for latter translation
|
# update language file for latter translation
|
||||||
if self.is_writable and self.language_file != self.default_language_file:
|
if is_writable() and \
|
||||||
|
self.language_file != self.default_language_file:
|
||||||
write_dict(self.language_file, self.t)
|
write_dict(self.language_file, self.t)
|
||||||
return regex_backslash.sub(
|
return regex_backslash.sub(
|
||||||
lambda m: m.group(1).translate(ttab_in), mt)
|
lambda m: m.group(1).translate(ttab_in), mt)
|
||||||
|
|
||||||
def params_substitution(self, message, symbols):
|
def params_substitution(self, message, symbols):
|
||||||
"""
|
"""
|
||||||
substitute parameters from symbols into message using %.
|
Substitutes parameters from symbols into message using %.
|
||||||
also parse %%{} placeholders for plural-forms processing.
|
also parse `%%{}` placeholders for plural-forms processing.
|
||||||
returns: string with parameters
|
|
||||||
NOTE: *symbols* MUST BE OR tuple OR dict of parameters!
|
Returns:
|
||||||
|
string with parameters
|
||||||
|
|
||||||
|
Note:
|
||||||
|
*symbols* MUST BE OR tuple OR dict of parameters!
|
||||||
"""
|
"""
|
||||||
def sub_plural(m):
|
def sub_plural(m):
|
||||||
"""string in %{} is transformed by this rules:
|
"""String in `%{}` is transformed by this rules:
|
||||||
If string starts with \\, ! or ? such transformations
|
If string starts with `\\`, `!` or `?` such transformations
|
||||||
take place:
|
take place::
|
||||||
|
|
||||||
|
"!string of words" -> "String of word" (Capitalize)
|
||||||
|
"!!string of words" -> "String Of Word" (Title)
|
||||||
|
"!!!string of words" -> "STRING OF WORD" (Upper)
|
||||||
|
"\\!string of words" -> "!string of word"
|
||||||
|
(remove \\ and disable transformations)
|
||||||
|
"?word?number" -> "word" (return word, if number == 1)
|
||||||
|
"?number" or "??number" -> "" (remove number,
|
||||||
|
if number == 1)
|
||||||
|
"?word?number" -> "number" (if number != 1)
|
||||||
|
|
||||||
"!string of words" -> "String of word" (Capitalize)
|
|
||||||
"!!string of words" -> "String Of Word" (Title)
|
|
||||||
"!!!string of words" -> "STRING OF WORD" (Upper)
|
|
||||||
"\\!string of words" -> "!string of word"
|
|
||||||
(remove \\ and disable transformations)
|
|
||||||
"?word?number" -> "word" (return word, if number == 1)
|
|
||||||
"?number" or "??number" -> "" (remove number,
|
|
||||||
if number == 1)
|
|
||||||
"?word?number" -> "number" (if number != 1)
|
|
||||||
"""
|
"""
|
||||||
def sub_tuple(m):
|
def sub_tuple(m):
|
||||||
""" word[number], !word[number], !!word[number], !!!word[number]
|
""" word[number], !word[number], !!word[number], !!!word[number]
|
||||||
@@ -894,7 +915,7 @@ class translator(object):
|
|||||||
|
|
||||||
def translate(self, message, symbols):
|
def translate(self, message, symbols):
|
||||||
"""
|
"""
|
||||||
get cached translated message with inserted parameters(symbols)
|
Gets cached translated message with inserted parameters(symbols)
|
||||||
"""
|
"""
|
||||||
message = get_from_cache(self.cache, message,
|
message = get_from_cache(self.cache, message,
|
||||||
lambda: self.get_t(message))
|
lambda: self.get_t(message))
|
||||||
@@ -917,7 +938,8 @@ class translator(object):
|
|||||||
|
|
||||||
def findT(path, language=DEFAULT_LANGUAGE):
|
def findT(path, language=DEFAULT_LANGUAGE):
|
||||||
"""
|
"""
|
||||||
must be run by the admin app
|
Note:
|
||||||
|
Must be run by the admin app
|
||||||
"""
|
"""
|
||||||
lang_file = pjoin(path, 'languages', language + '.py')
|
lang_file = pjoin(path, 'languages', language + '.py')
|
||||||
sentences = read_dict(lang_file)
|
sentences = read_dict(lang_file)
|
||||||
@@ -954,6 +976,10 @@ def findT(path, language=DEFAULT_LANGUAGE):
|
|||||||
write_dict(lang_file, sentences)
|
write_dict(lang_file, sentences)
|
||||||
|
|
||||||
def update_all_languages(application_path):
|
def update_all_languages(application_path):
|
||||||
|
"""
|
||||||
|
Note:
|
||||||
|
Must be run by the admin app
|
||||||
|
"""
|
||||||
path = pjoin(application_path, 'languages/')
|
path = pjoin(application_path, 'languages/')
|
||||||
for language in oslistdir(path):
|
for language in oslistdir(path):
|
||||||
if regex_langfile.match(language):
|
if regex_langfile.match(language):
|
||||||
|
|||||||
+19
-23
@@ -2,14 +2,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This file is part of the web2py Web Framework
|
| This file is part of the web2py Web Framework
|
||||||
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||||
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||||
|
|
||||||
Contains:
|
|
||||||
|
|
||||||
- wsgibase: the gluon wsgi application
|
|
||||||
|
|
||||||
|
The gluon wsgi application
|
||||||
|
---------------------------
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if False: import import_all # DO NOT REMOVE PART OF FREEZE PROCESS
|
if False: import import_all # DO NOT REMOVE PART OF FREEZE PROCESS
|
||||||
@@ -135,9 +133,9 @@ HTTPS_SCHEMES = set(('https', 'HTTPS'))
|
|||||||
|
|
||||||
def get_client(env):
|
def get_client(env):
|
||||||
"""
|
"""
|
||||||
guess the client address from the environment variables
|
Guesses the client address from the environment variables
|
||||||
|
|
||||||
first tries 'http_x_forwarded_for', secondly 'remote_addr'
|
First tries 'http_x_forwarded_for', secondly 'remote_addr'
|
||||||
if all fails, assume '127.0.0.1' or '::1' (running locally)
|
if all fails, assume '127.0.0.1' or '::1' (running locally)
|
||||||
"""
|
"""
|
||||||
eget = env.get
|
eget = env.get
|
||||||
@@ -160,7 +158,7 @@ def get_client(env):
|
|||||||
|
|
||||||
def serve_controller(request, response, session):
|
def serve_controller(request, response, session):
|
||||||
"""
|
"""
|
||||||
this function is used to generate a dynamic page.
|
This function is used to generate a dynamic page.
|
||||||
It first runs all models, then runs the function in the controller,
|
It first runs all models, then runs the function in the controller,
|
||||||
and then tries to render the output using a view/template.
|
and then tries to render the output using a view/template.
|
||||||
this function must run from the [application] folder.
|
this function must run from the [application] folder.
|
||||||
@@ -234,7 +232,7 @@ class LazyWSGI(object):
|
|||||||
return self._environ
|
return self._environ
|
||||||
def start_response(self,status='200', headers=[], exec_info=None):
|
def start_response(self,status='200', headers=[], exec_info=None):
|
||||||
"""
|
"""
|
||||||
in controller you can use::
|
in controller you can use:
|
||||||
|
|
||||||
- request.wsgi.environ
|
- request.wsgi.environ
|
||||||
- request.wsgi.start_response
|
- request.wsgi.start_response
|
||||||
@@ -249,7 +247,7 @@ class LazyWSGI(object):
|
|||||||
"""
|
"""
|
||||||
In you controller use::
|
In you controller use::
|
||||||
|
|
||||||
@request.wsgi.middleware(middleware1, middleware2, ...)
|
@request.wsgi.middleware(middleware1, middleware2, ...)
|
||||||
|
|
||||||
to decorate actions with WSGI middleware. actions must return strings.
|
to decorate actions with WSGI middleware. actions must return strings.
|
||||||
uses a simulated environment so it may have weird behavior in some cases
|
uses a simulated environment so it may have weird behavior in some cases
|
||||||
@@ -271,9 +269,9 @@ class LazyWSGI(object):
|
|||||||
|
|
||||||
def wsgibase(environ, responder):
|
def wsgibase(environ, responder):
|
||||||
"""
|
"""
|
||||||
this is the gluon wsgi application. the first function called when a page
|
The gluon wsgi application. The first function called when a page
|
||||||
is requested (static or dynamic). it can be called by paste.httpserver
|
is requested (static or dynamic). It can be called by paste.httpserver
|
||||||
or by apache mod_wsgi.
|
or by apache mod_wsgi (or any WSGI-compatible server).
|
||||||
|
|
||||||
- fills request with info
|
- fills request with info
|
||||||
- the environment variables, replacing '.' with '_'
|
- the environment variables, replacing '.' with '_'
|
||||||
@@ -290,13 +288,11 @@ def wsgibase(environ, responder):
|
|||||||
2. for dynamic pages:
|
2. for dynamic pages:
|
||||||
|
|
||||||
- /<application>[/<controller>[/<function>[/<sub>]]][.<extension>]
|
- /<application>[/<controller>[/<function>[/<sub>]]][.<extension>]
|
||||||
- (sub may go several levels deep, currently 3 levels are supported:
|
|
||||||
sub1/sub2/sub3)
|
|
||||||
|
|
||||||
The naming conventions are:
|
The naming conventions are:
|
||||||
|
|
||||||
- application, controller, function and extension may only contain
|
- application, controller, function and extension may only contain
|
||||||
[a-zA-Z0-9_]
|
`[a-zA-Z0-9_]`
|
||||||
- file and sub may also contain '-', '=', '.' and '/'
|
- file and sub may also contain '-', '=', '.' and '/'
|
||||||
"""
|
"""
|
||||||
eget = environ.get
|
eget = environ.get
|
||||||
@@ -567,7 +563,7 @@ def wsgibase(environ, responder):
|
|||||||
|
|
||||||
def save_password(password, port):
|
def save_password(password, port):
|
||||||
"""
|
"""
|
||||||
used by main() to save the password in the parameters_port.py file.
|
Used by main() to save the password in the parameters_port.py file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
password_file = abspath('parameters_%i.py' % port)
|
password_file = abspath('parameters_%i.py' % port)
|
||||||
@@ -607,10 +603,10 @@ def appfactory(wsgiapp=wsgibase,
|
|||||||
generates a wsgi application that does logging and profiling and calls
|
generates a wsgi application that does logging and profiling and calls
|
||||||
wsgibase
|
wsgibase
|
||||||
|
|
||||||
.. function:: gluon.main.appfactory(
|
Args:
|
||||||
[wsgiapp=wsgibase
|
wsgiapp: the base application
|
||||||
[, logfilename='httpserver.log'
|
logfilename: where to store apache-compatible requests log
|
||||||
[, profilerfilename='profiler.log']]])
|
profiler_dir: where to store profile files
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if profilerfilename is not None:
|
if profilerfilename is not None:
|
||||||
|
|||||||
+6
-3
@@ -2,9 +2,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This file is part of the web2py Web Framework
|
| This file is part of the web2py Web Framework
|
||||||
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||||
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||||
|
|
||||||
|
Useful regexes
|
||||||
|
---------------
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|||||||
+10
-7
@@ -2,8 +2,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Created by Attila Csipa <web2py@csipa.in.rs>
|
| This file is part of the web2py Web Framework
|
||||||
Modified by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
| Created by Attila Csipa <web2py@csipa.in.rs>
|
||||||
|
| Modified by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||||
|
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||||
|
|
||||||
|
Cron-style interface
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
@@ -27,7 +31,7 @@ _cron_subprocs = []
|
|||||||
|
|
||||||
def absolute_path_link(path):
|
def absolute_path_link(path):
|
||||||
"""
|
"""
|
||||||
Return an absolute path for the destination of a symlink
|
Returns an absolute path for the destination of a symlink
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if os.path.islink(path):
|
if os.path.islink(path):
|
||||||
@@ -40,7 +44,7 @@ def absolute_path_link(path):
|
|||||||
|
|
||||||
|
|
||||||
def stopcron():
|
def stopcron():
|
||||||
"graceful shutdown of cron"
|
"Graceful shutdown of cron"
|
||||||
global _cron_stopping
|
global _cron_stopping
|
||||||
_cron_stopping = True
|
_cron_stopping = True
|
||||||
while _cron_subprocs:
|
while _cron_subprocs:
|
||||||
@@ -107,7 +111,7 @@ class Token(object):
|
|||||||
|
|
||||||
def acquire(self, startup=False):
|
def acquire(self, startup=False):
|
||||||
"""
|
"""
|
||||||
returns the time when the lock is acquired or
|
Returns the time when the lock is acquired or
|
||||||
None if cron already running
|
None if cron already running
|
||||||
|
|
||||||
lock is implemented by writing a pickle (start, stop) in cron.master
|
lock is implemented by writing a pickle (start, stop) in cron.master
|
||||||
@@ -150,8 +154,7 @@ class Token(object):
|
|||||||
|
|
||||||
def release(self):
|
def release(self):
|
||||||
"""
|
"""
|
||||||
this function writes into cron.master the time when cron job
|
Writes into cron.master the time when cron job was completed
|
||||||
was completed
|
|
||||||
"""
|
"""
|
||||||
if not self.master.closed:
|
if not self.master.closed:
|
||||||
portalocker.lock(self.master, portalocker.LOCK_EX)
|
portalocker.lock(self.master, portalocker.LOCK_EX)
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# portalocker.py
|
|
||||||
# Cross-platform (posix/nt) API for flock-style file locking.
|
|
||||||
# Requires python 1.5.2 or better.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Cross-platform (posix/nt) API for flock-style file locking.
|
Cross-platform (posix/nt) API for flock-style file locking.
|
||||||
|
|
||||||
Synopsis:
|
Synopsis::
|
||||||
|
|
||||||
import portalocker
|
import portalocker
|
||||||
file = open(\"somefile\", \"r+\")
|
file = open(\"somefile\", \"r+\")
|
||||||
@@ -16,18 +13,18 @@ Synopsis:
|
|||||||
file.write(\"foo\")
|
file.write(\"foo\")
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
If you know what you're doing, you may choose to
|
If you know what you're doing, you may choose to::
|
||||||
|
|
||||||
portalocker.unlock(file)
|
portalocker.unlock(file)
|
||||||
|
|
||||||
before closing the file, but why?
|
before closing the file, but why?
|
||||||
|
|
||||||
Methods:
|
Methods::
|
||||||
|
|
||||||
lock( file, flags )
|
lock( file, flags )
|
||||||
unlock( file )
|
unlock( file )
|
||||||
|
|
||||||
Constants:
|
Constants::
|
||||||
|
|
||||||
LOCK_EX
|
LOCK_EX
|
||||||
LOCK_SH
|
LOCK_SH
|
||||||
@@ -163,6 +160,7 @@ def write_locked(filename, data):
|
|||||||
fp.close()
|
fp.close()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
import sys
|
||||||
f = LockedFile('test.txt', mode='wb')
|
f = LockedFile('test.txt', mode='wb')
|
||||||
f.write('test ok')
|
f.write('test ok')
|
||||||
f.close()
|
f.close()
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ __author__ = "Thadeus Burgess <thadeusb@thadeusb.com>"
|
|||||||
# These are keywords that are common to all SQL dialects, and should
|
# These are keywords that are common to all SQL dialects, and should
|
||||||
# never be used as a table or column. Even if you use one of these
|
# never be used as a table or column. Even if you use one of these
|
||||||
# the cursor will throw an OperationalError for the SQL syntax.
|
# the cursor will throw an OperationalError for the SQL syntax.
|
||||||
|
|
||||||
COMMON = set((
|
COMMON = set((
|
||||||
'SELECT',
|
'SELECT',
|
||||||
'INSERT',
|
'INSERT',
|
||||||
|
|||||||
+17
-14
@@ -2,9 +2,12 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This file is part of the web2py Web Framework
|
| This file is part of the web2py Web Framework
|
||||||
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||||
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||||
|
|
||||||
|
Restricted environment to execute application's code
|
||||||
|
-----------------------------------------------------
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
@@ -26,7 +29,7 @@ __all__ = ['RestrictedError', 'restricted', 'TicketStorage', 'compile2']
|
|||||||
class TicketStorage(Storage):
|
class TicketStorage(Storage):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
defines the ticket object and the default values of its members (None)
|
Defines the ticket object and the default values of its members (None)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -40,7 +43,7 @@ class TicketStorage(Storage):
|
|||||||
|
|
||||||
def store(self, request, ticket_id, ticket_data):
|
def store(self, request, ticket_id, ticket_data):
|
||||||
"""
|
"""
|
||||||
stores the ticket. It will figure out if this must be on disk or in db
|
Stores the ticket. It will figure out if this must be on disk or in db
|
||||||
"""
|
"""
|
||||||
if self.db:
|
if self.db:
|
||||||
self._store_in_db(request, ticket_id, ticket_data)
|
self._store_in_db(request, ticket_id, ticket_data)
|
||||||
@@ -51,12 +54,12 @@ class TicketStorage(Storage):
|
|||||||
self.db._adapter.reconnect()
|
self.db._adapter.reconnect()
|
||||||
try:
|
try:
|
||||||
table = self._get_table(self.db, self.tablename, request.application)
|
table = self._get_table(self.db, self.tablename, request.application)
|
||||||
id = table.insert(ticket_id=ticket_id,
|
table.insert(ticket_id=ticket_id,
|
||||||
ticket_data=cPickle.dumps(ticket_data),
|
ticket_data=cPickle.dumps(ticket_data),
|
||||||
created_datetime=request.now)
|
created_datetime=request.now)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
message = 'In FILE: %(layer)s\n\n%(traceback)s\n'
|
message = 'In FILE: %(layer)s\n\n%(traceback)s\n'
|
||||||
except Exception, e:
|
except Exception:
|
||||||
self.db.rollback()
|
self.db.rollback()
|
||||||
message =' Unable to store in FILE: %(layer)s\n\n%(traceback)s\n'
|
message =' Unable to store in FILE: %(layer)s\n\n%(traceback)s\n'
|
||||||
self.db.close()
|
self.db.close()
|
||||||
@@ -111,8 +114,8 @@ class TicketStorage(Storage):
|
|||||||
|
|
||||||
class RestrictedError(Exception):
|
class RestrictedError(Exception):
|
||||||
"""
|
"""
|
||||||
class used to wrap an exception that occurs in the restricted environment
|
Class used to wrap an exception that occurs in the restricted environment
|
||||||
below. the traceback is used to log the exception and generate a ticket.
|
below. The traceback is used to log the exception and generate a ticket.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -123,7 +126,7 @@ class RestrictedError(Exception):
|
|||||||
environment=None,
|
environment=None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
layer here is some description of where in the system the exception
|
Layer here is some description of where in the system the exception
|
||||||
occurred.
|
occurred.
|
||||||
"""
|
"""
|
||||||
if environment is None:
|
if environment is None:
|
||||||
@@ -148,7 +151,7 @@ class RestrictedError(Exception):
|
|||||||
|
|
||||||
def log(self, request):
|
def log(self, request):
|
||||||
"""
|
"""
|
||||||
logs the exception.
|
Logs the exception.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -168,7 +171,7 @@ class RestrictedError(Exception):
|
|||||||
|
|
||||||
def load(self, request, app, ticket_id):
|
def load(self, request, app, ticket_id):
|
||||||
"""
|
"""
|
||||||
loads a logged exception.
|
Loads a logged exception.
|
||||||
"""
|
"""
|
||||||
ticket_storage = TicketStorage(db=request.tickets_db)
|
ticket_storage = TicketStorage(db=request.tickets_db)
|
||||||
d = ticket_storage.load(request, app, ticket_id)
|
d = ticket_storage.load(request, app, ticket_id)
|
||||||
@@ -201,8 +204,8 @@ def compile2(code, layer):
|
|||||||
|
|
||||||
def restricted(code, environment=None, layer='Unknown'):
|
def restricted(code, 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
|
||||||
passed to RestrictedError to identify where the error occurred.
|
passed to RestrictedError to identify where the error occurred.
|
||||||
"""
|
"""
|
||||||
if environment is None:
|
if environment is None:
|
||||||
|
|||||||
+53
-54
@@ -2,9 +2,9 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This file is part of the web2py Web Framework
|
| This file is part of the web2py Web Framework
|
||||||
Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
|
||||||
License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
|
||||||
|
|
||||||
gluon.rewrite parses incoming URLs and formats outgoing URLs for gluon.html.URL.
|
gluon.rewrite parses incoming URLs and formats outgoing URLs for gluon.html.URL.
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ regex_args = re.compile('[^\w/.@=-]')
|
|||||||
|
|
||||||
|
|
||||||
def _router_default():
|
def _router_default():
|
||||||
"return new copy of default base router"
|
"Returns new copy of default base router"
|
||||||
router = Storage(
|
router = Storage(
|
||||||
default_application='init',
|
default_application='init',
|
||||||
applications='ALL',
|
applications='ALL',
|
||||||
@@ -85,7 +85,7 @@ def _router_default():
|
|||||||
|
|
||||||
|
|
||||||
def _params_default(app=None):
|
def _params_default(app=None):
|
||||||
"return new copy of default parameters"
|
"Returns a new copy of default parameters"
|
||||||
p = Storage()
|
p = Storage()
|
||||||
p.name = app or "BASE"
|
p.name = app or "BASE"
|
||||||
p.default_application = app or "init"
|
p.default_application = app or "init"
|
||||||
@@ -181,7 +181,7 @@ def fixup_missing_path_info(environ):
|
|||||||
|
|
||||||
|
|
||||||
def url_in(request, environ):
|
def url_in(request, environ):
|
||||||
"parse and rewrite incoming URL"
|
"Parses and rewrites incoming URL"
|
||||||
if routers:
|
if routers:
|
||||||
return map_url_in(request, environ)
|
return map_url_in(request, environ)
|
||||||
return regex_url_in(request, environ)
|
return regex_url_in(request, environ)
|
||||||
@@ -189,7 +189,7 @@ def url_in(request, environ):
|
|||||||
|
|
||||||
def url_out(request, environ, application, controller, function,
|
def url_out(request, environ, application, controller, function,
|
||||||
args, other, scheme, host, port, language=None):
|
args, other, scheme, host, port, language=None):
|
||||||
"assemble and rewrite outgoing URL"
|
"Assembles and rewrites outgoing URL"
|
||||||
if routers:
|
if routers:
|
||||||
acf = map_url_out(request, environ, application, controller,
|
acf = map_url_out(request, environ, application, controller,
|
||||||
function, args, other, scheme, host, port, language)
|
function, args, other, scheme, host, port, language)
|
||||||
@@ -214,7 +214,7 @@ def url_out(request, environ, application, controller, function,
|
|||||||
|
|
||||||
def try_rewrite_on_error(http_response, request, environ, ticket=None):
|
def try_rewrite_on_error(http_response, request, environ, ticket=None):
|
||||||
"""
|
"""
|
||||||
called from main.wsgibase to rewrite the http response.
|
Called from main.wsgibase to rewrite the http response.
|
||||||
"""
|
"""
|
||||||
status = int(str(http_response.status).split()[0])
|
status = int(str(http_response.status).split()[0])
|
||||||
if status >= 399 and THREAD_LOCAL.routes.routes_onerror:
|
if status >= 399 and THREAD_LOCAL.routes.routes_onerror:
|
||||||
@@ -255,7 +255,7 @@ def try_rewrite_on_error(http_response, request, environ, ticket=None):
|
|||||||
|
|
||||||
|
|
||||||
def try_redirect_on_error(http_object, request, ticket=None):
|
def try_redirect_on_error(http_object, request, ticket=None):
|
||||||
"called from main.wsgibase to rewrite the http response"
|
"Called from main.wsgibase to rewrite the http response"
|
||||||
status = int(str(http_object.status).split()[0])
|
status = int(str(http_object.status).split()[0])
|
||||||
if status > 399 and THREAD_LOCAL.routes.routes_onerror:
|
if status > 399 and THREAD_LOCAL.routes.routes_onerror:
|
||||||
keys = set(('%s/%s' % (request.application, status),
|
keys = set(('%s/%s' % (request.application, status),
|
||||||
@@ -392,7 +392,7 @@ def load(routes='routes.py', app=None, data=None, rdict=None):
|
|||||||
def compile_regex(k, v, env=None):
|
def compile_regex(k, v, env=None):
|
||||||
"""
|
"""
|
||||||
Preprocess and compile the regular expressions in routes_app/in/out
|
Preprocess and compile the regular expressions in routes_app/in/out
|
||||||
The resulting regex will match a pattern of the form:
|
The resulting regex will match a pattern of the form::
|
||||||
|
|
||||||
[remote address]:[protocol]://[host]:[method] [path]
|
[remote address]:[protocol]://[host]:[method] [path]
|
||||||
|
|
||||||
@@ -427,7 +427,7 @@ def compile_regex(k, v, env=None):
|
|||||||
|
|
||||||
|
|
||||||
def load_routers(all_apps):
|
def load_routers(all_apps):
|
||||||
"load-time post-processing of routers"
|
"Load-time post-processing of routers"
|
||||||
|
|
||||||
for app in routers:
|
for app in routers:
|
||||||
# initialize apps with routers that aren't present,
|
# initialize apps with routers that aren't present,
|
||||||
@@ -533,7 +533,7 @@ def load_routers(all_apps):
|
|||||||
|
|
||||||
|
|
||||||
def regex_uri(e, regexes, tag, default=None):
|
def regex_uri(e, regexes, tag, default=None):
|
||||||
"filter incoming URI against a list of regexes"
|
"Filters incoming URI against a list of regexes"
|
||||||
path = e['PATH_INFO']
|
path = e['PATH_INFO']
|
||||||
host = e.get('HTTP_HOST', e.get('SERVER_NAME', 'localhost')).lower()
|
host = e.get('HTTP_HOST', e.get('SERVER_NAME', 'localhost')).lower()
|
||||||
i = host.find(':')
|
i = host.find(':')
|
||||||
@@ -555,7 +555,7 @@ def regex_uri(e, regexes, tag, default=None):
|
|||||||
|
|
||||||
def regex_select(env=None, app=None, request=None):
|
def regex_select(env=None, app=None, request=None):
|
||||||
"""
|
"""
|
||||||
select a set of regex rewrite params for the current request
|
Selects a set of regex rewrite params for the current request
|
||||||
"""
|
"""
|
||||||
if app:
|
if app:
|
||||||
THREAD_LOCAL.routes = params_apps.get(app, params)
|
THREAD_LOCAL.routes = params_apps.get(app, params)
|
||||||
@@ -572,7 +572,7 @@ def regex_select(env=None, app=None, request=None):
|
|||||||
|
|
||||||
|
|
||||||
def regex_filter_in(e):
|
def regex_filter_in(e):
|
||||||
"regex rewrite incoming URL"
|
"Regex rewrite incoming URL"
|
||||||
routes = THREAD_LOCAL.routes
|
routes = THREAD_LOCAL.routes
|
||||||
query = e.get('QUERY_STRING', None)
|
query = e.get('QUERY_STRING', None)
|
||||||
e['WEB2PY_ORIGINAL_URI'] = e['PATH_INFO'] + (query and ('?' + query) or '')
|
e['WEB2PY_ORIGINAL_URI'] = e['PATH_INFO'] + (query and ('?' + query) or '')
|
||||||
@@ -603,7 +603,7 @@ def invalid_url(routes):
|
|||||||
web2py_error='invalid path')
|
web2py_error='invalid path')
|
||||||
|
|
||||||
def regex_url_in(request, environ):
|
def regex_url_in(request, environ):
|
||||||
"rewrite and parse incoming URL"
|
"Rewrites and parses incoming URL"
|
||||||
|
|
||||||
# ##################################################
|
# ##################################################
|
||||||
# select application
|
# select application
|
||||||
@@ -667,7 +667,7 @@ def regex_url_in(request, environ):
|
|||||||
|
|
||||||
|
|
||||||
def regex_filter_out(url, e=None):
|
def regex_filter_out(url, e=None):
|
||||||
"regex rewrite outgoing URL"
|
"Regex rewrite outgoing URL"
|
||||||
if not hasattr(THREAD_LOCAL, 'routes'):
|
if not hasattr(THREAD_LOCAL, 'routes'):
|
||||||
regex_select() # ensure routes is set (for application threads)
|
regex_select() # ensure routes is set (for application threads)
|
||||||
routes = THREAD_LOCAL.routes
|
routes = THREAD_LOCAL.routes
|
||||||
@@ -810,10 +810,10 @@ def filter_err(status, application='app', ticket='tkt'):
|
|||||||
|
|
||||||
|
|
||||||
class MapUrlIn(object):
|
class MapUrlIn(object):
|
||||||
"logic for mapping incoming URLs"
|
"Logic for mapping incoming URLs"
|
||||||
|
|
||||||
def __init__(self, request=None, env=None):
|
def __init__(self, request=None, env=None):
|
||||||
"initialize a map-in object"
|
"Initializes a map-in object"
|
||||||
self.request = request
|
self.request = request
|
||||||
self.env = env
|
self.env = env
|
||||||
|
|
||||||
@@ -861,7 +861,7 @@ class MapUrlIn(object):
|
|||||||
self.port = '443' if self.scheme == 'https' else '80'
|
self.port = '443' if self.scheme == 'https' else '80'
|
||||||
|
|
||||||
def map_prefix(self):
|
def map_prefix(self):
|
||||||
"strip path prefix, if present in its entirety"
|
"Strips path prefix, if present in its entirety"
|
||||||
prefix = routers.BASE.path_prefix
|
prefix = routers.BASE.path_prefix
|
||||||
if prefix:
|
if prefix:
|
||||||
prefixlen = len(prefix)
|
prefixlen = len(prefix)
|
||||||
@@ -873,7 +873,7 @@ class MapUrlIn(object):
|
|||||||
self.args = List(self.args[prefixlen:]) # strip the prefix
|
self.args = List(self.args[prefixlen:]) # strip the prefix
|
||||||
|
|
||||||
def map_app(self):
|
def map_app(self):
|
||||||
"determine application name"
|
"Determines application name"
|
||||||
base = routers.BASE # base router
|
base = routers.BASE # base router
|
||||||
self.domain_application = None
|
self.domain_application = None
|
||||||
self.domain_controller = None
|
self.domain_controller = None
|
||||||
@@ -935,12 +935,12 @@ class MapUrlIn(object):
|
|||||||
self._args_match = self.router._args_match
|
self._args_match = self.router._args_match
|
||||||
|
|
||||||
def map_root_static(self):
|
def map_root_static(self):
|
||||||
'''
|
"""
|
||||||
handle root-static files (no hyphen mapping)
|
Handles root-static files (no hyphen mapping)
|
||||||
|
|
||||||
a root-static file is one whose incoming URL expects it to be at the root,
|
a root-static file is one whose incoming URL expects it to be at the root,
|
||||||
typically robots.txt & favicon.ico
|
typically robots.txt & favicon.ico
|
||||||
'''
|
"""
|
||||||
|
|
||||||
if len(self.args) == 1 and self.arg0 in self.router.root_static:
|
if len(self.args) == 1 and self.arg0 in self.router.root_static:
|
||||||
self.controller = self.request.controller = 'static'
|
self.controller = self.request.controller = 'static'
|
||||||
@@ -952,7 +952,7 @@ class MapUrlIn(object):
|
|||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
def map_language(self):
|
def map_language(self):
|
||||||
"handle language (no hyphen mapping)"
|
"Handles language (no hyphen mapping)"
|
||||||
arg0 = self.arg0 # no hyphen mapping
|
arg0 = self.arg0 # no hyphen mapping
|
||||||
if arg0 and self.languages and arg0 in self.languages:
|
if arg0 and self.languages and arg0 in self.languages:
|
||||||
self.language = arg0
|
self.language = arg0
|
||||||
@@ -964,7 +964,7 @@ class MapUrlIn(object):
|
|||||||
arg0 = self.arg0
|
arg0 = self.arg0
|
||||||
|
|
||||||
def map_controller(self):
|
def map_controller(self):
|
||||||
"identify controller"
|
"Identifies controller"
|
||||||
# handle controller
|
# handle controller
|
||||||
#
|
#
|
||||||
arg0 = self.harg0 # map hyphens
|
arg0 = self.harg0 # map hyphens
|
||||||
@@ -981,7 +981,7 @@ class MapUrlIn(object):
|
|||||||
|
|
||||||
def map_static(self):
|
def map_static(self):
|
||||||
'''
|
'''
|
||||||
handle static files
|
Handles static files
|
||||||
file_match but no hyphen mapping
|
file_match but no hyphen mapping
|
||||||
'''
|
'''
|
||||||
if self.controller != 'static':
|
if self.controller != 'static':
|
||||||
@@ -1025,7 +1025,7 @@ class MapUrlIn(object):
|
|||||||
return static_file, version
|
return static_file, version
|
||||||
|
|
||||||
def map_function(self):
|
def map_function(self):
|
||||||
"handle function.extension"
|
"Handles function.extension"
|
||||||
arg0 = self.harg0 # map hyphens
|
arg0 = self.harg0 # map hyphens
|
||||||
functions = self.functions.get(self.controller, set())
|
functions = self.functions.get(self.controller, set())
|
||||||
if isinstance(self.router.default_function, dict):
|
if isinstance(self.router.default_function, dict):
|
||||||
@@ -1058,9 +1058,9 @@ class MapUrlIn(object):
|
|||||||
web2py_error='invalid extension')
|
web2py_error='invalid extension')
|
||||||
|
|
||||||
def validate_args(self):
|
def validate_args(self):
|
||||||
'''
|
"""
|
||||||
check args against validation pattern
|
Checks args against validation pattern
|
||||||
'''
|
"""
|
||||||
for arg in self.args:
|
for arg in self.args:
|
||||||
if not self.router._args_match.match(arg):
|
if not self.router._args_match.match(arg):
|
||||||
raise HTTP(
|
raise HTTP(
|
||||||
@@ -1068,16 +1068,15 @@ class MapUrlIn(object):
|
|||||||
web2py_error='invalid arg <%s>' % arg)
|
web2py_error='invalid arg <%s>' % arg)
|
||||||
|
|
||||||
def sluggify(self):
|
def sluggify(self):
|
||||||
""
|
|
||||||
self.request.env.update(
|
self.request.env.update(
|
||||||
(k.lower().replace('.', '_'), v) for k, v in self.env.iteritems())
|
(k.lower().replace('.', '_'), v) for k, v in self.env.iteritems())
|
||||||
|
|
||||||
def update_request(self):
|
def update_request(self):
|
||||||
'''
|
"""
|
||||||
update request from self
|
Updates request from self
|
||||||
build env.request_uri
|
Builds env.request_uri
|
||||||
make lower-case versions of http headers in env
|
Makes lower-case versions of http headers in env
|
||||||
'''
|
"""
|
||||||
self.request.application = self.application
|
self.request.application = self.application
|
||||||
self.request.controller = self.controller
|
self.request.controller = self.controller
|
||||||
self.request.function = self.function
|
self.request.function = self.function
|
||||||
@@ -1105,24 +1104,24 @@ class MapUrlIn(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def arg0(self):
|
def arg0(self):
|
||||||
"return first arg"
|
"Returns first arg"
|
||||||
return self.args(0)
|
return self.args(0)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def harg0(self):
|
def harg0(self):
|
||||||
"return first arg with optional hyphen mapping"
|
"Returns first arg with optional hyphen mapping"
|
||||||
if self.map_hyphen and self.args(0):
|
if self.map_hyphen and self.args(0):
|
||||||
return self.args(0).replace('-', '_')
|
return self.args(0).replace('-', '_')
|
||||||
return self.args(0)
|
return self.args(0)
|
||||||
|
|
||||||
def pop_arg_if(self, dopop):
|
def pop_arg_if(self, dopop):
|
||||||
"conditionally remove first arg and return new first arg"
|
"Conditionally removes first arg and returns new first arg"
|
||||||
if dopop:
|
if dopop:
|
||||||
self.args.pop(0)
|
self.args.pop(0)
|
||||||
|
|
||||||
|
|
||||||
class MapUrlOut(object):
|
class MapUrlOut(object):
|
||||||
"logic for mapping outgoing URLs"
|
"Logic for mapping outgoing URLs"
|
||||||
|
|
||||||
def __init__(self, request, env, application, controller,
|
def __init__(self, request, env, application, controller,
|
||||||
function, args, other, scheme, host, port, language):
|
function, args, other, scheme, host, port, language):
|
||||||
@@ -1179,13 +1178,13 @@ class MapUrlOut(object):
|
|||||||
self.omit_function = False
|
self.omit_function = False
|
||||||
|
|
||||||
def omit_lang(self):
|
def omit_lang(self):
|
||||||
"omit language if possible"
|
"Omits language if possible"
|
||||||
|
|
||||||
if not self.language or self.language == self.default_language:
|
if not self.language or self.language == self.default_language:
|
||||||
self.omit_language = True
|
self.omit_language = True
|
||||||
|
|
||||||
def omit_acf(self):
|
def omit_acf(self):
|
||||||
"omit what we can of a/c/f"
|
"Omits what we can of a/c/f"
|
||||||
|
|
||||||
router = self.router
|
router = self.router
|
||||||
|
|
||||||
@@ -1254,7 +1253,7 @@ class MapUrlOut(object):
|
|||||||
self.omit_function = False
|
self.omit_function = False
|
||||||
|
|
||||||
def build_acf(self):
|
def build_acf(self):
|
||||||
"build acf from components"
|
"Builds a/c/f from components"
|
||||||
acf = ''
|
acf = ''
|
||||||
if self.map_hyphen:
|
if self.map_hyphen:
|
||||||
self.application = self.application.replace('_', '-')
|
self.application = self.application.replace('_', '-')
|
||||||
@@ -1280,7 +1279,7 @@ class MapUrlOut(object):
|
|||||||
return acf or '/'
|
return acf or '/'
|
||||||
|
|
||||||
def acf(self):
|
def acf(self):
|
||||||
"convert components to /app/lang/controller/function"
|
"Converts components to /app/lang/controller/function"
|
||||||
|
|
||||||
if not routers:
|
if not routers:
|
||||||
return None # use regex filter
|
return None # use regex filter
|
||||||
@@ -1290,7 +1289,7 @@ class MapUrlOut(object):
|
|||||||
|
|
||||||
|
|
||||||
def map_url_in(request, env, app=False):
|
def map_url_in(request, env, app=False):
|
||||||
"route incoming URL"
|
"Routes incoming URL"
|
||||||
|
|
||||||
# initialize router-url object
|
# initialize router-url object
|
||||||
#
|
#
|
||||||
@@ -1333,8 +1332,8 @@ def map_url_in(request, env, app=False):
|
|||||||
|
|
||||||
def map_url_out(request, env, application, controller,
|
def map_url_out(request, env, application, controller,
|
||||||
function, args, other, scheme, host, port, language=None):
|
function, args, other, scheme, host, port, language=None):
|
||||||
'''
|
"""
|
||||||
supply /a/c/f (or /a/lang/c/f) portion of outgoing url
|
Supply /a/c/f (or /a/lang/c/f) portion of outgoing url
|
||||||
|
|
||||||
The basic rule is that we can only make transformations
|
The basic rule is that we can only make transformations
|
||||||
that map_url_in can reverse.
|
that map_url_in can reverse.
|
||||||
@@ -1342,14 +1341,14 @@ def map_url_out(request, env, application, controller,
|
|||||||
Suppose that the incoming arguments are a,c,f,args,lang
|
Suppose that the incoming arguments are a,c,f,args,lang
|
||||||
and that the router defaults are da, dc, df, dl.
|
and that the router defaults are da, dc, df, dl.
|
||||||
|
|
||||||
We can perform these transformations trivially if args=[] and lang=None or dl:
|
We can perform these transformations trivially if args=[] and lang=None or dl::
|
||||||
|
|
||||||
/da/dc/df => /
|
/da/dc/df => /
|
||||||
/a/dc/df => /a
|
/a/dc/df => /a
|
||||||
/a/c/df => /a/c
|
/a/c/df => /a/c
|
||||||
|
|
||||||
We would also like to be able to strip the default application or application/controller
|
We would also like to be able to strip the default application or application/controller
|
||||||
from URLs with function/args present, thus:
|
from URLs with function/args present, thus::
|
||||||
|
|
||||||
/da/c/f/args => /c/f/args
|
/da/c/f/args => /c/f/args
|
||||||
/da/dc/f/args => /f/args
|
/da/dc/f/args => /f/args
|
||||||
@@ -1357,14 +1356,14 @@ def map_url_out(request, env, application, controller,
|
|||||||
We use [applications] and [controllers] and {functions} to suppress ambiguous omissions.
|
We use [applications] and [controllers] and {functions} to suppress ambiguous omissions.
|
||||||
|
|
||||||
We assume that language names do not collide with a/c/f names.
|
We assume that language names do not collide with a/c/f names.
|
||||||
'''
|
"""
|
||||||
map = MapUrlOut(request, env, application, controller,
|
map = MapUrlOut(request, env, application, controller,
|
||||||
function, args, other, scheme, host, port, language)
|
function, args, other, scheme, host, port, language)
|
||||||
return map.acf()
|
return map.acf()
|
||||||
|
|
||||||
|
|
||||||
def get_effective_router(appname):
|
def get_effective_router(appname):
|
||||||
"return a private copy of the effective router for the specified application"
|
"Returns a private copy of the effective router for the specified application"
|
||||||
if not routers or appname not in routers:
|
if not routers or appname not in routers:
|
||||||
return None
|
return None
|
||||||
return Storage(routers[appname]) # return a copy
|
return Storage(routers[appname]) # return a copy
|
||||||
|
|||||||
+7
-3
@@ -2599,8 +2599,11 @@ class SQLFORM(FORM):
|
|||||||
for k, v in sorted(exportManager.items()):
|
for k, v in sorted(exportManager.items()):
|
||||||
if not v:
|
if not v:
|
||||||
continue
|
continue
|
||||||
label = v[1] if hasattr(v, "__getitem__") else k
|
if hasattr(v, "__getitem__"):
|
||||||
title = v[2] if hasattr(v, "__getitem__") else label
|
label = v[1]
|
||||||
|
title = v[2] if len(v)>2 else label
|
||||||
|
else:
|
||||||
|
label = title = k
|
||||||
link = url2(vars=dict(
|
link = url2(vars=dict(
|
||||||
order=request.vars.order or '',
|
order=request.vars.order or '',
|
||||||
_export_type=k,
|
_export_type=k,
|
||||||
@@ -2926,7 +2929,8 @@ class SQLTABLE(TABLE):
|
|||||||
if not sqlrows:
|
if not sqlrows:
|
||||||
return
|
return
|
||||||
if not columns:
|
if not columns:
|
||||||
columns = ['.'.join(sqlrows.db._adapter.REGEX_TABLE_DOT_FIELD.match(c).groups()) for c in sqlrows.colnames]
|
REGEX_TABLE_DOT_FIELD = sqlrows.db._adapter.REGEX_TABLE_DOT_FIELD
|
||||||
|
columns = [c for c in sqlrows.colnames if REGEX_TABLE_DOT_FIELD.match(c)]
|
||||||
if headers == 'fieldname:capitalize':
|
if headers == 'fieldname:capitalize':
|
||||||
headers = {}
|
headers = {}
|
||||||
for c in columns:
|
for c in columns:
|
||||||
|
|||||||
+54
-21
@@ -278,7 +278,8 @@ class Mail(object):
|
|||||||
sender=None,
|
sender=None,
|
||||||
encoding='utf-8',
|
encoding='utf-8',
|
||||||
raw=False,
|
raw=False,
|
||||||
headers={}
|
headers={},
|
||||||
|
from_address=None
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Sends an email using data specified in constructor
|
Sends an email using data specified in constructor
|
||||||
@@ -308,8 +309,9 @@ class Mail(object):
|
|||||||
encoding: encoding of all strings passed to this method (including
|
encoding: encoding of all strings passed to this method (including
|
||||||
message bodies)
|
message bodies)
|
||||||
headers: dictionary of headers to refine the headers just before
|
headers: dictionary of headers to refine the headers just before
|
||||||
sending mail, e.g. {'Return-Path' : 'bounces@example.org'}
|
sending mail, e.g. {'X-Mailer' : 'web2py mailer'}
|
||||||
|
from_address: address to appear in the 'From:' header, this is not the
|
||||||
|
envelope sender. If not specified the sender will be used
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
#Send plain text message to single address:
|
#Send plain text message to single address:
|
||||||
@@ -655,7 +657,10 @@ class Mail(object):
|
|||||||
# no cryptography process as usual
|
# no cryptography process as usual
|
||||||
payload = payload_in
|
payload = payload_in
|
||||||
|
|
||||||
payload['From'] = encoded_or_raw(sender.decode(encoding))
|
if from_address:
|
||||||
|
payload['From'] = encoded_or_raw(from_address.decode(encoding))
|
||||||
|
else:
|
||||||
|
payload['From'] = encoded_or_raw(sender.decode(encoding))
|
||||||
origTo = to[:]
|
origTo = to[:]
|
||||||
if to:
|
if to:
|
||||||
payload['To'] = encoded_or_raw(', '.join(to).decode(encoding))
|
payload['To'] = encoded_or_raw(', '.join(to).decode(encoding))
|
||||||
@@ -752,7 +757,8 @@ class Recaptcha(DIV):
|
|||||||
error_message='invalid',
|
error_message='invalid',
|
||||||
label='Verify:',
|
label='Verify:',
|
||||||
options='',
|
options='',
|
||||||
comment = ''
|
comment = '',
|
||||||
|
ajax=False
|
||||||
):
|
):
|
||||||
self.request_vars = request and request.vars or current.request.vars
|
self.request_vars = request and request.vars or current.request.vars
|
||||||
self.remote_addr = request.env.remote_addr
|
self.remote_addr = request.env.remote_addr
|
||||||
@@ -767,6 +773,7 @@ class Recaptcha(DIV):
|
|||||||
self.label = label
|
self.label = label
|
||||||
self.options = options
|
self.options = options
|
||||||
self.comment = comment
|
self.comment = comment
|
||||||
|
self.ajax = ajax
|
||||||
|
|
||||||
def _validate(self):
|
def _validate(self):
|
||||||
|
|
||||||
@@ -820,18 +827,43 @@ class Recaptcha(DIV):
|
|||||||
server = self.API_SSL_SERVER
|
server = self.API_SSL_SERVER
|
||||||
else:
|
else:
|
||||||
server = self.API_SERVER
|
server = self.API_SERVER
|
||||||
captcha = DIV(
|
if not self.ajax:
|
||||||
SCRIPT("var RecaptchaOptions = {%s};" % self.options),
|
captcha = DIV(
|
||||||
SCRIPT(_type="text/javascript",
|
SCRIPT("var RecaptchaOptions = {%s};" % self.options),
|
||||||
_src="%s/challenge?k=%s%s" % (server, public_key, error_param)),
|
SCRIPT(_type="text/javascript",
|
||||||
TAG.noscript(
|
_src="%s/challenge?k=%s%s" % (server, public_key, error_param)),
|
||||||
IFRAME(
|
TAG.noscript(
|
||||||
_src="%s/noscript?k=%s%s" % (
|
IFRAME(
|
||||||
server, public_key, error_param),
|
_src="%s/noscript?k=%s%s" % (
|
||||||
_height="300", _width="500", _frameborder="0"), BR(),
|
server, public_key, error_param),
|
||||||
INPUT(
|
_height="300", _width="500", _frameborder="0"), BR(),
|
||||||
_type='hidden', _name='recaptcha_response_field',
|
INPUT(
|
||||||
_value='manual_challenge')), _id='recaptcha')
|
_type='hidden', _name='recaptcha_response_field',
|
||||||
|
_value='manual_challenge')), _id='recaptcha')
|
||||||
|
|
||||||
|
else: #use Google's ajax interface, needed for LOADed components
|
||||||
|
|
||||||
|
url_recaptcha_js = "%s/js/recaptcha_ajax.js" % server
|
||||||
|
RecaptchaOptions = "var RecaptchaOptions = {%s}" % self.options
|
||||||
|
script = """%(options)s;
|
||||||
|
jQuery.getScript('%(url)s',function() {
|
||||||
|
Recaptcha.create('%(public_key)s',
|
||||||
|
'recaptcha',jQuery.extend(RecaptchaOptions,{'callback':Recaptcha.focus_response_field}))
|
||||||
|
}) """ % ({'options':RecaptchaOptions,'url':url_recaptcha_js,'public_key':public_key})
|
||||||
|
captcha = DIV(
|
||||||
|
SCRIPT(
|
||||||
|
script,
|
||||||
|
_type="text/javascript",
|
||||||
|
),
|
||||||
|
TAG.noscript(
|
||||||
|
IFRAME(
|
||||||
|
_src="%s/noscript?k=%s%s" % (
|
||||||
|
server, public_key, error_param),
|
||||||
|
_height="300", _width="500", _frameborder="0"), BR(),
|
||||||
|
INPUT(
|
||||||
|
_type='hidden', _name='recaptcha_response_field',
|
||||||
|
_value='manual_challenge')), _id='recaptcha')
|
||||||
|
|
||||||
if not self.errors.captcha:
|
if not self.errors.captcha:
|
||||||
return XML(captcha).xml()
|
return XML(captcha).xml()
|
||||||
else:
|
else:
|
||||||
@@ -2030,8 +2062,9 @@ class Auth(object):
|
|||||||
if user and user.get(settings.passfield, False):
|
if user and user.get(settings.passfield, False):
|
||||||
password = settings.table_user[
|
password = settings.table_user[
|
||||||
settings.passfield].validate(password)[0]
|
settings.passfield].validate(password)[0]
|
||||||
if not user.registration_key.strip() and password == \
|
if ((user.registration_key is None or
|
||||||
user[settings.passfield]:
|
not user.registration_key.strip()) and
|
||||||
|
password == user[settings.passfield]):
|
||||||
self.login_user(user)
|
self.login_user(user)
|
||||||
return user
|
return user
|
||||||
else:
|
else:
|
||||||
@@ -2317,8 +2350,8 @@ class Auth(object):
|
|||||||
elif temp_user.registration_key in ('disabled', 'blocked'):
|
elif temp_user.registration_key in ('disabled', 'blocked'):
|
||||||
response.flash = self.messages.login_disabled
|
response.flash = self.messages.login_disabled
|
||||||
return form
|
return form
|
||||||
elif not temp_user.registration_key is None and \
|
elif (not temp_user.registration_key is None
|
||||||
temp_user.registration_key.strip():
|
and temp_user.registration_key.strip()):
|
||||||
response.flash = \
|
response.flash = \
|
||||||
self.messages.registration_verifying
|
self.messages.registration_verifying
|
||||||
return form
|
return form
|
||||||
|
|||||||
+2
-2
@@ -17,10 +17,10 @@ import cgi
|
|||||||
import urllib
|
import urllib
|
||||||
import struct
|
import struct
|
||||||
import decimal
|
import decimal
|
||||||
|
import unicodedata
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
from gluon.utils import simple_hash, web2py_uuid, DIGEST_ALG_BY_SIZE
|
from gluon.utils import simple_hash, web2py_uuid, DIGEST_ALG_BY_SIZE
|
||||||
from gluon.dal import FieldVirtual, FieldMethod
|
from gluon.dal import FieldVirtual, FieldMethod
|
||||||
from gluon.contrib import translitcodec
|
|
||||||
|
|
||||||
regex_isint = re.compile('^[+-]?\d+$')
|
regex_isint = re.compile('^[+-]?\d+$')
|
||||||
|
|
||||||
@@ -2519,7 +2519,7 @@ def urlify(s, maxlen=80, keep_underscores=False):
|
|||||||
if isinstance(s, str):
|
if isinstance(s, str):
|
||||||
s = s.decode('utf-8') # to unicode
|
s = s.decode('utf-8') # to unicode
|
||||||
s = s.lower() # to lowercase
|
s = s.lower() # to lowercase
|
||||||
s = s.encode('translit/long') # replace special characters
|
s = unicodedata.normalize('NFKD', s) # replace special characters
|
||||||
s = s.encode('ascii', 'ignore') # encode as ASCII
|
s = s.encode('ascii', 'ignore') # encode as ASCII
|
||||||
s = re.sub('&\w+?;', '', s) # strip html entities
|
s = re.sub('&\w+?;', '', s) # strip html entities
|
||||||
if keep_underscores:
|
if keep_underscores:
|
||||||
|
|||||||
+4
-4
@@ -1222,12 +1222,12 @@ end tell
|
|||||||
url = get_url(ip, proto=proto, port=port)
|
url = get_url(ip, proto=proto, port=port)
|
||||||
|
|
||||||
if not options.nobanner:
|
if not options.nobanner:
|
||||||
print 'please visit:'
|
message = '\nplease visit:\n\t%s\n' % url
|
||||||
print '\t', url
|
|
||||||
if sys.platform.startswith('win'):
|
if sys.platform.startswith('win'):
|
||||||
print 'use "taskkill /f /pid %i" to shutdown the web2py server' % os.getpid()
|
message += 'use "taskkill /f /pid %i" to shutdown the web2py server\n\n' % os.getpid()
|
||||||
else:
|
else:
|
||||||
print 'use "kill -SIGTERM %i" to shutdown the web2py server' % os.getpid()
|
message += 'use "kill -SIGTERM %i" to shutdown the web2py server\n\n' % os.getpid()
|
||||||
|
print message
|
||||||
|
|
||||||
# enhance linecache.getline (used by debugger) to look at the source file
|
# enhance linecache.getline (used by debugger) to look at the source file
|
||||||
# if the line was not found (under py2exe & when file was modified)
|
# if the line was not found (under py2exe & when file was modified)
|
||||||
|
|||||||
Reference in New Issue
Block a user