Compare commits

..

6 Commits

Author SHA1 Message Date
dlage 4228b070d7 fix wrong branch signature. 2020-03-17 16:40:48 +00:00
dlage c4e0ab2316 fix wrong submodule repo url. 2020-03-17 16:29:22 +00:00
dlage ac6494387d Update to the web2py/pydal repo. 2020-03-17 16:26:47 +00:00
dlage f6b9d20fd6 Merge remote-tracking branch 'web2py/master' into ah-stable 2020-03-17 16:24:00 +00:00
dlage 9d934e0e7b updated pydal to master. 2020-03-17 16:22:05 +00:00
dlage a7963a2b0e point pydal to patched version. 2020-01-07 19:22:25 +00:00
44 changed files with 547 additions and 904 deletions
+5 -1
View File
@@ -12,7 +12,11 @@ python:
- '2.7'
- '3.6'
- '3.7'
- '3.8'
- 'pypy3.5'
matrix:
allow_failures:
- python: 'pypy3.5'
install:
- pip install -e .
-4
View File
@@ -1,7 +1,3 @@
## 2.20.1
new makefile to update binaries from Nico Zanferrari
## 2.19.0
- new command line options (Thanks Paolo Pastori)
+1 -58
View File
@@ -45,7 +45,7 @@ rmfiles:
rm -rf applications/examples/uploads/*
src:
### Use semantic versioning
echo 'Version 2.20.4-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
echo 'Version 2.18.5-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
### rm -f all junk files
make clean
# make rmfiles
@@ -104,63 +104,6 @@ win:
mv ../web2py_win/web2py/_ssl.pyd ../web2py_win/web2py/_ssl.pyd.legacy | echo 'done'
cd ../web2py_win; zip -r web2py_win.zip web2py
mv ../web2py_win/web2py_win.zip .
binaries:
echo '' > NEWINSTALL
cp VERSION ../web2py_win_py27/web2py/
cp README.markdown ../web2py_win_py27/web2py/
cp NEWINSTALL ../web2py_win_py27/web2py/
cp LICENSE ../web2py_win_py27/web2py/
cp CHANGELOG ../web2py_win_py27/web2py/
rm -rf ../web2py_win_py27/web2py/gluon
cp -r gluon ../web2py_win_py27/web2py/gluon
rm -rf ../web2py_win_py27/web2py/applications/*
cp -r applications/__init__.py ../web2py_win_py27/web2py/applications/
cp -r applications/admin ../web2py_win_py27/web2py/applications/
cp -r applications/welcome ../web2py_win_py27/web2py/applications/
cp -r applications/examples ../web2py_win_py27/web2py/applications/
cd ../web2py_win_py27; zip -r ../web2py/web2py_win_py27.zip web2py
cp VERSION ../web2py_win_py37/web2py/
cp README.markdown ../web2py_win_py37/web2py/
cp NEWINSTALL ../web2py_win_py37/web2py/
cp LICENSE ../web2py_win_py37/web2py/
cp CHANGELOG ../web2py_win_py37/web2py/
rm -rf ../web2py_win_py37/web2py/gluon
cp -r gluon ../web2py_win_py37/web2py/gluon
rm -rf ../web2py_win_py37/web2py/applications/*
cp -r applications/__init__.py ../web2py_win_py37/web2py/applications/
cp -r applications/admin ../web2py_win_py37/web2py/applications/
cp -r applications/welcome ../web2py_win_py37/web2py/applications/
cp -r applications/examples ../web2py_win_py37/web2py/applications/
cd ../web2py_win_py37; zip -r ../web2py/web2py_win_py37.zip web2py
cp VERSION ../web2py_osx_py27/web2py.app/Contents/MacOS/
cp README.markdown ../web2py_osx_py27/web2py.app/Contents/MacOS/
cp NEWINSTALL ../web2py_osx_py27/web2py.app/Contents/MacOS/
cp LICENSE ../web2py_osx_py27/web2py.app/Contents/MacOS/
cp CHANGELOG ../web2py_osx_py27/web2py.app/Contents/MacOS/
rm -rf ../web2py_osx_py27/web2py.app/Contents/MacOS/gluon
cp -r gluon ../web2py_osx_py27/web2py.app/Contents/MacOS/gluon
rm -rf ../web2py_osx_py27/web2py.app/Contents/MacOS/applications/*
cp -r applications/__init__.py ../web2py_osx_py27/web2py.app/Contents/MacOS/applications/
cp -r applications/admin ../web2py_osx_py27/web2py.app/Contents/MacOS/applications/
cp -r applications/welcome ../web2py_osx_py27/web2py.app/Contents/MacOS/applications/
cp -r applications/examples ../web2py_osx_py27/web2py.app/Contents/MacOS/applications/
cd ../web2py_osx_py27; zip -r ../web2py/web2py_osx_py27.zip web2py.app
cp VERSION ../web2py_osx_py37/web2py.app/Contents/MacOS/
cp README.markdown ../web2py_osx_py37/web2py.app/Contents/MacOS/
cp NEWINSTALL ../web2py_osx_py37/web2py.app/Contents/MacOS/
cp LICENSE ../web2py_osx_py37/web2py.app/Contents/MacOS/
cp CHANGELOG ../web2py_osx_py37/web2py.app/Contents/MacOS/
rm -rf ../web2py_osx_py37/web2py.app/Contents/MacOS/gluon
cp -r gluon ../web2py_osx_py37/web2py.app/Contents/MacOS/gluon
rm -rf ../web2py_osx_py37/web2py.app/Contents/MacOS/applications/*
cp -r applications/__init__.py ../web2py_osx_py37/web2py.app/Contents/MacOS/applications/
cp -r applications/admin ../web2py_osx_py37/web2py.app/Contents/MacOS/applications/
cp -r applications/welcome ../web2py_osx_py37/web2py.app/Contents/MacOS/applications/
cp -r applications/examples ../web2py_osx_py37/web2py.app/Contents/MacOS/applications/
cd ../web2py_osx_py37; zip -r ../web2py/web2py_osx_py37.zip web2py.app
run:
python2.7 web2py.py -a hello
commit:
+1 -1
View File
@@ -1 +1 @@
Version 2.20.4-stable+timestamp.2020.05.02.22.03.36
Version 2.18.5-stable+timestamp.2019.04.07.21.13.59
@@ -194,6 +194,8 @@ def select():
request.vars.query = '%s.%s.%s==%s' % (request.args[0],
match.group('table'), match.group('field'),
match.group('value'))
else:
request.vars.query = session.last_query
query = get_query(request)
if request.vars.start:
start = int(request.vars.start)
@@ -220,6 +222,7 @@ def select():
else:
orderby = '~' + orderby
session.last_orderby = orderby
session.last_query = request.vars.query
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
_name='query', _value=request.vars.query or '', _class='form-control',
requires=IS_NOT_EMPTY(
+1 -1
View File
@@ -1261,7 +1261,7 @@ def plugin():
defines = {}
for m in models:
data = safe_read(apath('%s/models/%s' % (app, m), r=request))
defines[m] = re.findall(REGEX_DEFINE_TABLE, data, re.MULTILINE)
defines[m] = regex_tables.findall(data)
defines[m].sort()
# Get all controllers
+1 -7
View File
@@ -6,10 +6,7 @@ from gluon.fileutils import read_file
from gluon.utils import web2py_uuid
from pydal.contrib import portalocker
# ###########################################################
# ## make sure administrator is on localhost or https,
# ## or from
# ## gluon.settings.global_settings.trusted_lan_prefix
# ## subnet
# ## make sure administrator is on localhost or https
# ###########################################################
@@ -25,9 +22,6 @@ else:
if request.is_https:
session.secure()
elif request.env.trusted_lan_prefix and \
request.client.startswith(request.env.trusted_lan_prefix):
request.is_local = True
elif not request.is_local and not DEMO_MODE:
raise HTTP(200, T('Admin is disabled because insecure channel'))
+1 -1
View File
@@ -82,7 +82,7 @@
<div style="overflow:auto; width:80%;">
{{linkto = lambda f, t, r: URL('update', args=[request.args[0], r, f]) if f else "#"}}
{{upload=URL('download',args=request.args[0])}}
{{=SQLTABLE(rows,linkto,upload,orderby=True,query=query,_class='table table-striped table-bordered sortable')}}
{{=SQLTABLE(rows,linkto,upload,orderby=True,_class='table table-striped table-bordered sortable')}}
</div>
{{pass}}
<br/><br/>
@@ -194,6 +194,8 @@ def select():
request.vars.query = '%s.%s.%s==%s' % (request.args[0],
match.group('table'), match.group('field'),
match.group('value'))
else:
request.vars.query = session.last_query
query = get_query(request)
if request.vars.start:
start = int(request.vars.start)
@@ -220,6 +222,7 @@ def select():
else:
orderby = '~' + orderby
session.last_orderby = orderby
session.last_query = request.vars.query
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
_name='query', _value=request.vars.query or '', _class='form-control',
requires=IS_NOT_EMPTY(
+1 -1
View File
@@ -82,7 +82,7 @@
<div style="overflow:auto; width:80%;">
{{linkto = lambda f, t, r: URL('update', args=[request.args[0], r, f]) if f else "#"}}
{{upload=URL('download',args=request.args[0])}}
{{=SQLTABLE(rows,linkto,upload,orderby=True,query=query,_class='table table-striped table-bordered sortable')}}
{{=SQLTABLE(rows,linkto,upload,orderby=True,_class='table table-striped table-bordered sortable')}}
</div>
{{pass}}
<br/><br/>
@@ -9,8 +9,8 @@
<table class="twothirds">
<thead>
<tr>
<th>For Python 3.7</th>
<th>For Python 2.7</th>
<th>For Normal Users (Py3)</th>
<th>For Legacy Users (Py2)</th>
<th>For Testers</th>
<th>For Developers</th>
</tr>
@@ -18,13 +18,13 @@
<tbody>
<tr>
<td>
<a class="btn btn180 rounded green" href="https://mdipierro.pythonanywhere.com/examples/static/web2py_win_py37.zip">Windows binaries</a>
<a class="btn btn180 rounded green" href="https://mdipierro.pythonanywhere.com/examples/static/web2py_win.zip">Windows binaries</a>
</td>
<td>
<a class="btn btn180 rounded" href="https://mdipierro.pythonanywhere.com/examples/static/web2py_win_py27.zip">Windows binaries</a>
<a class="btn btn180 rounded" href="https://mdipierro.pythonanywhere.com/examples/static/web2py_win_py2.zip">Windows binaries</a>
</td>
<td>
<a class="btn btn180 rounded yellow" href="https://mdipierro.pythonanywhere.com/examples/static/nightly/web2py_win_py27.zip">Windows binaries</a>
<a class="btn btn180 rounded yellow" href="https://mdipierro.pythonanywhere.com/examples/static/nightly/web2py_win.zip">Windows binaries</a>
</td>
<td>
<a class="btn btn180 rounded red" href="http://github.com/web2py/web2py/">Git Repository</a>
@@ -32,13 +32,13 @@
</tr>
<tr>
<td>
<a class="btn btn180 rounded green" href="https://mdipierro.pythonanywhere.com/examples/static/web2py_osx_py37.zip">Mac binaries</a>
<a class="btn btn180 rounded green" href="https://mdipierro.pythonanywhere.com/examples/static/web2py_osx.zip">Mac binaries</a>
</td>
<td>
<a class="btn btn180 rounded" href="https://mdipierro.pythonanywhere.com/examples/static/web2py_osx_py27.zip">Mac binaries</a>
<a class="btn btn180 rounded" href="https://mdipierro.pythonanywhere.com/examples/static/web2py_osx_py2.zip">Mac binaries</a>
</td>
<td>
<a class="btn btn180 rounded yellow" href="https://mdipierro.pythonanywhere.com/examples/static/nightly/web2py_osx_py37.zip">Mac binaries</a>
<a class="btn btn180 rounded yellow" href="https://mdipierro.pythonanywhere.com/examples/static/nightly/web2py_osx.zip">Mac binaries</a>
</td>
<td>
<a class="btn btn180 rounded" href="http://mdipierro.github.io/web2py/web2py_manual_5th.pdf">Manual</a>
+3 -3
View File
@@ -30,9 +30,6 @@ except:
if request.is_https:
session.secure()
elif request.env.trusted_lan_prefix and \
remote_addr.startswith(request.env.trusted_lan_prefix):
request.is_local = True
elif (remote_addr not in hosts) and (remote_addr != '127.0.0.1') and \
(request.function != 'manage'):
raise HTTP(200, T('appadmin is disabled because insecure channel'))
@@ -197,6 +194,8 @@ def select():
request.vars.query = '%s.%s.%s==%s' % (request.args[0],
match.group('table'), match.group('field'),
match.group('value'))
else:
request.vars.query = session.last_query
query = get_query(request)
if request.vars.start:
start = int(request.vars.start)
@@ -223,6 +222,7 @@ def select():
else:
orderby = '~' + orderby
session.last_orderby = orderby
session.last_query = request.vars.query
form = FORM(TABLE(TR(T('Query:'), '', INPUT(_style='width:400px',
_name='query', _value=request.vars.query or '', _class='form-control',
requires=IS_NOT_EMPTY(
+1 -1
View File
@@ -82,7 +82,7 @@
<div style="overflow:auto; width:80%;">
{{linkto = lambda f, t, r: URL('update', args=[request.args[0], r, f]) if f else "#"}}
{{upload=URL('download',args=request.args[0])}}
{{=SQLTABLE(rows,linkto,upload,orderby=True,query=query,_class='table table-striped table-bordered sortable')}}
{{=SQLTABLE(rows,linkto,upload,orderby=True,_class='table table-striped table-bordered sortable')}}
</div>
{{pass}}
<br/><br/>
+4
View File
@@ -10,6 +10,10 @@ environment:
COVERAGE_PROCESS_START: gluon/tests/coverage.ini
PYTHON_ARCH: "64"
- PYTHON: "C:/Python35"
COVERAGE_PROCESS_START: gluon/tests/coverage.ini
PYTHON_ARCH: "64"
- PYTHON: "C:/Python36"
COVERAGE_PROCESS_START: gluon/tests/coverage.ini
PYTHON_ARCH: "64"
+1 -1
View File
@@ -7,7 +7,7 @@ a = Analysis(['web2py.py'],
pathex=['.'],
binaries=[('/System/Library/Frameworks/Tk.framework/Tk', 'tk'), ('/System/Library/Frameworks/Tcl.framework/Tcl', 'tcl')],
datas=[],
hiddenimports=['site-packages', 'argparse', 'cgi', 'cgitb', 'code', 'concurrent', 'concurrent.futures',
hiddenimports=['site-packages', 'cgi', 'cgitb', 'code', 'concurrent', 'concurrent.futures',
'concurrent.futures._base', 'concurrent.futures.process', 'concurrent.futures.thread', 'configparser', 'cProfile', 'csv', 'ctypes.wintypes',
'email.mime', 'email.mime.base', 'email.mime.multipart', 'email.mime.nonmultipart', 'email.mime.text', 'html.parser', 'http.cookies',
'ipaddress', 'imaplib', 'imp', 'json', 'json.decoder', 'json.encoder', 'json.scanner', 'logging.config', 'logging.handlers', 'profile', 'pstats',
+1 -1
View File
@@ -7,7 +7,7 @@ a = Analysis(['web2py.py'],
pathex=['.'],
binaries=[],
datas=[],
hiddenimports=['site-packages', 'argparse', 'cgi', 'cgitb', 'code', 'concurrent', 'concurrent.futures',
hiddenimports=['site-packages', 'cgi', 'cgitb', 'code', 'concurrent', 'concurrent.futures',
'concurrent.futures._base', 'concurrent.futures.process', 'concurrent.futures.thread', 'configparser', 'csv', 'ctypes.wintypes',
'email.mime', 'email.mime.base', 'email.mime.multipart', 'email.mime.nonmultipart', 'email.mime.text', 'html.parser', 'http.cookies',
'ipaddress', 'imp', 'json', 'json.decoder', 'json.encoder', 'json.scanner', 'logging.config', 'logging.handlers', 'profile', 'pstats',
@@ -7,7 +7,7 @@ a = Analysis(['web2py.py'],
pathex=['.'],
binaries=[],
datas=[],
hiddenimports=['site-packages', 'argparse', 'cgi', 'cgitb', 'code', 'concurrent', 'concurrent.futures',
hiddenimports=['site-packages', 'cgi', 'cgitb', 'code', 'concurrent', 'concurrent.futures',
'concurrent.futures._base', 'concurrent.futures.process', 'concurrent.futures.thread', 'configparser', 'csv', 'ctypes.wintypes',
'email.mime', 'email.mime.base', 'email.mime.multipart', 'email.mime.nonmultipart', 'email.mime.text', 'html.parser', 'http.cookies',
'ipaddress', 'imp', 'json', 'json.decoder', 'json.encoder', 'json.scanner', 'logging.config', 'logging.handlers', 'profile', 'pstats',
+27 -33
View File
@@ -44,18 +44,16 @@ See the documentation for WSGIServer/Server for more information.
On most platforms, fcgi will fallback to regular CGI behavior if run in a
non-FastCGI context. If you want to force CGI behavior, set the environment
variable FCGI_FORCE_CGI to "Y" or "y".
Modified for web2py
"""
__author__ = 'Allan Saddi <allan@saddi.com>'
__version__ = '$Revision$'
import cgi
import sys
import os
import signal
import struct
import cStringIO as StringIO
import select
import socket
import errno
@@ -70,15 +68,6 @@ except ImportError:
import dummy_threading as threading
thread_available = False
is_py2 = sys.version_info[0] == 2
if is_py2:
from cgi import escape
import cStringIO as StringIO
else:
from io import StringIO
from html import escape
# Apparently 2.3 doesn't define SHUT_WR? Assume it is 1 in this case.
if not hasattr(socket, 'SHUT_WR'):
socket.SHUT_WR = 1
@@ -245,9 +234,11 @@ class InputStream(object):
total += len(line)
if 0 < sizehint <= total:
break
yield self.readline()
line = self.readline()
return lines
__iter__ = readlines
def __iter__(self):
return self
def next(self):
r = self.readline()
@@ -445,13 +436,13 @@ def encode_pair(name, value):
if nameLength < 128:
s = chr(nameLength)
else:
s = struct.pack('!L', nameLength | 0x80000000)
s = struct.pack('!L', nameLength | 0x80000000L)
valueLength = len(value)
if valueLength < 128:
s += chr(valueLength)
else:
s += struct.pack('!L', valueLength | 0x80000000)
s += struct.pack('!L', valueLength | 0x80000000L)
return s + name + value
@@ -601,7 +592,7 @@ class Request(object):
self._flush()
self._end(appStatus, protocolStatus)
def _end(self, appStatus=0, protocolStatus=FCGI_REQUEST_COMPLETE):
def _end(self, appStatus=0L, protocolStatus=FCGI_REQUEST_COMPLETE):
self._conn.end_request(self, appStatus, protocolStatus)
def _flush(self):
@@ -624,7 +615,7 @@ class CGIRequest(Request):
self.stderr = sys.stderr
self.data = StringIO.StringIO()
def _end(self, appStatus=0, protocolStatus=FCGI_REQUEST_COMPLETE):
def _end(self, appStatus=0L, protocolStatus=FCGI_REQUEST_COMPLETE):
sys.exit(appStatus)
def _flush(self):
@@ -673,7 +664,7 @@ class Connection(object):
self.process_input()
except EOFError:
break
except (select.error, socket.error) as e:
except (select.error, socket.error), e:
if e.errno == errno.EBADF: # Socket was closed by Request.
break
raise
@@ -723,7 +714,7 @@ class Connection(object):
"""
rec.write(self._sock)
def end_request(self, req, appStatus=0,
def end_request(self, req, appStatus=0L,
protocolStatus=FCGI_REQUEST_COMPLETE, remove=True):
"""
End a Request.
@@ -772,7 +763,7 @@ class Connection(object):
if not self._multiplexed and self._requests:
# Can't multiplex requests.
self.end_request(req, 0, FCGI_CANT_MPX_CONN, remove=False)
self.end_request(req, 0L, FCGI_CANT_MPX_CONN, remove=False)
else:
self._requests[inrec.requestId] = req
@@ -863,7 +854,7 @@ class MultiplexedConnection(Connection):
finally:
self._lock.release()
def end_request(self, req, appStatus=0,
def end_request(self, req, appStatus=0L,
protocolStatus=FCGI_REQUEST_COMPLETE, remove=True):
self._lock.acquire()
try:
@@ -958,7 +949,8 @@ class Server(object):
this keyword is ignored; it's not possible to multiplex requests
at all.
"""
self.handler = handler or self.default_handler
if handler is not None:
self.handler = handler
self.maxwrite = maxwrite
if thread_available:
try:
@@ -1085,7 +1077,7 @@ class Server(object):
while self._keepGoing:
try:
r, w, e = select.select([sock], [], [], timeout)
except select.error as e:
except select.error, e:
if e.errno == errno.EINTR:
continue
raise
@@ -1133,13 +1125,13 @@ class Server(object):
self._keepGoing = False
self._hupReceived = reload
def default_handler(self, req):
def handler(self, req):
"""
Default handler, which just raises an exception. Unless a handler
is passed at initialization time, this must be implemented by
a subclass.
"""
raise NotImplementedError(self.__class__.__name__ + '.handler')
raise NotImplementedError, self.__class__.__name__ + '.handler'
def error(self, req):
"""
@@ -1155,7 +1147,8 @@ class WSGIServer(Server):
FastCGI server that supports the Web Server Gateway Interface. See
<http://www.python.org/peps/pep-0333.html>.
"""
def __init__(self, application, environ=None, multithreaded=True, **kw):
def __init__(self, application, environ=None,
multithreaded=True, **kw):
"""
environ, if present, must be a dictionary-like object. Its
contents will be copied into application's environ. Useful
@@ -1163,7 +1156,7 @@ class WSGIServer(Server):
Set multithreaded to False if your application is not MT-safe.
"""
if 'handler'in kw:
if kw.has_key('handler'):
del kw['handler'] # Doesn't make sense to let this through
super(WSGIServer, self).__init__(**kw)
@@ -1177,7 +1170,7 @@ class WSGIServer(Server):
# Used to force single-threadedness
self._app_lock = thread.allocate_lock()
def default_handler(self, req):
def handler(self, req):
"""Special handler for WSGI."""
if req.role != FCGI_RESPONDER:
return FCGI_UNKNOWN_ROLE, 0
@@ -1247,7 +1240,7 @@ class WSGIServer(Server):
try:
if headers_sent:
# Re-raise if too late
raise exc_info[0](exc_info[1], exc_info[2])
raise exc_info[0], exc_info[1], exc_info[2]
finally:
exc_info = None # avoid dangling circular ref
else:
@@ -1311,6 +1304,7 @@ class WSGIServer(Server):
if __name__ == '__main__':
def test_app(environ, start_response):
"""Probably not the most efficient example."""
import cgi
start_response('200 OK', [('Content-Type', 'text/html')])
yield '<html><head><title>Hello World!</title></head>\n' \
'<body>\n' \
@@ -1319,10 +1313,10 @@ if __name__ == '__main__':
names = environ.keys()
names.sort()
for name in names:
yield '<tr><td>%s</td><td>%s</td></tr>\n' % (name, escape(environ[name]))
yield '<tr><td>%s</td><td>%s</td></tr>\n' % (
name, cgi.escape(`environ[name]`))
form = cgi.FieldStorage(fp=environ['wsgi.input'],
environ=environ,
form = cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ,
keep_blank_values=1)
if form.list:
yield '<tr><th colspan="2">Form data</th></tr>'
+1 -1
View File
@@ -109,7 +109,7 @@ def saml2_handler(session, request, config_filename = None, entityid = None):
client = Saml2Client(config_file = config_filename)
if not entityid:
idps = client.metadata.with_descriptor("idpsso")
entityid = list(idps.keys())[0]
entityid = idps.keys()[0]
bindings = [BINDING_HTTP_REDIRECT, BINDING_HTTP_POST]
binding, destination = client.pick_binding(
"single_sign_on_service", bindings, "idpsso", entity_id=entityid)
+8 -13
View File
@@ -15,11 +15,7 @@
from __future__ import unicode_literals
import sys
if sys.version_info[0] < 3:
is_py2 = True
else:
is_py2 = False
if sys.version > '3':
unicode = str
@@ -164,8 +160,7 @@ class SoapDispatcher(object):
# Now we change 'external' and 'model' to the received forms i.e. 'ext' and 'mod'
# After that we know how the client has prefixed additional namespaces
decoded_xml = xml if is_py2 else xml.decode('utf8')
ns = NS_RX.findall(decoded_xml)
ns = NS_RX.findall(xml)
for k, v in ns:
if v in self.namespaces.values():
_ns_reversed[v] = k
@@ -374,23 +369,23 @@ class SoapDispatcher(object):
e['name'] = k
if array:
e[:] = {'minOccurs': "0", 'maxOccurs': "unbounded"}
if v is None:
if v in TYPE_MAP.keys():
t = 'xsd:%s' % TYPE_MAP[v]
elif v is None:
t = 'xsd:anyType'
elif type(v) == list:
elif isinstance(v, list):
n = "ArrayOf%s%s" % (name, k)
l = []
for d in v:
l.extend(d.items())
parse_element(n, l, array=True, complex=True)
t = "tns:%s" % n
elif type(v) == dict:
elif isinstance(v, dict):
n = "%s%s" % (name, k)
parse_element(n, v.items(), complex=True)
t = "tns:%s" % n
elif v in TYPE_MAP:
t = 'xsd:%s' % TYPE_MAP[v]
else:
raise TypeError("unknown type %s for marshalling" % str(v))
raise TypeError("unknonw type %s for marshalling" % str(v))
e.add_attribute('type', t)
parse_element("%s" % method, args and args.items())
+1 -9
View File
@@ -242,15 +242,7 @@ class Request(Storage):
# parse POST variables on POST, PUT, BOTH only in post_vars
if body and not is_json and env.request_method in ('POST', 'PUT', 'DELETE', 'BOTH'):
query_string = env.pop('QUERY_STRING', None)
content_disposition = env.get('HTTP_CONTENT_DISPOSITION')
if content_disposition:
headers = {'content-disposition': content_disposition,
'content-type': env['CONTENT_TYPE'],
'content-length': env['CONTENT_LENGTH'],
}
else:
headers = None
dpost = cgi.FieldStorage(fp=body, environ=env, headers=headers, keep_blank_values=1)
dpost = cgi.FieldStorage(fp=body, environ=env, keep_blank_values=1)
try:
post_vars.update(dpost)
except:
+7 -20
View File
@@ -190,8 +190,7 @@ def URL(a=None,
port=None,
encode_embedded_slash=False,
url_encode=True,
language=None,
hash_extension=True
language=None
):
"""
generates a url '/a/c/f' corresponding to application a, controller c
@@ -340,8 +339,7 @@ def URL(a=None,
if '.' in function:
function, extension = function.rsplit('.', 1)
# only include the extension as part of the variables for the hash if requested
function2 = '%s.%s' % (function, extension or 'html') if hash_extension else function
function2 = '%s.%s' % (function, extension or 'html')
if not (application and controller and function):
raise SyntaxError('not enough information to build the url (%s %s %s)' % (application, controller, function))
@@ -418,7 +416,7 @@ def URL(a=None,
return url
def verifyURL(request, hmac_key=None, hash_vars=True, salt=None, user_signature=None, hash_extension=True):
def verifyURL(request, hmac_key=None, hash_vars=True, salt=None, user_signature=None):
"""
Verifies that a request's args & vars have not been tampered with by the user
@@ -479,19 +477,10 @@ def verifyURL(request, hmac_key=None, hash_vars=True, salt=None, user_signature=
# always include all of the args
other = args and urllib_quote('/' + '/'.join([str(x) for x in args])) or ''
# decide whether the extension should be part of the hash verification
h_extension = request.extension if hash_extension else ''
# only add a period to the extension when it exists otherwise empty
# extensions will fail to validate
if h_extension:
h_extension = '.%s' % (h_extension)
h_args = '/%s/%s/%s%s%s' % (request.application,
h_args = '/%s/%s/%s.%s%s' % (request.application,
request.controller,
request.function,
h_extension,
request.extension,
other)
# but only include those vars specified (allows more flexibility for use with
@@ -1461,10 +1450,8 @@ class SCRIPT(DIV):
(fa, co) = self._xml()
fa = to_bytes(fa)
# no escaping of subcomponents
co = b'\n'.join(map(to_bytes,
# allow xml components (i.e. ASSIGNJS)
map(lambda c: c.xml() if hasattr(c, 'xml') and callable(c.xml) else c,
self.components)))
co = b'\n'.join([to_bytes(component) for component in
self.components])
if co:
# <script [attributes]><!--//--><![CDATA[//><!--
# script body
+20 -19
View File
@@ -56,18 +56,19 @@ create_missing_folders()
# set up logging for subsequent imports
import logging.config
# do not need fancy graphical loggers when served by handler
# (e.g. apache + mod_wsgi), speed up execution
if not global_settings.web2py_runtime_handler:
# attention!, the import Tkinter in messageboxhandler, changes locale ...
import gluon.messageboxhandler
# This needed to prevent exception on Python 2.5:
# NameError: name 'gluon' is not defined
# See http://bugs.python.org/issue1436
logging.gluon = gluon
# so we must restore it! Thanks ozancag
import locale
locale.setlocale(locale.LC_CTYPE, "C") # IMPORTANT, web2py requires locale "C"
# This needed to prevent exception on Python 2.5:
# NameError: name 'gluon' is not defined
# See http://bugs.python.org/issue1436
# attention!, the import Tkinter in messageboxhandler, changes locale ...
import gluon.messageboxhandler
logging.gluon = gluon
# so we must restore it! Thanks ozancag
import locale
locale.setlocale(locale.LC_CTYPE, "C") # IMPORTANT, web2py requires locale "C"
exists = os.path.exists
pjoin = os.path.join
try:
logging.config.fileConfig(abspath("logging.conf"))
@@ -75,9 +76,6 @@ except: # fails on GAE or when logfile is missing
logging.basicConfig()
logger = logging.getLogger("web2py")
exists = os.path.exists
pjoin = os.path.join
from gluon.restricted import RestrictedError
from gluon.http import HTTP, redirect
from gluon.globals import Request, Response, Session
@@ -101,14 +99,17 @@ requests = 0 # gc timer
try:
version_info = read_file(pjoin(global_settings.gluon_parent, 'VERSION'))
web2py_version = global_settings.web2py_version = version_info.split()[-1].strip()
raw_version_string = version_info.split()[-1].strip()
global_settings.web2py_version = raw_version_string
web2py_version = global_settings.web2py_version
except:
raise RuntimeError("Cannot determine web2py version")
# do not need rocket nor HttpServer when served by handler
# (e.g. apache + mod_wsgi), speed up execution and save memory
if not global_settings.web2py_runtime_handler:
try:
from gluon import rocket
except:
if not global_settings.web2py_runtime_gae:
logger.warn('unable to import Rocket')
load_routes()
+394 -607
View File
File diff suppressed because it is too large Load Diff
+1 -5
View File
@@ -23,11 +23,7 @@ HTTP_SERVER_SOFTWARE = '%s Python/%s' % (
BUF_SIZE = 16384
SOCKET_TIMEOUT = 10 # in secs
THREAD_STOP_CHECK_INTERVAL = 1 # in secs, How often should threads check for a server stop message?
if hasattr(sys, 'frozen'):
# py2installer
IS_JYTHON = False
else:
IS_JYTHON = platform.system() == 'Java' # Handle special cases for Jython
IS_JYTHON = platform.system() == 'Java' # Handle special cases for Jython
IGNORE_ERRORS_ON_CLOSE = set([errno.ECONNABORTED, errno.ECONNRESET])
DEFAULT_LISTEN_QUEUE_SIZE = 5
DEFAULT_MIN_THREADS = 10
+1 -1
View File
@@ -84,7 +84,7 @@ def custom_json(o):
elif isinstance(o, decimal.Decimal):
return float(o)
elif isinstance(o, (bytes, bytearray)):
return str(o) if hasattr(str, 'decode') else str(o, encoding='utf-8')
return str(o)
elif isinstance(o, lazyT):
return str(o)
elif isinstance(o, XmlComponent):
-4
View File
@@ -43,7 +43,3 @@ global_settings.is_source = os.path.exists(os.path.join(
global_settings.gluon_parent, 'web2py.py'))
global_settings.is_py2 = PY2
# allow admin app for clients on trusted LAN when over plain http,
# default is to allow only from localhost or when serving https
#global_settings.trusted_lan_prefix = '192.168.0.'
+1 -20
View File
@@ -20,7 +20,6 @@ import logging
import types
import re
import glob
import site
import traceback
import gluon.fileutils as fileutils
from gluon.settings import global_settings
@@ -241,16 +240,13 @@ def run(
if not cron_job and not scheduler_job and \
sys.stdin and not sys.stdin.name == '/dev/null':
confirm = raw_input(
'application %s does not exist, create (y/N)?' % a)
'application %s does not exist, create (y/n)?' % a)
else:
logging.warn('application does not exist and will not be created')
return
if confirm.lower() in ('y', 'yes'):
os.mkdir(adir)
fileutils.create_app(adir)
else:
logging.warn('application folder does not exist and has not been created as requested')
return
if force_migrate:
c = 'appadmin' # Load all models (hack already used for appadmin controller)
@@ -307,11 +303,6 @@ def run(
if import_models:
BaseAdapter.close_all_instances('commit')
except SystemExit:
print(traceback.format_exc())
if import_models:
BaseAdapter.close_all_instances('rollback')
raise
except:
print(traceback.format_exc())
if import_models:
@@ -321,11 +312,6 @@ def run(
exec(python_code, _env)
if import_models:
BaseAdapter.close_all_instances('commit')
except SystemExit:
print(traceback.format_exc())
if import_models:
BaseAdapter.close_all_instances('rollback')
raise
except:
print(traceback.format_exc())
if import_models:
@@ -335,11 +321,6 @@ def run(
execfile("scripts/migrator.py", _env)
if import_models:
BaseAdapter.close_all_instances('commit')
except SystemExit:
print(traceback.format_exc())
if import_models:
BaseAdapter.close_all_instances('rollback')
raise
except:
print(traceback.format_exc())
if import_models:
+9 -13
View File
@@ -99,7 +99,7 @@ class CacheRepresenter(object):
nvalue = field.represent(value, row[field.tablename])
except KeyError:
nvalue = None
if isinstance(field.represent, _repr_ref): # BKR ISSUE/2312 20200422
if isinstance(field, _repr_ref):
cache[field][value] = nvalue
return nvalue
@@ -1330,7 +1330,7 @@ class SQLFORM(FORM):
# - user not trying to upload a new file
# - there is existing file and user is not trying to delete it
# this is because removing the file may not pass validation
for key in list(self.errors):
for key in self.errors.keys():
if key in self.table \
and self.table[key].type == 'upload' \
and request_vars.get(key, None) in (None, '') \
@@ -1501,7 +1501,7 @@ class SQLFORM(FORM):
if readonly and not ignore_rw and not field.readable:
continue
if record and fieldname not in [x.name for x in extra_fields]:
if record:
default = record[fieldname]
else:
default = field.default
@@ -2667,7 +2667,7 @@ class SQLFORM(FORM):
if export_type:
order = request.vars.order or ''
if sortable:
if order:
if order and not order == 'None':
otablename, ofieldname = order.split('~')[-1].split('.', 1)
sort_field = db[otablename][ofieldname]
orderby = sort_field if order[:1] != '~' else ~sort_field
@@ -2800,7 +2800,7 @@ class SQLFORM(FORM):
order = request.vars.order or ''
asc_icon, desc_icon = sorter_icons
if sortable:
if order:
if order and not order == 'None':
otablename, ofieldname = order.split('~')[-1].split('.', 1)
sort_field = db[otablename][ofieldname]
orderby = sort_field if order[:1] != '~' else ~sort_field
@@ -2820,14 +2820,14 @@ class SQLFORM(FORM):
if key == order.lstrip('~'):
if inverted:
if key == order:
marker = asc_icon
key, marker = 'None', asc_icon
else:
key, marker = order[1:], desc_icon
else:
if key == order:
key, marker = '~' + order, asc_icon
else:
marker = desc_icon
key, marker = 'None', desc_icon
elif inverted and key == str(field):
key = '~' + key
header = A(header, marker, _href=url(vars=dict(
@@ -3393,7 +3393,6 @@ class SQLTABLE(TABLE):
linkto: URL (or lambda to generate a URL) to edit individual records
upload: URL to download uploaded files
orderby: Add an orderby link to column headers.
query: Query string to support orderby headers.
headers: dictionary of headers to headers redefinions
headers can also be a string to generate the headers from data
for now only headers="fieldname:capitalize",
@@ -3429,7 +3428,6 @@ class SQLTABLE(TABLE):
linkto=None,
upload=None,
orderby=None,
query='',
headers={},
truncate=16,
columns=None,
@@ -3501,10 +3499,8 @@ class SQLTABLE(TABLE):
attrcol.update(_class=coldict['class'])
row.append(TH(coldict['label'], **attrcol))
elif orderby:
link = th_link + '?orderby=' + c
if query:
link += '&query=' + query
row.append(TH(A(headers.get(c, c), _href=link, cid=cid)))
row.append(TH(A(headers.get(c, c),
_href=th_link + '?orderby=' + c, cid=cid)))
else:
row.append(TH(headers.get(c, re.sub(self.REGEX_ALIAS_MATCH, r'\2', c))))
+1 -1
View File
@@ -188,7 +188,7 @@ class TestBareHelpers(unittest.TestCase):
XML('<h1>HelloWorld</h1>').__repr__())
# bug check for the sanitizer for closing no-close tags
self.assertEqual(XML('<p>Test</p><br/><p>Test</p><br/>', sanitize=True).xml(),
XML('<p>Test</p><br/><p>Test</p><br/>').xml())
XML('<p>Test</p><br /><p>Test</p><br />').xml())
# basic flatten test
self.assertEqual(XML('<p>Test</p>').flatten(), '<p>Test</p>')
self.assertEqual(XML('<p>Test</p>').flatten(render=lambda text, tag, attr: text), '<p>Test</p>')
+10 -15
View File
@@ -816,15 +816,7 @@ class Mail(object):
server.login(*self.settings.login.split(':', 1))
result = server.sendmail(sender, to, payload.as_string())
finally:
# do not want to hide errors raising some exception here
try:
server.quit()
except smtplib.SMTPException:
# ensure to close any socket with SMTP server
try:
server.close()
except Exception:
pass
server.quit()
except Exception as e:
logger.warning('Mail.send failure:%s' % e)
self.result = result
@@ -992,15 +984,15 @@ def addrow(form, a, b, c, style, _id, position=-1):
DIV(b, SPAN(c, _class='inline-help'),
_class='controls'),
_class='control-group', _id=_id))
elif style in ("bootstrap3_inline", "bootstrap4_inline"):
elif style == "bootstrap3_inline":
form[0].insert(position, DIV(LABEL(a, _class='control-label col-sm-3'),
DIV(b, SPAN(c, _class='help-block'),
_class='col-sm-9'),
_class='form-group row', _id=_id))
elif style in ("bootstrap3_stacked", "bootstrap4_stacked"):
_class='form-group', _id=_id))
elif style == "bootstrap3_stacked":
form[0].insert(position, DIV(LABEL(a, _class='control-label'),
b, SPAN(c, _class='help-block'),
_class='form-group row', _id=_id))
_class='form-group', _id=_id))
else:
form[0].insert(position, TR(TD(LABEL(a), _class='w2p_fl'),
TD(b, _class='w2p_fw'),
@@ -3930,7 +3922,7 @@ class Auth(AuthAPI):
return self.has_permission(name, table_name, record_id)
return self.requires(has_permission, otherwise=otherwise)
def requires_signature(self, otherwise=None, hash_vars=True, hash_extension=True):
def requires_signature(self, otherwise=None, hash_vars=True):
"""
Decorator that prevents access to action if not logged in or
if user logged in is not a member of group_id.
@@ -3938,7 +3930,7 @@ class Auth(AuthAPI):
group_id is calculated.
"""
def verify():
return URL.verify(current.request, user_signature=True, hash_vars=hash_vars, hash_extension=True)
return URL.verify(current.request, user_signature=True, hash_vars=hash_vars)
return self.requires(verify, otherwise)
def accessible_query(self, name, table, user_id=None):
@@ -5613,6 +5605,9 @@ class Expose(object):
and file creation under `base`.
"""
# why would this not be callable? but otherwise tests do not pass
if current.session and callable(current.session.forget):
current.session.forget()
self.follow_symlink_out = follow_symlink_out
self.base = self.normalize_path(
base or os.path.join(current.request.folder, 'static'))
+9 -13
View File
@@ -704,9 +704,14 @@ def start():
run_system_tests(options)
if options.quiet:
# mute existing loggers, to do that iterate
# over all loggers (root logger included) and remove
# attached logging.StreamHandler instances currently
# to prevent writes on stdout set a null stream
class NullFile(object):
def write(self, x):
pass
sys.stdout = NullFile()
# but still has to mute existing loggers, to do that iterate
# over all existing loggers (root logger included) and remove
# all attached logging.StreamHandler instances currently
# streaming on sys.stdout or sys.stderr
loggers = [logging.getLogger()]
loggers.extend(logging.Logger.manager.loggerDict.values())
@@ -716,18 +721,9 @@ def start():
if isinstance(h, logging.StreamHandler) and \
h.stream in (sys.stdout, sys.stderr):
l.removeHandler(h)
# this is to avoid the warning
# ``No handlers could be found for logger "..."``
# emitted by logging module when no handler is found
logging.Logger.manager.emittedNoHandlerWarning = 1
# to prevent writes on stdout set a null stream
class NullFile(object):
def write(self, x):
pass
sys.stdout = NullFile()
# NOTE: stderr.write() is still working
elif not options.no_banner:
if not options.no_banner:
# banner
print(ProgramName)
print(ProgramAuthor)
-3
View File
@@ -62,9 +62,6 @@ if not os.path.isdir('applications'):
sys.path = [path] + [p for p in sys.path if not p == path]
from gluon.settings import global_settings
global_settings.web2py_runtime_handler = True
import gluon.main
wsgiref.handlers.CGIHandler().run(gluon.main.wsgibase)
+1 -3
View File
@@ -40,9 +40,6 @@ if not os.path.isdir('applications'):
sys.path = [path] + [p for p in sys.path if not p == path]
from gluon.settings import global_settings
global_settings.web2py_runtime_handler = True
import gluon.main
import gluon.contrib.gateways.fcgi as fcgi
@@ -54,6 +51,7 @@ else:
application = gluon.main.wsgibase
if SOFTCRON:
from gluon.settings import global_settings
global_settings.web2py_crontype = 'soft'
fcgi.WSGIServer(application, bindAddress='/tmp/fcgi.sock').run()
+4 -5
View File
@@ -49,15 +49,14 @@ from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
global_settings.web2py_runtime_handler = True
global_settings.web2py_runtime_gae = True
global_settings.db_sessions = True
if os.environ.get('SERVER_SOFTWARE', '').startswith('Devel'):
global_settings.web2py_runtime = 'gae:development'
DEBUG = True
(global_settings.web2py_runtime, DEBUG) = \
('gae:development', True)
else:
global_settings.web2py_runtime = 'gae:production'
DEBUG = False
(global_settings.web2py_runtime, DEBUG) = \
('gae:production', False)
import gluon.main
-2
View File
@@ -13,8 +13,6 @@ def __ExtensionFactory__():
if not os.path.isdir('applications'):
raise RuntimeError('Running from the wrong folder')
sys.path = [path] + [p for p in sys.path if not p == path]
from gluon.settings import global_settings
global_settings.web2py_runtime_handler = True
import gluon.main
import isapi_wsgi
application = gluon.main.wsgibase
-3
View File
@@ -40,9 +40,6 @@ if not os.path.isdir('applications'):
sys.path = [path] + [p for p in sys.path if not p == path]
from gluon.settings import global_settings
global_settings.web2py_runtime_handler = True
import gluon.main
+1 -3
View File
@@ -53,9 +53,6 @@ if not os.path.isdir('applications'):
sys.path = [path] + [p for p in sys.path if not p == path]
from gluon.settings import global_settings
global_settings.web2py_runtime_handler = True
import gluon.main
# uncomment one of the two imports below depending on the SCGIWSGI server installed
@@ -73,6 +70,7 @@ else:
application = wsgiapp
if SOFTCRON:
from gluon.settings import global_settings
global_settings.web2py_crontype = 'soft'
# uncomment one of the two rows below depending on the SCGIWSGI server installed
-2
View File
@@ -21,8 +21,6 @@ from gevent import monkey
monkey.patch_all()
def run(options):
from gluon.settings import global_settings
global_settings.web2py_runtime_handler = True
import gluon.main
if options.password != '<recycle>':
gluon.main.save_password(options.password, int(options.port))
+1 -3
View File
@@ -26,9 +26,6 @@ if not os.path.isdir('applications'):
sys.path = [path] + [p for p in sys.path if not p == path]
from gluon.settings import global_settings
global_settings.web2py_runtime_handler = True
import gluon.main
if LOGGING:
@@ -39,4 +36,5 @@ else:
application = gluon.main.wsgibase
if SOFTCRON:
from gluon.settings import global_settings
global_settings.web2py_crontype = 'soft'
+12 -12
View File
@@ -41,7 +41,7 @@ from __future__ import with_statement
from gluon import current
from gluon.storage import Storage
from gluon._compat import pickle
from optparse import OptionParser
import datetime
import stat
import time
@@ -62,12 +62,13 @@ class SessionSet(object):
def get(self):
"""Get session files/records."""
raise NotImplementedError()
raise NotImplementedError
def trash(self):
"""Trash expired sessions."""
now = datetime.datetime.now()
for item in self.get():
status = 'OK'
last_visit = item.last_visit_default()
try:
@@ -87,18 +88,16 @@ class SessionSet(object):
if age > self.expiration or not self.expiration:
item.delete()
status = 'trashed'
else:
status = 'OK'
if self.verbose > 1:
print('key: %s' % item)
print('key: %s' % str(item))
print('expiration: %s seconds' % self.expiration)
print('last visit: %s' % last_visit)
print('last visit: %s' % str(last_visit))
print('age: %s seconds' % age)
print('status: %s' % status)
print('')
elif self.verbose > 0:
print('%s %s' % (item, status))
print('%s %s' % (str(item), status))
class SessionSetDb(SessionSet):
@@ -180,8 +179,8 @@ class SessionFile(object):
def get(self):
session = Storage()
with open(self.filename, 'rb') as f:
session.update(pickle.load(f))
with open(self.filename, 'rb+') as f:
session.update(cPickle.load(f))
return session
def last_visit_default(self):
@@ -199,7 +198,8 @@ def total_seconds(delta):
Args:
delta: datetime.timedelta instance.
"""
return (delta.microseconds + (delta.seconds + (delta.days * 86400)) * 1000000) / 1e6
return (delta.microseconds + (delta.seconds + (delta.days * 24 * 3600)) *
10 ** 6) / 10 ** 6
def single_loop(expiration=None, force=False, verbose=False):
if expiration is None:
@@ -216,9 +216,9 @@ def single_loop(expiration=None, force=False, verbose=False):
def main():
"""Main processing."""
from optparse import OptionParser
parser = OptionParser(usage="%%prog [options]\nVersion: %s" % VERSION)
usage = '%prog [options]' + '\nVersion: %s' % VERSION
parser = OptionParser(usage=usage)
parser.add_option('-f', '--force',
action='store_true', dest='force', default=False,
-3
View File
@@ -19,9 +19,6 @@ else:
# process -f (--folder) option
if '-f' in sys.argv:
fi = sys.argv.index('-f')
# maybe session2trash arg
if '-A' in sys.argv and fi > sys.argv.index('-A'):
fi = None
elif '--folder' in sys.argv:
fi = sys.argv.index('--folder')
else: