Compare commits

...

37 Commits

Author SHA1 Message Date
mdipierro
63224e8ce6 2.7.3 2013-10-11 18:10:57 -05:00
mdipierro
ff7f9568db fixed validation of nagtive integers, thanks Stefan 2013-10-11 18:06:57 -05:00
mdipierro
3635dd8faf fixed problem with Virtual Fields and grid 2013-10-11 17:59:30 -05:00
mdipierro
d5fda056ff simplified logic for number validators 2013-10-11 17:07:17 -05:00
mdipierro
d8e8d1d597 fixed problem with IS_INT_IN_RANGE for large numbers 2013-10-11 16:59:05 -05:00
mdipierro
59290534bc fixed issue 1708:gae memcache_contrib does not set the time_expire, thanks Nicholas 2013-10-09 11:58:15 -05:00
mdipierro
8fb0b71be6 fixed compilerapp sorting issue, better 2013-10-09 11:31:33 -05:00
mdipierro
ddc0fc9949 fixed compilerapp sorting issue, possibly 2013-10-09 11:15:07 -05:00
mdipierro
5428fdbd04 reverted error commit 2013-10-09 09:07:00 -05:00
Massimo
98f2bfbfb6 Merge branch 'master' of github.com:web2py/web2py 2013-10-08 11:39:30 -05:00
Massimo
d780d26cc9 merge heads 2013-10-08 11:38:28 -05:00
mdipierro
a5711bd933 Merge pull request #244 from timrichardson/issue/1692
fix for Issue 1692 virtual fields in SQLFORM.grid
2013-10-08 09:35:51 -07:00
mdipierro
b96cde2f77 Merge pull request #243 from cccaballero/master
more spanish translations
2013-10-08 09:34:16 -07:00
Tim Richardson
a3f3ed1298 fix for Issue 1692 virtual fields in forms 2013-10-08 13:31:36 +11:00
mdipierro
5f34193ac7 fixed demo mode 2013-10-07 09:17:51 -05:00
cccaballero
6fe6852a0c more spanish translations
more spanish translations
2013-10-07 09:49:48 -04:00
mdipierro
961d143f7d 2.7.2 2013-10-07 08:40:39 -05:00
mdipierro
0e98544a79 Merge pull request #242 from rhr/master
fix for using the shell with IPython >= 1.0
2013-10-06 19:37:56 -07:00
mdipierro
86d8b8dece Merge pull request #241 from spametki/master
IMAP fixed patch for google code issue 1707
2013-10-06 19:37:11 -07:00
Rick Ree
46e2a663e9 fix for using the shell with IPython >= 1.0 2013-10-06 17:18:04 -05:00
spametki
e7fbd0095f IMAP google code issue 1707: fixed patch 2013-10-06 14:39:23 -03:00
mdipierro
add6fa526e fixed regex status in http.py 2013-10-06 11:52:23 -05:00
mdipierro
47e77e9a9c Merge pull request #239 from abastardi/patch-1
Fixed problem with Rows.render
2013-10-06 08:15:09 -07:00
mdipierro
81036ac997 Merge pull request #237 from alfonsodg/master
Added gitignore restrictions and changes for admin.py
2013-10-06 08:13:58 -07:00
mdipierro
77df883566 Merge pull request #236 from niphlod/enhancement/anyserver_options
fixed gevent workers
2013-10-06 08:11:03 -07:00
mdipierro
bfc7e3b4e9 Merge pull request #238 from houdinihound/patch-1
Support for HTTP Status Code: 429 - Too Many Requests
2013-10-06 08:09:52 -07:00
spametki
e05fe15470 IMAP .insert support for custom date (Google Code issue 1707) 2013-10-06 12:09:44 -03:00
mdipierro
2a062a2ff5 fixed setup scripts for apache to use processes, not threads, thanks Thomas 2013-10-06 10:08:40 -05:00
abastardi
44e7b70dbc Fixed problem with Rows.render 2013-10-06 09:04:47 -04:00
Jose C
88abefb896 Support for HTTP Status Code: 429 - Too Many Requests
Currently raising HTTP 429 results in HTTP 500 being sent.  This patch resolves that issue.
2013-10-05 15:42:48 +01:00
mdipierro
06ca5e6857 grid refcator patch for ajax, thanks Niphlod 2013-10-05 08:52:45 -05:00
Alfonso de la Guarda Reyes
c1f8d34892 Minor fixes for pep and styles widget.py 2013-10-05 08:08:37 -05:00
Alfonso de la Guarda Reyes
5679661914 Minor fixes for pep and style 2013-10-05 08:03:50 -05:00
Alfonso de la Guarda Reyes
cd957cf52b Fixes for some pep and code syntax 2013-10-05 07:59:04 -05:00
Alfonso de la Guarda Reyes
fff798c1cc Added restriction for .idea inside gitignore 2013-10-05 07:51:12 -05:00
niphlod
b464d3185e fixed gevent workers 2013-10-05 13:43:03 +02:00
mdipierro
cfb68ff90f fixed ldap_auth.py 2013-10-04 21:31:39 -05:00
24 changed files with 269 additions and 270 deletions

1
.gitignore vendored
View File

@@ -55,3 +55,4 @@ applications/admin/cron/cron.master
HOWTO-web2py-devel
*.sublime-project
*.sublime-workspace
.idea/*

View File

@@ -1,4 +1,4 @@
## 2.7.1
## 2.7.1 - 2.7.2
- jQuery 1.10.2
- codemirror 3.18, thanks Paolo

View File

@@ -30,7 +30,7 @@ update:
echo "remember that pymysql was tweaked"
src:
### Use semantic versioning
echo 'Version 2.7.1-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
echo 'Version 2.7.3-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
### rm -f all junk files
make clean
### clean up baisc apps

View File

@@ -1 +1 @@
Version 2.7.1-stable+timestamp.2013.10.04.15.14.09
Version 2.7.3-stable+timestamp.2013.10.11.18.10.01

View File

@@ -33,7 +33,7 @@ class Servers:
@staticmethod
def wsgiref(app, address, **options): # pragma: no cover
from wsgiref.simple_server import make_server, WSGIRequestHandler
options = {}
class QuietHandler(WSGIRequestHandler):
def log_request(*args, **kw):
pass
@@ -71,6 +71,7 @@ class Servers:
@staticmethod
def paste(app, address, **options):
options = {}
from paste import httpserver
from paste.translogger import TransLogger
httpserver.serve(app, host=address[0], port=address[1], **options)
@@ -90,10 +91,12 @@ class Servers:
@staticmethod
def gevent(app, address, **options):
options = options['options']
workers = options.workers
from gevent import pywsgi
from gevent.pool import Pool
pywsgi.WSGIServer(address, app, spawn='workers' in options and Pool(
int(options.workers)) or 'default').serve_forever()
pywsgi.WSGIServer(address, app, spawn=workers and Pool(
int(options.workers)) or 'default', log=None).serve_forever()
@staticmethod
def bjoern(app, address, **options):
@@ -130,6 +133,7 @@ class Servers:
@staticmethod
def gunicorn(app, address, **options):
options = {}
from gunicorn.app.base import Application
config = {'bind': "%s:%d" % address}
config.update(options)
@@ -176,27 +180,6 @@ class Servers:
s = wsgi.WSGIServer(callable=app, bind="%s:%d" % address)
s.start()
def run(servername, ip, port, softcron=True, logging=False, profiler=None):
if servername == 'gevent':
from gevent import monkey
monkey.patch_all()
elif servername == 'eventlet':
import eventlet
eventlet.monkey_patch()
import gluon.main
if logging:
application = gluon.main.appfactory(wsgiapp=gluon.main.wsgibase,
logfilename='httpserver.log',
profiler_dir=profiler)
else:
application = gluon.main.wsgibase
if softcron:
from gluon.settings import global_settings
global_settings.web2py_crontype = 'soft'
getattr(Servers, servername)(application, (ip, int(port)))
def mongrel2_handler(application, conn, debug=False):
"""
@@ -303,6 +286,30 @@ def mongrel2_handler(application, conn, debug=False):
req, data, code=code, status=status, headers=headers)
def run(servername, ip, port, softcron=True, logging=False, profiler=None,
options=None):
if servername == 'gevent':
from gevent import monkey
monkey.patch_all()
elif servername == 'eventlet':
import eventlet
eventlet.monkey_patch()
import gluon.main
if logging:
application = gluon.main.appfactory(wsgiapp=gluon.main.wsgibase,
logfilename='httpserver.log',
profiler_dir=profiler)
else:
application = gluon.main.wsgibase
if softcron:
from gluon.settings import global_settings
global_settings.web2py_crontype = 'soft'
getattr(Servers, servername)(application, (ip, int(port)), options=options)
def main():
usage = "python anyserver.py -s tornado -i 127.0.0.1 -p 8000 -l -P"
try:
@@ -339,14 +346,15 @@ def main():
help='port number')
parser.add_option('-w',
'--workers',
default='',
default=None,
dest='workers',
help='number of workers number')
(options, args) = parser.parse_args()
print 'starting %s on %s:%s...' % (
options.server, options.ip, options.port)
run(options.server, options.ip, options.port,
logging=options.logging, profiler=options.profiler_dir)
logging=options.logging, profiler=options.profiler_dir,
options=options)
if __name__ == '__main__':
main()

View File

@@ -7,33 +7,35 @@
'%s %%{row} updated': '%s filas actualizadas',
'%Y-%m-%d': '%Y-%m-%d',
'%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S',
'(requires internet access, experimental)': '(requires internet access, experimental)',
'(requires internet access, experimental)': '(requiere acceso a internet, experimental)',
'(something like "it-it")': '(algo como "it-it")',
'@markmin\x01(file **gluon/contrib/plural_rules/%s.py** is not found)': '(file **gluon/contrib/plural_rules/%s.py** is not found)',
'@markmin\x01An error occured, please [[reload %s]] the page': 'An error occured, please [[reload %s]] the page',
'@markmin\x01Searching: **%s** %%{file}': 'Searching: **%s** files',
'A new version of web2py is available': 'Hay una nueva versión de web2py disponible',
'A new version of web2py is available: %s': 'Hay una nueva versión de web2py disponible: %s',
'About': 'acerca de',
'About application': 'Acerca de la aplicación',
'additional code for your application': 'código adicional para su aplicación',
'Additional code for your application': 'Additional code for your application',
'admin disabled because no admin password': ' por falta de contraseña',
'Additional code for your application': 'Código adicional para su aplicación',
'admin disabled because no admin password': 'admin deshabilitado por falta de contraseña',
'admin disabled because not supported on google app engine': 'admin deshabilitado, no es soportado en GAE',
'admin disabled because unable to access password file': 'admin deshabilitado, imposible acceder al archivo con la contraseña',
'Admin is disabled because insecure channel': 'Admin deshabilitado, el canal no es seguro',
'Admin is disabled because unsecure channel': 'Admin deshabilitado, el canal no es seguro',
'Admin language': 'Admin language',
'administrative interface': 'administrative interface',
'Admin language': 'Lenguaje de administración',
'administrative interface': 'interfaz administrativa',
'Administrator Password:': 'Contraseña del Administrador:',
'An error occured, please %s the page': 'An error occured, please %s the page',
'An error occured, please %s the page': 'Ha ocurrido un error, por favor %s la página',
'and rename it (required):': 'y renombrela (requerido):',
'and rename it:': ' y renombrelo:',
'appadmin': 'appadmin',
'appadmin is disabled because insecure channel': 'admin deshabilitado, el canal no es seguro',
'application "%s" uninstalled': 'aplicación "%s" desinstalada',
'application %(appname)s installed with md5sum: %(digest)s': 'application %(appname)s installed with md5sum: %(digest)s',
'application compiled': 'aplicación compilada',
'application is compiled and cannot be designed': 'la aplicación está compilada y no puede ser modificada',
'Application name:': 'Application name:',
'Application name:': 'Nombre de la aplicación:',
'are not used': 'are not used',
'are not used yet': 'are not used yet',
'Are you sure you want to delete file "%s"?': '¿Está seguro que desea eliminar el archivo "%s"?',
@@ -43,13 +45,13 @@
'Are you sure you want to uninstall application "%s"?': '¿Está seguro que desea desinstalar la aplicación "%s"?',
'Are you sure you want to upgrade web2py now?': '¿Está seguro que desea actualizar web2py ahora?',
'arguments': 'argumentos',
'at char %s': 'at char %s',
'at line %s': 'at line %s',
'at char %s': 'en el caracter %s',
'at line %s': 'en la línea %s',
'ATTENTION: Login requires a secure (HTTPS) connection or running on localhost.': 'ATENCION: Inicio de sesión requiere una conexión segura (HTTPS) o localhost.',
'ATTENTION: TESTING IS NOT THREAD SAFE SO DO NOT PERFORM MULTIPLE TESTS CONCURRENTLY.': 'ATENCION: NO EJECUTE VARIAS PRUEBAS SIMULTANEAMENTE, NO SON THREAD SAFE.',
'ATTENTION: you cannot edit the running application!': 'ATENCION: no puede modificar la aplicación que se ejecuta!',
'Autocomplete': 'Autocomplete',
'Autocomplete Python Code': 'Autocomplete Python Code',
'Autocomplete Python Code': 'Autocompletar código Python',
'Available databases and tables': 'Bases de datos y tablas disponibles',
'back': 'atrás',
'breakpoint': 'breakpoint',
@@ -57,17 +59,17 @@
'browse': 'buscar',
'cache': 'cache',
'cache, errors and sessions cleaned': 'cache, errores y sesiones eliminados',
'can be a git repo': 'can be a git repo',
'can be a git repo': 'puede ser un repositorio git',
'Cannot be empty': 'No puede estar vacío',
'Cannot compile: there are errors in your app. Debug it, correct errors and try again.': 'No se puede compilar: hay errores en su aplicación. Depure, corrija errores y vuelva a intentarlo.',
'Cannot compile: there are errors in your app:': 'No se puede compilar: hay errores en su aplicación:',
'cannot create file': 'no es posible crear archivo',
'cannot upload file "%(filename)s"': 'no es posible subir archivo "%(filename)s"',
'Change admin password': 'cambie contraseña admin',
'change editor settings': 'change editor settings',
'change editor settings': 'cambiar la configuración del editor',
'Change Password': 'Cambie Contraseña',
'check all': 'marcar todos',
'Check for upgrades': 'Check for upgrades',
'Check for upgrades': 'buscar actualizaciones',
'Check to delete': 'Marque para eliminar',
'Checking for upgrades...': 'Buscando actulizaciones...',
'Clean': 'limpiar',
@@ -75,23 +77,24 @@
'click here for the administrative interface': 'haga clic aquí para usar la interfaz administrativa',
'Click row to expand traceback': 'Click row to expand traceback',
'click to check for upgrades': 'haga clic para buscar actualizaciones',
'click to open': 'click to open',
'click to open': 'click para abrir',
'Client IP': 'IP del Cliente',
'code': 'código',
'Code listing': 'Code listing',
'collapse/expand all': 'collapse/expand all',
'commit (mercurial)': 'commit (mercurial)',
'Code listing': 'Listado de código',
'collapse/expand all': 'contraer/expandir todo',
'commit (mercurial)': 'confirmar (mercurial)',
'Compile': 'compilar',
'compiled application removed': 'aplicación compilada removida',
'continue': 'continue',
'continue': 'continuar',
'Controllers': 'Controladores',
'controllers': 'controladores',
'Count': 'Count',
'Create': 'crear',
'Create': 'Crear',
'create file with filename:': 'cree archivo con nombre:',
'Create new application using the Wizard': 'Create new application using the Wizard',
'Create new application using the Wizard': 'Crear nueva aplicación utilizando el asistente',
'create new application:': 'nombre de la nueva aplicación:',
'Create new simple application': 'Cree una nueva aplicación',
'Create/Upload': 'Create/Upload',
'created by': 'creado por',
'crontab': 'crontab',
'Current request': 'Solicitud en curso',
@@ -112,25 +115,25 @@
'delete': 'eliminar',
'delete all checked': 'eliminar marcados',
'delete plugin': 'eliminar plugin',
'Delete this file (you will be asked to confirm deletion)': 'Delete this file (you will be asked to confirm deletion)',
'Delete this file (you will be asked to confirm deletion)': 'Elimine este fichero (se le pedirá confirmación)',
'Delete:': 'Elimine:',
'Deploy': 'Deploy',
'Deploy on Google App Engine': 'Instale en Google App Engine',
'Deploy to OpenShift': 'Deploy to OpenShift',
'Deploy to OpenShift': 'Instale en OpenShift',
'Description': 'Descripción',
'design': 'modificar',
'DESIGN': 'DISEÑO',
'Design for': 'Diseño para',
'Detailed traceback description': 'Detailed traceback description',
'details': 'details',
'details': 'detalles',
'direction: ltr': 'direction: ltr',
'Disable': 'Disable',
'Disable': 'Deshabilitar',
'docs': 'docs',
'done!': 'listo!',
'Download': 'Download',
'download files via http:': 'download files via http:',
'download layouts': 'download layouts',
'download plugins': 'download plugins',
'Download': 'Descargar',
'download files via http:': 'descargar archivos via http:',
'download layouts': 'descargar layouts',
'download plugins': 'descargar plugins',
'E-mail': 'Correo electrónico',
'EDIT': 'EDITAR',
'Edit': 'editar',
@@ -157,7 +160,7 @@
'Expand Abbreviation': 'Expand Abbreviation',
'export as csv file': 'exportar como archivo CSV',
'exposes': 'expone',
'exposes:': 'exposes:',
'exposes:': 'expone:',
'extends': 'extiende',
'failed to compile file because:': 'failed to compile file because:',
'failed to reload module': 'recarga del módulo ha fallado',
@@ -173,8 +176,8 @@
'file saved on %(time)s': 'archivo guardado %(time)s',
'file saved on %s': 'archivo guardado %s',
'filter': 'filter',
'Find Next': 'Find Next',
'Find Previous': 'Find Previous',
'Find Next': 'Buscar próximo',
'Find Previous': 'Bucar anterior',
'First name': 'Nombre',
'Frames': 'Frames',
'Functions with no doctests will result in [passed] tests.': 'Funciones sin doctests equivalen a pruebas [aceptadas].',
@@ -221,8 +224,8 @@
'Login to the Administrative Interface': 'Inicio de sesión para la Interfaz Administrativa',
'Logout': 'fin de sesión',
'Lost Password': 'Contraseña perdida',
'manage': 'manage',
'Manage': 'Manage',
'manage': 'gestionar',
'Manage': 'Gestionar',
'merge': 'combinar',
'Models': 'Modelos',
'models': 'modelos',
@@ -230,11 +233,11 @@
'modules': 'módulos',
'Name': 'Nombre',
'new application "%s" created': 'nueva aplicación "%s" creada',
'New application wizard': 'New application wizard',
'New application wizard': 'Asistente para nueva aplicación',
'new plugin installed': 'nuevo plugin instalado',
'New Record': 'Registro nuevo',
'new record inserted': 'nuevo registro insertado',
'New simple application': 'New simple application',
'New simple application': 'Nueva aplicación',
'next': 'next',
'next 100 rows': '100 filas siguientes',
'NO': 'NO',
@@ -245,16 +248,16 @@
'No ticket_storage.txt found under /private folder': 'No ticket_storage.txt found under /private folder',
'online designer': 'online designer',
'or alternatively': 'or alternatively',
'Or Get from URL:': 'Or Get from URL:',
'Or Get from URL:': 'O obtener desde una URL:',
'or import from csv file': 'o importar desde archivo CSV',
'or provide app url:': 'o provea URL de la aplicación:',
'or provide application url:': 'o provea URL de la aplicación:',
'Origin': 'Origen',
'Original/Translation': 'Original/Traducción',
'Overwrite installed app': 'sobreescriba aplicación instalada',
'Overwrite installed app': 'sobreescriba la aplicación instalada',
'Pack all': 'empaquetar todo',
'Pack compiled': 'empaquete compiladas',
'Pack custom': 'Pack custom',
'Pack custom': 'empaquetar personalizado',
'pack plugin': 'empaquetar plugin',
'PAM authenticated user, cannot change password here': 'usuario autenticado por PAM, no puede cambiar la contraseña aquí',
'Password': 'Contraseña',
@@ -268,8 +271,8 @@
'Plural-Forms:': 'Plural-Forms:',
'Powered by': 'Este sitio usa',
'previous 100 rows': '100 filas anteriores',
'Private files': 'Private files',
'private files': 'private files',
'Private files': 'Archivos privados',
'private files': 'archivos privados',
'Query:': 'Consulta:',
'Rapid Search': 'Rapid Search',
'record': 'registro',
@@ -282,9 +285,9 @@
'reload': 'reload',
'Reload routes': 'Reload routes',
'Remove compiled': 'eliminar compiladas',
'Removed Breakpoint on %s at line %s': 'Removed Breakpoint on %s at line %s',
'Replace': 'Replace',
'Replace All': 'Replace All',
'Removed Breakpoint on %s at line %s': 'Eliminado punto de ruptura en %s en la línea %s',
'Replace': 'Reemplazar',
'Replace All': 'Reemplazar todos',
'request': 'request',
'Resolve Conflict file': 'archivo Resolución de Conflicto',
'response': 'response',
@@ -300,19 +303,19 @@
'Running on %s': 'Running on %s',
'Save': 'Save',
'save': 'guardar',
'Save file:': 'Save file:',
'Save file: %s': 'Save file: %s',
'Save via Ajax': 'Save via Ajax',
'Save file:': 'Guardar:',
'Save file: %s': 'Guardar: %s',
'Save via Ajax': 'Guardar via Ajax',
'Saved file hash:': 'Hash del archivo guardado:',
'selected': 'seleccionado(s)',
'session': 'session',
'session expired': 'sesión expirada',
'Set Breakpoint on %s at line %s: %s': 'Set Breakpoint on %s at line %s: %s',
'Set Breakpoint on %s at line %s: %s': 'Establecer punto de ruptura en %s en la línea %s: %s',
'shell': 'shell',
'Site': 'sitio',
'some files could not be removed': 'algunos archivos no pudieron ser removidos',
'Start searching': 'Start searching',
'Start wizard': 'Start wizard',
'Start searching': 'Iniciar búsqueda',
'Start wizard': 'Iniciar asistente',
'state': 'estado',
'Static': 'Static',
'static': 'estáticos',
@@ -321,7 +324,7 @@
'stop': 'stop',
'submit': 'enviar',
'Submit': 'Submit',
'successful': 'successful',
'successful': 'exitoso',
'Sure you want to delete this object?': '¿Está seguro que desea eliminar este objeto?',
'table': 'tabla',
'Table name': 'Nombre de la tabla',
@@ -329,21 +332,21 @@
'Testing application': 'Probando aplicación',
'The "query" is a condition like "db.table1.field1==\'value\'". Something like "db.table1.field1==db.table2.field2" results in a SQL JOIN.': 'La "consulta" es una condición como "db.tabla1.campo1==\'valor\'". Algo como "db.tabla1.campo1==db.tabla2.campo2" resulta en un JOIN SQL.',
'the application logic, each URL path is mapped in one exposed function in the controller': 'la lógica de la aplicación, cada ruta URL se mapea en una función expuesta en el controlador',
'The application logic, each URL path is mapped in one exposed function in the controller': 'The application logic, each URL path is mapped in one exposed function in the controller',
'The application logic, each URL path is mapped in one exposed function in the controller': 'La lógica de la aplicación, cada ruta URL se mapea en una función expuesta en el controlador',
'the data representation, define database tables and sets': 'la representación de datos, define tablas y conjuntos de base de datos',
'The data representation, define database tables and sets': 'The data representation, define database tables and sets',
'The presentations layer, views are also known as templates': 'The presentations layer, views are also known as templates',
'The data representation, define database tables and sets': 'La representación de datos, define tablas y conjuntos de base de datos',
'The presentations layer, views are also known as templates': 'La capa de presentación, las vistas también son llamadas plantillas',
'the presentations layer, views are also known as templates': 'la capa de presentación, las vistas también son llamadas plantillas',
'There are no controllers': 'No hay controladores',
'There are no models': 'No hay modelos',
'There are no modules': 'No hay módulos',
'There are no plugins': 'There are no plugins',
'There are no private files': 'There are no private files',
'There are no plugins': 'No hay plugins',
'There are no private files': 'No hay archivos privados',
'There are no static files': 'No hay archivos estáticos',
'There are no translators, only default language is supported': 'No hay traductores, sólo el lenguaje por defecto es soportado',
'There are no views': 'No hay vistas',
'These files are not served, they are only available from within your app': 'These files are not served, they are only available from within your app',
'These files are served without processing, your images go here': 'These files are served without processing, your images go here',
'These files are not served, they are only available from within your app': 'Estos archivos no son servidos, ellos solo estan disponibles para su aplicación',
'These files are served without processing, your images go here': 'Estos archivos son servidos sin procesar, sus imágenes van aquí',
'these files are served without processing, your images go here': 'estos archivos son servidos sin procesar, sus imágenes van aquí',
'This is the %(filename)s template': 'Esta es la plantilla %(filename)s',
'this page to see if a breakpoint was hit and debug interaction is required.': 'this page to see if a breakpoint was hit and debug interaction is required.',
@@ -355,14 +358,14 @@
'To create a plugin, name a file/folder plugin_[name]': 'Para crear un plugin, nombre un archivo/carpeta plugin_[nombre]',
'To emulate a breakpoint programatically, write:': 'To emulate a breakpoint programatically, write:',
'to use the debugger!': 'to use the debugger!',
'toggle breakpoint': 'toggle breakpoint',
'Toggle Fullscreen': 'Toggle Fullscreen',
'toggle breakpoint': 'alternar punto de ruptura',
'Toggle Fullscreen': 'Alternar pantalla completa',
'Traceback': 'Traceback',
'translation strings for the application': 'cadenas de caracteres de traducción para la aplicación',
'Translation strings for the application': 'Translation strings for the application',
'Translation strings for the application': 'Cadenas de caracteres de traducción para la aplicación',
'try': 'intente',
'try something like': 'intente algo como',
'Try the mobile interface': 'Try the mobile interface',
'Try the mobile interface': 'Pruebe la interfaz móvil',
'try view': 'try view',
'Type some Python code in here and hit Return (Enter) to execute it.': 'Type some Python code in here and hit Return (Enter) to execute it.',
'Unable to check for upgrades': 'No es posible verificar la existencia de actualizaciones',
@@ -383,10 +386,10 @@
'Update:': 'Actualice:',
'upgrade now to %s': 'upgrade now to %s',
'upgrade web2py now': 'actualize web2py ahora',
'Upload': 'Upload',
'Upload': 'Subir',
'Upload & install packed application': 'Suba e instale aplicación empaquetada',
'Upload a package:': 'Upload a package:',
'Upload and install packed application': 'Upload and install packed application',
'Upload a package:': 'Subir un paquete:',
'Upload and install packed application': 'Suba e instale una aplicación empaquetada',
'upload application:': 'subir aplicación:',
'Upload existing application': 'Suba esta aplicación',
'upload file:': 'suba archivo:',

View File

@@ -8,6 +8,7 @@ from gluon.fileutils import read_file
# ## make sure administrator is on localhost or https
# ###########################################################
http_host = request.env.http_host.split(':')[0]
if request.env.web2py_runtime_gae:
@@ -145,6 +146,10 @@ elif session.is_mobile == 'false':
else:
is_mobile = request.user_agent().is_mobile
if DEMO_MODE:
session.authorized = True
session.forget()
if request.controller == "webservices":
basic = request.env.http_authorization
if not basic or not basic[:6].lower() == 'basic ':

View File

@@ -264,16 +264,6 @@
}
});
},
trap_link: function (target) {
$('#' + target + ' a.w2p_trap').each(function (i) {
var link = $(this);
link.click(function (e) {
web2py.hide_flash();
web2py.ajax_page('get', link.attr('href'), [], target, $(this));
e.preventDefault();
});
});
},
ajax_page: function (method, action, data, target, element) {
/* element is a new parameter, but should be put be put in front */
if(element == undefined) element = $(document);
@@ -307,7 +297,6 @@
web2py.fire(element, 'ajax:complete', [xhr, status], target);
web2py.updatePage(xhr, target); /* Parse and load the html received */
web2py.trap_form(action, target);
web2py.trap_link(target);
web2py.ajax_init('#' + target);
web2py.after_ajax(xhr);
}
@@ -692,10 +681,8 @@ collapse = jQuery.web2py.collapse;
fade = jQuery.web2py.fade;
/* internals - shouldn't be needed
web2py_ajax_init = jQuery.web2py.ajax_init;
web2py_event_handlers = jQuery.web2py.event_handlers;
web2py_trap_link = jQuery.web2py.trap_link;
web2py_calc_entropy = jQuery.web2py.calc_entropy;
*/

View File

@@ -264,16 +264,6 @@
}
});
},
trap_link: function (target) {
$('#' + target + ' a.w2p_trap').each(function (i) {
var link = $(this);
link.click(function (e) {
web2py.hide_flash();
web2py.ajax_page('get', link.attr('href'), [], target, $(this));
e.preventDefault();
});
});
},
ajax_page: function (method, action, data, target, element) {
/* element is a new parameter, but should be put be put in front */
if(element == undefined) element = $(document);
@@ -307,7 +297,6 @@
web2py.fire(element, 'ajax:complete', [xhr, status], target);
web2py.updatePage(xhr, target); /* Parse and load the html received */
web2py.trap_form(action, target);
web2py.trap_link(target);
web2py.ajax_init('#' + target);
web2py.after_ajax(xhr);
}
@@ -692,10 +681,8 @@ collapse = jQuery.web2py.collapse;
fade = jQuery.web2py.fade;
/* internals - shouldn't be needed
web2py_ajax_init = jQuery.web2py.ajax_init;
web2py_event_handlers = jQuery.web2py.event_handlers;
web2py_trap_link = jQuery.web2py.trap_link;
web2py_calc_entropy = jQuery.web2py.calc_entropy;
*/

View File

@@ -264,16 +264,6 @@
}
});
},
trap_link: function (target) {
$('#' + target + ' a.w2p_trap').each(function (i) {
var link = $(this);
link.click(function (e) {
web2py.hide_flash();
web2py.ajax_page('get', link.attr('href'), [], target, $(this));
e.preventDefault();
});
});
},
ajax_page: function (method, action, data, target, element) {
/* element is a new parameter, but should be put be put in front */
if(element == undefined) element = $(document);
@@ -307,7 +297,6 @@
web2py.fire(element, 'ajax:complete', [xhr, status], target);
web2py.updatePage(xhr, target); /* Parse and load the html received */
web2py.trap_form(action, target);
web2py.trap_link(target);
web2py.ajax_init('#' + target);
web2py.after_ajax(xhr);
}
@@ -692,10 +681,8 @@ collapse = jQuery.web2py.collapse;
fade = jQuery.web2py.fade;
/* internals - shouldn't be needed
web2py_ajax_init = jQuery.web2py.ajax_init;
web2py_event_handlers = jQuery.web2py.event_handlers;
web2py_trap_link = jQuery.web2py.trap_link;
web2py_calc_entropy = jQuery.web2py.calc_entropy;
*/

View File

@@ -353,7 +353,7 @@ def plugin_install(app, fobj, request, filename):
return False
def check_new_version(myversion, version_URL):
def check_new_version(myversion, version_url):
"""
Compares current web2py's version with the latest stable web2py version.
@@ -374,7 +374,7 @@ def check_new_version(myversion, version_URL):
"""
try:
from urllib import urlopen
version = urlopen(version_URL).read()
version = urlopen(version_url).read()
pversion = parse_version(version)
pmyversion = parse_version(myversion)
except IOError:
@@ -398,7 +398,7 @@ def unzip(filename, dir, subfolder=''):
raise RuntimeError('Not a valid zipfile')
zf = zipfile.ZipFile(filename)
if not subfolder.endswith('/'):
subfolder = subfolder + '/'
subfolder += '/'
n = len(subfolder)
for name in sorted(zf.namelist()):
if not name.startswith(subfolder):
@@ -432,11 +432,11 @@ def upgrade(request, url='http://web2py.com'):
web2py_version = request.env.web2py_version
gluon_parent = request.env.gluon_parent
if not gluon_parent.endswith('/'):
gluon_parent = gluon_parent + '/'
gluon_parent += '/'
(check, version) = check_new_version(web2py_version,
url + '/examples/default/version')
if not check:
return (False, 'Already latest version')
return False, 'Already latest version'
if os.path.exists(os.path.join(gluon_parent, 'web2py.exe')):
version_type = 'win'
destination = gluon_parent
@@ -452,7 +452,6 @@ def upgrade(request, url='http://web2py.com'):
full_url = url + '/examples/static/web2py_%s.zip' % version_type
filename = abspath('web2py_%s_downloaded.zip' % version_type)
file = None
try:
write_file(filename, urllib.urlopen(full_url).read(), 'wb')
except Exception, e:

View File

@@ -19,7 +19,6 @@ When web2py is running on Google App Engine,
caching will be provided by the GAE memcache
(see gluon.contrib.gae_memcache)
"""
import traceback
import time
import portalocker
import shelve
@@ -278,7 +277,7 @@ class CacheOnDisk(CacheAbstract):
storage = shelve.open(self.shelve_name)
except:
logger.error('corrupted cache file %s, will try rebuild it'
% (self.shelve_name))
% self.shelve_name)
storage = None
if not storage and os.path.exists(self.shelve_name):
os.unlink(self.shelve_name)
@@ -479,7 +478,6 @@ class Cache(object):
if not session_ and public_:
cache_control += ', public'
expires = (current.request.utcnow + datetime.timedelta(seconds=time_expire)).strftime('%a, %d %b %Y %H:%M:%S GMT')
vary = None
else:
cache_control += ', private'
expires = 'Fri, 01 Jan 1990 00:00:00 GMT'

View File

@@ -380,7 +380,6 @@ _base_environment_['SQLFORM'] = SQLFORM
_base_environment_['SQLTABLE'] = SQLTABLE
_base_environment_['LOAD'] = LOAD
def build_environment(request, response, session, store_current=True):
"""
Build the environment dictionary into which web2py files are executed.
@@ -392,8 +391,11 @@ def build_environment(request, response, session, store_current=True):
request.env = Storage()
# Enable standard conditional models (i.e., /*.py, /[controller]/*.py, and
# /[controller]/[function]/*.py)
response.models_to_run = [r'^\w+\.py$', r'^%s/\w+\.py$' % request.controller,
r'^%s/%s/\w+\.py$' % (request.controller, request.function)]
response.models_to_run = [
r'^\w+\.py$',
r'^%s/\w+\.py$' % request.controller,
r'^%s/%s/\w+\.py$' % (request.controller, request.function)
]
t = environment['T'] = translator(os.path.join(request.folder,'languages'),
request.env.http_accept_language)
@@ -452,12 +454,12 @@ def compile_views(folder):
"""
path = pjoin(folder, 'views')
for file in listdir(path, '^[\w/\-]+(\.\w+)*$'):
for fname in listdir(path, '^[\w/\-]+(\.\w+)*$'):
try:
data = parse_template(file, path)
data = parse_template(fname, path)
except Exception, e:
raise Exception("%s in %s" % (e, file))
filename = ('views/%s.py' % file).replace('/', '_').replace('\\', '_')
raise Exception("%s in %s" % (e, fname))
filename = 'views.%s.py' % fname.replace(os.path.sep, '.')
filename = pjoin(folder, 'compiled', filename)
write_file(filename, data)
save_pyc(filename)
@@ -470,9 +472,10 @@ def compile_models(folder):
"""
path = pjoin(folder, 'models')
for file in listdir(path, '.+\.py$'):
data = read_file(pjoin(path, file))
filename = pjoin(folder, 'compiled', 'models', file)
for fname in listdir(path, '.+\.py$'):
data = read_file(pjoin(path, fname))
modelfile = 'models.'+fname.replace(os.path.sep,'.')
filename = pjoin(folder, 'compiled', modelfile)
mktree(filename)
write_file(filename, data)
save_pyc(filename)
@@ -485,20 +488,21 @@ def compile_controllers(folder):
"""
path = pjoin(folder, 'controllers')
for file in listdir(path, '.+\.py$'):
for fname in listdir(path, '.+\.py$'):
### why is this here? save_pyc(pjoin(path, file))
data = read_file(pjoin(path, file))
data = read_file(pjoin(path, fname))
exposed = regex_expose.findall(data)
for function in exposed:
command = data + "\nresponse._vars=response._caller(%s)\n" % \
function
filename = pjoin(folder, 'compiled', ('controllers/'
+ file[:-3]).replace('/', '_')
+ '_' + function + '.py')
filename = pjoin(folder, 'compiled',
'controllers.%s.%s.py' % (fname[:-3],function))
write_file(filename, command)
save_pyc(filename)
os.unlink(filename)
def model_cmp(a,b):
return cmp(a.count('.'),b.count('.')) or cmp(a,b)
def run_models_in(environment):
"""
@@ -508,34 +512,39 @@ def run_models_in(environment):
folder = environment['request'].folder
c = environment['request'].controller
f = environment['request'].function
f = environment['request'].function
response = environment['response']
path = pjoin(folder, 'models')
cpath = pjoin(folder, 'compiled')
if os.path.exists(cpath):
for model in listdir(cpath, '^models_\w+\.pyc$', 0):
restricted(read_pyc(model), environment, layer=model)
path = pjoin(cpath, 'models')
models = listdir(path, '^\w+\.pyc$', 0, sort=True)
compiled = True
compiled = os.path.exists(cpath)
if compiled:
models = sorted(listdir(cpath, '^models[_.][\w.]+\.pyc$', 0),model_cmp)
else:
path = pjoin(folder, 'models')
models = listdir(path, '^\w+\.py$', 0, sort=True)
compiled = False
n = len(path) + 1
models = sorted(listdir(path, '^\w+\.py$', 0, sort=False),model_cmp)
n = len(path)+1
models_to_run = None
for model in models:
regex = environment['response'].models_to_run
if isinstance(regex, list):
regex = re_compile('|'.join(regex))
file = model[n:].replace(os.path.sep, '/').replace('.pyc', '.py')
if not regex.search(file) and c != 'appadmin':
continue
elif compiled:
code = read_pyc(model)
elif is_gae:
code = getcfs(model, model,
lambda: compile2(read_file(model), model))
else:
code = getcfs(model, model, None)
restricted(code, environment, layer=model)
if response.models_to_run != models_to_run:
regex = models_to_run = response.models_to_run
if isinstance(regex, list):
regex = re_compile('|'.join(regex))
if models_to_run:
if compiled:
fname = model[n:-4].replace('.','/')+'.py'
else:
fname = model[n:].replace(os.path.sep,'/')
if not regex.search(fname) and c != 'appadmin':
continue
elif compiled:
code = read_pyc(model)
elif is_gae:
code = getcfs(model, model,
lambda: compile2(read_file(model), model))
else:
code = getcfs(model, model, None)
restricted(code, environment, layer=model)
def run_controller_in(controller, function, environment):
@@ -551,12 +560,17 @@ def run_controller_in(controller, function, environment):
badc = 'invalid controller (%s/%s)' % (controller, function)
badf = 'invalid function (%s/%s)' % (controller, function)
if os.path.exists(path):
filename = pjoin(path, 'controllers_%s_%s.pyc'
filename = pjoin(path, 'controllers.%s.%s.pyc'
% (controller, function))
if not os.path.exists(filename):
raise HTTP(404,
rewrite.THREAD_LOCAL.routes.error_message % badf,
web2py_error=badf)
### for backward compatibility
filename = pjoin(path, 'controllers_%s_%s.pyc'
% (controller, function))
### end for backward compatibility
if not os.path.exists(filename):
raise HTTP(404,
rewrite.THREAD_LOCAL.routes.error_message % badf,
web2py_error=badf)
restricted(read_pyc(filename), environment, layer=filename)
elif function == '_TEST':
# TESTING: adjust the path to include site packages
@@ -631,11 +645,15 @@ def run_view_in(environment):
context=environment)
restricted(ccode, environment, 'file stream')
elif os.path.exists(path):
x = view.replace('/', '.')
files = ['views.%s.pyc' % x]
if allow_generic:
files.append('views.generic.%s.pyc' % request.extension)
# for backward compatibility
x = view.replace('/', '_')
files = ['views_%s.pyc' % x]
files.append('views_%s.pyc' % x)
if allow_generic:
files.append('views_generic.%s.pyc' % request.extension)
# for backward compatibility
if request.extension == 'html':
files.append('views_%s.pyc' % x[:-5])
if allow_generic:

View File

@@ -37,7 +37,7 @@ class MemcacheClient(object):
self.client.delete(key)
else:
value = f()
self.client.set(key, (time.time(), value))
self.client.set(key, (time.time(), value), time=time_expire)
return value
def increment(self, key, value=1):

View File

@@ -640,10 +640,10 @@ def ldap_auth(server='ldap', port=None,
else:
# bind as anonymous
con.simple_bind_s('', '')
# if username is None, return empty list
if username is None:
return list()
# if username is None, return empty list
if username is None:
return list()
# search for groups where user is in
filter = '(&(%s=%s)(%s))' % (ldap.filter.escape_filter_chars(
group_member_attrib

View File

@@ -6124,7 +6124,7 @@ class IMAPAdapter(NoSQLAdapter):
else:
return (uid_list[0], uid_list[-1])
def convert_date(self, date, add=None):
def convert_date(self, date, add=None, imf=False):
if add is None:
add = datetime.timedelta()
""" Convert a date object to a string
@@ -6138,7 +6138,10 @@ class IMAPAdapter(NoSQLAdapter):
if isinstance(date, basestring):
# Prevent unexpected date response format
try:
dayname, datestring = date.split(",")
if "," in date:
dayname, datestring = date.split(",")
else:
dayname, datestring = None, date
date_list = datestring.strip().split()
year = int(date_list[2])
month = months.index(date_list[1].upper())
@@ -6150,8 +6153,10 @@ class IMAPAdapter(NoSQLAdapter):
LOGGER.error("Could not parse date text: %s. %s" %
(date, e))
return None
elif isinstance(date, (datetime.datetime, datetime.date)):
return (date + add).strftime("%d-%b-%Y")
elif isinstance(date, (datetime.date, datetime.datetime)):
if imf: date_format = "%a, %d %b %Y %H:%M:%S %z"
else: date_format = "%d-%b-%Y"
return (date + add).strftime(date_format)
else:
return None
@@ -6532,7 +6537,8 @@ class IMAPAdapter(NoSQLAdapter):
mailbox = table.mailbox
d = dict(((k.name, v) for k, v in fields))
date_time = (d.get("created", datetime.datetime.now())).timetuple()
date_time = d.get("created", datetime.datetime.now())
struct_time = date_time.timetuple()
if len(d) > 0:
message = d.get("email", None)
attachments = d.get("attachments", [])
@@ -6547,6 +6553,8 @@ class IMAPAdapter(NoSQLAdapter):
message = Message()
message["from"] = d.get("sender", "")
message["subject"] = d.get("subject", "")
message["date"] = self.convert_date(date_time, imf=True)
if mime:
message.set_type(mime)
if charset:
@@ -6569,7 +6577,7 @@ class IMAPAdapter(NoSQLAdapter):
[add_payload(message, c) for c in content]
[add_payload(message, a) for a in attachments]
message = message.as_string()
return (mailbox, flags, date_time, message)
return (mailbox, flags, struct_time, message)
else:
raise NotImplementedError("IMAP empty insert is not implemented")
@@ -6918,7 +6926,7 @@ def sqlhtml_validators(field):
elif field_type == 'double' or field_type == 'float':
requires.append(validators.IS_FLOAT_IN_RANGE(-1e100, 1e100))
elif field_type in ('integer','bigint'):
requires.append(validators.IS_INT_IN_RANGE(-1e100, 1e100))
requires.append(validators.IS_INT_IN_RANGE(-2**31, 2**31-1))
elif field_type.startswith('decimal'):
requires.append(validators.IS_DECIMAL_IN_RANGE(-10**10, 10**10))
elif field_type == 'date':
@@ -10501,7 +10509,7 @@ class Rows(object):
if i is None:
return (self.repr(i, fields=fields) for i in range(len(self)))
return (self.render(i, fields=fields) for i in range(len(self)))
import sqlhtml
row = copy.deepcopy(self.records[i])
keys = row.keys()

View File

@@ -44,6 +44,7 @@ defined_status = {
416: 'REQUESTED RANGE NOT SATISFIABLE',
417: 'EXPECTATION FAILED',
422: 'UNPROCESSABLE ENTITY',
429: 'TOO MANY REQUESTS',
451: 'UNAVAILABLE FOR LEGAL REASONS', # http://www.451unavailable.org/
500: 'INTERNAL SERVER ERROR',
501: 'NOT IMPLEMENTED',
@@ -53,8 +54,7 @@ defined_status = {
505: 'HTTP VERSION NOT SUPPORTED',
}
regex_status = re.compile('^\d{3} \w+$')
regex_status = re.compile('^\d{3} [0-9A-Z ]+$')
class HTTP(Exception):

View File

@@ -288,7 +288,10 @@ def run(
else:
try:
import IPython
if IPython.__version__ >= '0.11':
if IPython.__version__ >= '1.0':
IPython.start_ipython(user_ns=_env)
return
elif IPython.__version__ >= '0.11':
from IPython.frontend.terminal.embed import InteractiveShellEmbed
shell = InteractiveShellEmbed(user_ns=_env)
shell()

View File

@@ -45,11 +45,6 @@ except ImportError:
table_field = re.compile('[\w_]+\.[\w_]+')
widget_class = re.compile('^\w*')
def trap_class(_class=None, trap=True):
return (trap and 'w2p_trap' or '') + (_class and ' ' + _class or '')
def represent(field, value, record):
f = field.represent
if not callable(f):
@@ -1897,7 +1892,8 @@ class SQLFORM(FORM):
callback=callback,
delete=delete,
noconfirm=noconfirm,
_class=trap_class(ui.get('button'), trap))
_class=ui.get('button'),
cid=request.cid)
else:
return A(SPAN(_class=ui.get(buttonclass)),
_href=buttonurl,
@@ -1905,7 +1901,8 @@ class SQLFORM(FORM):
delete=delete,
noconfirm=noconfirm,
_title=T(buttontext),
_class=trap_class(ui.get('buttontext'), trap))
_class=ui.get('buttontext'),
cid=request.cid)
dbset = db(query,ignore_common_filters=ignore_common_filters)
tablenames = db._adapter.tables(dbset.query)
@@ -1920,14 +1917,14 @@ class SQLFORM(FORM):
else:
fields = []
columns = []
filter1 = lambda f:isinstance(f,Field)
filter2 = lambda f:isinstance(f,Field) and f.readable
for table in tables:
fields += filter(filter1, table)
columns += filter(filter2, table)
for k,f in table.iteritems():
if not k.startswith('_'):
if isinstance(f,Field):
fields.append(f) # these are selected
if f.readable:
columns.append(f) # these are displayed
elif isinstance(f,Field.Virtual) and f.readable:
if isinstance(f,Field.Virtual) and f.readable:
f.tablename = table._tablename
columns.append(f)
fields.append(f)
@@ -2057,7 +2054,22 @@ class SQLFORM(FORM):
if ondelete:
ondelete(table, request.args[-1])
record.delete_record()
redirect(referrer, client_side=client_side_delete)
if request.ajax:
#this means javascript is enabled, so we don't need to do
#a redirect
if not client_side_delete:
#if it's an ajax request and we don't need to reload the
#entire page, let's just inform that there have been no
#exceptions and don't regenerate the grid
raise HTTP(200)
else:
#if it's requested that the grid gets reloaded on delete
#on ajax, the redirect should be on the original location
newloc = request.env.http_web2py_component_location
redirect(newloc, client_side=client_side_delete)
else:
#we need to do a redirect because javascript is not enabled
redirect(referrer, client_side=client_side_delete)
exportManager = dict(
csv_with_hidden_cols=(ExporterCSV, 'CSV (hidden cols)'),
@@ -2221,7 +2233,7 @@ class SQLFORM(FORM):
marker = sorter_icons[1]
header = A(header, marker, _href=url(vars=dict(
keywords=request.vars.keywords or '',
order=key)), _class=trap_class())
order=key)), cid=request.cid)
headcols.append(TH(header, _class=ui.get('default')))
toadd = []
@@ -2261,7 +2273,9 @@ class SQLFORM(FORM):
limitby = None
try:
table_fields = filter(lambda f: f.tablename in tablenames, fields)
table_fields = filter(
lambda f: (f.tablename in tablenames) and \
(not(isinstance(f,Field.Virtual))),fields)
if dbset._db._adapter.dbengine=='google:datastore':
rows = dbset.select(left=left,orderby=orderby,
groupby=groupby,limitby=limitby,
@@ -2269,7 +2283,6 @@ class SQLFORM(FORM):
cacheable=True,*table_fields)
next_cursor = dbset._db.get('_lastcursor', None)
else:
# print('table_fields: %s' %([f_.name for f_ in table_fields],))
rows = dbset.select(left=left,orderby=orderby,
groupby=groupby,limitby=limitby,
cacheable=True,*table_fields)
@@ -2303,7 +2316,7 @@ class SQLFORM(FORM):
if order: d['order']=order
if request.vars.keywords: d['keywords']=request.vars.keywords
paginator.append(LI(
A('next',_href=url(vars=d),_class=trap_class())))
A('next',_href=url(vars=d),cid=request.cid)))
elif paginate and paginate<nrows:
npages, reminder = divmod(nrows, paginate)
if reminder:
@@ -2319,7 +2332,7 @@ class SQLFORM(FORM):
d['order'] = order
if request.vars.keywords:
d['keywords'] = request.vars.keywords
return A(name, _href=url(vars=d), _class=trap_class())
return A(name, _href=url(vars=d), cid=request.cid)
NPAGES = 5 # window is 2*NPAGES
if page > NPAGES + 1:
paginator.append(LI(self_link('<<', 0)))
@@ -2329,7 +2342,7 @@ class SQLFORM(FORM):
for p in pages:
if p == page:
paginator.append(LI(A(p + 1, _onclick='return false'),
_class=trap_class('current')))
_class='current'))
else:
paginator.append(LI(self_link(p + 1, p)))
if page < npages - NPAGES:
@@ -2355,6 +2368,7 @@ class SQLFORM(FORM):
continue
if field.type == 'blob':
continue
print row
value = row[str(field)]
maxlength = maxtextlengths.get(str(field), maxtextlength)
if field.represent:
@@ -2598,13 +2612,13 @@ class SQLFORM(FORM):
name = format(db[referee],record)
breadcrumbs.append(
LI(A(T(db[referee]._plural),
_class=trap_class(),
cid=request.cid,
_href=url()),
SPAN(divider, _class='divider'),
_class='w2p_grid_breadcrumb_elem'))
if kwargs.get('details', True):
breadcrumbs.append(
LI(A(name, _class=trap_class(),
LI(A(name, cid=request.cid,
_href=url(args=['view', referee, id])),
SPAN(divider, _class='divider'),
_class='w2p_grid_breadcrumb_elem'))
@@ -2617,7 +2631,7 @@ class SQLFORM(FORM):
# if isinstance(linked_tables, dict):
# linked_tables = linked_tables.get(table._tablename, [])
if linked_tables is None or referee in linked_tables:
field.represent = lambda id, r=None, referee=referee, rep=field.represent: A(callable(rep) and rep(id) or id, _class=trap_class(), _href=url(args=['view', referee, id]))
field.represent = lambda id, r=None, referee=referee, rep=field.represent: A(callable(rep) and rep(id) or id, cid=request.cid, _href=url(args=['view', referee, id]))
except (KeyError, ValueError, TypeError):
redirect(URL(args=table._tablename))
if nargs == len(args) + 1:
@@ -2668,7 +2682,7 @@ class SQLFORM(FORM):
args0 = tablename + '.' + fieldname
links.append(
lambda row, t=t, nargs=nargs, args0=args0:
A(SPAN(t), _class=trap_class(), _href=url(
A(SPAN(t), cid=request.cid, _href=url(
args=[args0, row[id_field_name]])))
grid = SQLFORM.grid(query, args=request.args[:nargs], links=links,
@@ -2679,7 +2693,7 @@ class SQLFORM(FORM):
header = table._plural
next = grid.create_form or grid.update_form or grid.view_form
breadcrumbs.append(LI(
A(T(header), _class=trap_class(),_href=url()),
A(T(header), cid=request.cid,_href=url()),
SPAN(divider, _class='divider') if next else '',
_class='active w2p_grid_breadcrumb_elem'))
if grid.create_form:
@@ -2694,7 +2708,7 @@ class SQLFORM(FORM):
grid.view_form.record))
if next:
breadcrumbs.append(LI(
A(T(header), _class=trap_class(),_href=url()),
A(T(header), cid=request.cid,_href=url()),
_class='active w2p_grid_breadcrumb_elem'))
grid.insert(
0, DIV(UL(*breadcrumbs, **{'_class': breadcrumbs_class}),

View File

@@ -22,6 +22,8 @@ from cStringIO import StringIO
from gluon.utils import simple_hash, web2py_uuid, DIGEST_ALG_BY_SIZE
from gluon.dal import FieldVirtual, FieldMethod
regex_isint = re.compile('^\-?\d+$')
JSONErrors = (NameError, TypeError, ValueError, AttributeError,
KeyError)
try:
@@ -692,15 +694,15 @@ class IS_INT_IN_RANGE(Validator):
>>> IS_INT_IN_RANGE(1,5)(5)
(5, 'enter an integer between 1 and 4')
>>> IS_INT_IN_RANGE(1,5)(3.5)
(3, 'enter an integer between 1 and 4')
(3.5, 'enter an integer between 1 and 4')
>>> IS_INT_IN_RANGE(None,5)('4')
(4, None)
>>> IS_INT_IN_RANGE(None,5)('6')
(6, 'enter an integer less than or equal to 4')
('6', 'enter an integer less than or equal to 4')
>>> IS_INT_IN_RANGE(1,None)('4')
(4, None)
>>> IS_INT_IN_RANGE(1,None)('0')
(0, 'enter an integer greater than or equal to 1')
('0', 'enter an integer greater than or equal to 1')
>>> IS_INT_IN_RANGE()(6)
(6, None)
>>> IS_INT_IN_RANGE()('abc')
@@ -741,24 +743,13 @@ class IS_INT_IN_RANGE(Validator):
% dict(min=self.minimum, max=self.maximum - 1)
def __call__(self, value):
try:
fvalue = float(value)
value = int(value)
if value != fvalue:
return (value, self.error_message)
if self.minimum is None:
if self.maximum is None or value < self.maximum:
return (value, None)
elif self.maximum is None:
if value >= self.minimum:
return (value, None)
elif self.minimum <= value < self.maximum:
return (value, None)
except ValueError:
pass
if value and regex_isint.match(str(value)):
v = int(value)
if ((self.minimum is None or v >= self.minimum) and
(self.maximum is None or v < self.maximum)):
return (v, None)
return (value, self.error_message)
def str2dec(number):
s = str(number)
if not '.' in s:
@@ -839,17 +830,12 @@ class IS_FLOAT_IN_RANGE(Validator):
def __call__(self, value):
try:
if self.dot == '.':
fvalue = float(value)
v = float(value)
else:
fvalue = float(str(value).replace(self.dot, '.'))
if self.minimum is None:
if self.maximum is None or fvalue <= self.maximum:
return (fvalue, None)
elif self.maximum is None:
if fvalue >= self.minimum:
return (fvalue, None)
elif self.minimum <= fvalue <= self.maximum:
return (fvalue, None)
v = float(str(value).replace(self.dot, '.'))
if ((self.minimum is None or v >= self.minimum) and
(self.maximum is None or v <= self.maximum)):
return (v, None)
except (ValueError, TypeError):
pass
return (value, self.error_message)
@@ -948,14 +934,9 @@ class IS_DECIMAL_IN_RANGE(Validator):
v = value
else:
v = decimal.Decimal(str(value).replace(self.dot, '.'))
if self.minimum is None:
if self.maximum is None or v <= self.maximum:
return (v, None)
elif self.maximum is None:
if v >= self.minimum:
return (v, None)
elif self.minimum <= v <= self.maximum:
return (v, None)
if ((self.minimum is None or v >= self.minimum) and
(self.maximum is None or v <= self.maximum)):
return (v, None)
except (ValueError, TypeError, decimal.InvalidOperation):
pass
return (value, self.error_message)

View File

@@ -1005,7 +1005,7 @@ def console():
if not os.path.exists('applications/__init__.py'):
write_file('applications/__init__.py', '')
return (options, args)
return options, args
def check_existent_app(options, appname):
@@ -1022,7 +1022,7 @@ def get_code_for_scheduler(app, options):
code = code % ("','".join(app[1:]))
app_ = app[0]
if not check_existent_app(options, app_):
print "Application '%s' doesn't exist, skipping" % (app_)
print "Application '%s' doesn't exist, skipping" % app_
return None, None
return app_, code

View File

@@ -299,7 +299,7 @@ NameVirtualHost *:80
NameVirtualHost *:443
<VirtualHost *:80>
WSGIDaemonProcess web2py user=apache group=apache
WSGIDaemonProcess web2py user=apache group=apache processes=1 threads=1
WSGIProcessGroup web2py
WSGIScriptAlias / /opt/web-apps/web2py/wsgihandler.py

View File

@@ -301,7 +301,7 @@ NameVirtualHost *:80
NameVirtualHost *:443
<VirtualHost *:80>
WSGIDaemonProcess web2py user=apache group=apache
WSGIDaemonProcess web2py user=apache group=apache processes=1 threads=1
WSGIProcessGroup web2py
WSGIScriptAlias / /opt/web-apps/web2py/wsgihandler.py
WSGIPassAuthorization On

View File

@@ -91,7 +91,7 @@ NameVirtualHost *:443
# within a virtual host container, only WSGI applications associated with
# virtual hosts with the same server name as that virtual host can be
# delegated to that set of daemon processes.
WSGIDaemonProcess web2py user=www-data group=www-data
WSGIDaemonProcess web2py user=www-data group=www-data processes=1 threads=1
<VirtualHost *:80>
WSGIProcessGroup web2py