Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 65ee8d378a | |||
| 98a11a717f | |||
| a5007cc1c4 | |||
| eb4cc8ceed | |||
| 30707c169e | |||
| 06209aff29 | |||
| d23a6e7b1b | |||
| c23e95a9e2 | |||
| d13c5349b6 | |||
| 0ad67ad5c8 | |||
| f875bc1520 | |||
| d51de88096 | |||
| 0e4964308f | |||
| fc7c1bd2de | |||
| cf76978a39 | |||
| 79f64cbe72 | |||
| ae2425d348 | |||
| d3f4c70e79 | |||
| ba30988580 | |||
| db6a06b963 | |||
| 7427258b90 | |||
| 1ece50a988 | |||
| 2720f06789 | |||
| e89103d796 | |||
| 60db14b55b | |||
| 7a7c84993f | |||
| 9eae04d93c | |||
| 2a758d3936 | |||
| 44f2860d58 | |||
| 64c42f7580 | |||
| 777c3053e8 | |||
| 01270ca984 | |||
| 9ccbab19f4 | |||
| a4246c08ac | |||
| c1df6203b0 | |||
| 933e3df9d3 | |||
| 9ffce59ddb | |||
| 97bb26d452 | |||
| ca8b5f6945 | |||
| f70f671324 | |||
| 2a39a883e8 | |||
| bb402ff511 | |||
| 0fa639ec57 | |||
| 3cbaa7eb5f | |||
| e7dc64f114 | |||
| 987263c028 | |||
| 5490480906 | |||
| 3f2b1fe9ca | |||
| 405b0b2e68 | |||
| b76bc6cc03 | |||
| 1b2d0da909 | |||
| 0e6cc87c8b | |||
| 041ec3c63c | |||
| ef9e2dca1f | |||
| b4a945b3ae | |||
| 82cb9011ac | |||
| 1ec6411cfb | |||
| 31b1f746fe | |||
| fa6e9b1caf | |||
| e004215ea6 | |||
| bf0cf06343 | |||
| 4882890a3c | |||
| 6c4649d992 | |||
| 279858b424 | |||
| a633bcde7d | |||
| 88ed162dae | |||
| 6aff6e1132 | |||
| 1ed5117200 | |||
| 97a0eac8ce | |||
| f1dd7f0d89 | |||
| 30a93c49ac | |||
| 7699766ff3 |
+1
-5
@@ -12,11 +12,7 @@ python:
|
||||
- '2.7'
|
||||
- '3.6'
|
||||
- '3.7'
|
||||
- 'pypy3.5'
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- python: 'pypy3.5'
|
||||
- '3.8'
|
||||
|
||||
install:
|
||||
- pip install -e .
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 2.20.1
|
||||
|
||||
new makefile to update binaries from Nico Zanferrari
|
||||
|
||||
## 2.19.0
|
||||
- new command line options (Thanks Paolo Pastori)
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ rmfiles:
|
||||
rm -rf applications/examples/uploads/*
|
||||
src:
|
||||
### Use semantic versioning
|
||||
echo 'Version 2.18.5-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
||||
echo 'Version 2.20.4-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
||||
### rm -f all junk files
|
||||
make clean
|
||||
# make rmfiles
|
||||
@@ -104,6 +104,63 @@ 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 @@
|
||||
Version 2.18.5-stable+timestamp.2019.04.07.21.13.59
|
||||
Version 2.20.4-stable+timestamp.2020.05.02.22.03.36
|
||||
|
||||
@@ -194,8 +194,6 @@ 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)
|
||||
@@ -222,7 +220,6 @@ 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(
|
||||
|
||||
@@ -1261,7 +1261,7 @@ def plugin():
|
||||
defines = {}
|
||||
for m in models:
|
||||
data = safe_read(apath('%s/models/%s' % (app, m), r=request))
|
||||
defines[m] = regex_tables.findall(data)
|
||||
defines[m] = re.findall(REGEX_DEFINE_TABLE, data, re.MULTILINE)
|
||||
defines[m].sort()
|
||||
|
||||
# Get all controllers
|
||||
|
||||
@@ -6,7 +6,10 @@ 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
|
||||
# ## make sure administrator is on localhost or https,
|
||||
# ## or from
|
||||
# ## gluon.settings.global_settings.trusted_lan_prefix
|
||||
# ## subnet
|
||||
# ###########################################################
|
||||
|
||||
|
||||
@@ -22,6 +25,9 @@ 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'))
|
||||
|
||||
|
||||
@@ -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,_class='table table-striped table-bordered sortable')}}
|
||||
{{=SQLTABLE(rows,linkto,upload,orderby=True,query=query,_class='table table-striped table-bordered sortable')}}
|
||||
</div>
|
||||
{{pass}}
|
||||
<br/><br/>
|
||||
|
||||
@@ -194,8 +194,6 @@ 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)
|
||||
@@ -222,7 +220,6 @@ 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(
|
||||
|
||||
@@ -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,_class='table table-striped table-bordered sortable')}}
|
||||
{{=SQLTABLE(rows,linkto,upload,orderby=True,query=query,_class='table table-striped table-bordered sortable')}}
|
||||
</div>
|
||||
{{pass}}
|
||||
<br/><br/>
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
<table class="twothirds">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>For Normal Users (Py3)</th>
|
||||
<th>For Legacy Users (Py2)</th>
|
||||
<th>For Python 3.7</th>
|
||||
<th>For Python 2.7</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.zip">Windows binaries</a>
|
||||
<a class="btn btn180 rounded green" href="https://mdipierro.pythonanywhere.com/examples/static/web2py_win_py37.zip">Windows binaries</a>
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn180 rounded" href="https://mdipierro.pythonanywhere.com/examples/static/web2py_win_py2.zip">Windows binaries</a>
|
||||
<a class="btn btn180 rounded" href="https://mdipierro.pythonanywhere.com/examples/static/web2py_win_py27.zip">Windows binaries</a>
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn180 rounded yellow" href="https://mdipierro.pythonanywhere.com/examples/static/nightly/web2py_win.zip">Windows binaries</a>
|
||||
<a class="btn btn180 rounded yellow" href="https://mdipierro.pythonanywhere.com/examples/static/nightly/web2py_win_py27.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.zip">Mac binaries</a>
|
||||
<a class="btn btn180 rounded green" href="https://mdipierro.pythonanywhere.com/examples/static/web2py_osx_py37.zip">Mac binaries</a>
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn180 rounded" href="https://mdipierro.pythonanywhere.com/examples/static/web2py_osx_py2.zip">Mac binaries</a>
|
||||
<a class="btn btn180 rounded" href="https://mdipierro.pythonanywhere.com/examples/static/web2py_osx_py27.zip">Mac binaries</a>
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn180 rounded yellow" href="https://mdipierro.pythonanywhere.com/examples/static/nightly/web2py_osx.zip">Mac binaries</a>
|
||||
<a class="btn btn180 rounded yellow" href="https://mdipierro.pythonanywhere.com/examples/static/nightly/web2py_osx_py37.zip">Mac binaries</a>
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn180 rounded" href="http://mdipierro.github.io/web2py/web2py_manual_5th.pdf">Manual</a>
|
||||
|
||||
@@ -30,6 +30,9 @@ 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'))
|
||||
@@ -194,8 +197,6 @@ 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)
|
||||
@@ -222,7 +223,6 @@ 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(
|
||||
|
||||
@@ -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,_class='table table-striped table-bordered sortable')}}
|
||||
{{=SQLTABLE(rows,linkto,upload,orderby=True,query=query,_class='table table-striped table-bordered sortable')}}
|
||||
</div>
|
||||
{{pass}}
|
||||
<br/><br/>
|
||||
|
||||
@@ -10,10 +10,6 @@ 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"
|
||||
|
||||
@@ -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', 'cgi', 'cgitb', 'code', 'concurrent', 'concurrent.futures',
|
||||
hiddenimports=['site-packages', 'argparse', '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',
|
||||
|
||||
@@ -7,7 +7,7 @@ a = Analysis(['web2py.py'],
|
||||
pathex=['.'],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=['site-packages', 'cgi', 'cgitb', 'code', 'concurrent', 'concurrent.futures',
|
||||
hiddenimports=['site-packages', 'argparse', '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', 'cgi', 'cgitb', 'code', 'concurrent', 'concurrent.futures',
|
||||
hiddenimports=['site-packages', 'argparse', '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',
|
||||
|
||||
@@ -44,16 +44,18 @@ 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
|
||||
@@ -68,6 +70,15 @@ 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
|
||||
@@ -234,11 +245,9 @@ class InputStream(object):
|
||||
total += len(line)
|
||||
if 0 < sizehint <= total:
|
||||
break
|
||||
line = self.readline()
|
||||
return lines
|
||||
yield self.readline()
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
__iter__ = readlines
|
||||
|
||||
def next(self):
|
||||
r = self.readline()
|
||||
@@ -436,13 +445,13 @@ def encode_pair(name, value):
|
||||
if nameLength < 128:
|
||||
s = chr(nameLength)
|
||||
else:
|
||||
s = struct.pack('!L', nameLength | 0x80000000L)
|
||||
s = struct.pack('!L', nameLength | 0x80000000)
|
||||
|
||||
valueLength = len(value)
|
||||
if valueLength < 128:
|
||||
s += chr(valueLength)
|
||||
else:
|
||||
s += struct.pack('!L', valueLength | 0x80000000L)
|
||||
s += struct.pack('!L', valueLength | 0x80000000)
|
||||
|
||||
return s + name + value
|
||||
|
||||
@@ -592,7 +601,7 @@ class Request(object):
|
||||
self._flush()
|
||||
self._end(appStatus, protocolStatus)
|
||||
|
||||
def _end(self, appStatus=0L, protocolStatus=FCGI_REQUEST_COMPLETE):
|
||||
def _end(self, appStatus=0, protocolStatus=FCGI_REQUEST_COMPLETE):
|
||||
self._conn.end_request(self, appStatus, protocolStatus)
|
||||
|
||||
def _flush(self):
|
||||
@@ -615,7 +624,7 @@ class CGIRequest(Request):
|
||||
self.stderr = sys.stderr
|
||||
self.data = StringIO.StringIO()
|
||||
|
||||
def _end(self, appStatus=0L, protocolStatus=FCGI_REQUEST_COMPLETE):
|
||||
def _end(self, appStatus=0, protocolStatus=FCGI_REQUEST_COMPLETE):
|
||||
sys.exit(appStatus)
|
||||
|
||||
def _flush(self):
|
||||
@@ -664,7 +673,7 @@ class Connection(object):
|
||||
self.process_input()
|
||||
except EOFError:
|
||||
break
|
||||
except (select.error, socket.error), e:
|
||||
except (select.error, socket.error) as e:
|
||||
if e.errno == errno.EBADF: # Socket was closed by Request.
|
||||
break
|
||||
raise
|
||||
@@ -714,7 +723,7 @@ class Connection(object):
|
||||
"""
|
||||
rec.write(self._sock)
|
||||
|
||||
def end_request(self, req, appStatus=0L,
|
||||
def end_request(self, req, appStatus=0,
|
||||
protocolStatus=FCGI_REQUEST_COMPLETE, remove=True):
|
||||
"""
|
||||
End a Request.
|
||||
@@ -763,7 +772,7 @@ class Connection(object):
|
||||
|
||||
if not self._multiplexed and self._requests:
|
||||
# Can't multiplex requests.
|
||||
self.end_request(req, 0L, FCGI_CANT_MPX_CONN, remove=False)
|
||||
self.end_request(req, 0, FCGI_CANT_MPX_CONN, remove=False)
|
||||
else:
|
||||
self._requests[inrec.requestId] = req
|
||||
|
||||
@@ -854,7 +863,7 @@ class MultiplexedConnection(Connection):
|
||||
finally:
|
||||
self._lock.release()
|
||||
|
||||
def end_request(self, req, appStatus=0L,
|
||||
def end_request(self, req, appStatus=0,
|
||||
protocolStatus=FCGI_REQUEST_COMPLETE, remove=True):
|
||||
self._lock.acquire()
|
||||
try:
|
||||
@@ -949,8 +958,7 @@ class Server(object):
|
||||
this keyword is ignored; it's not possible to multiplex requests
|
||||
at all.
|
||||
"""
|
||||
if handler is not None:
|
||||
self.handler = handler
|
||||
self.handler = handler or self.default_handler
|
||||
self.maxwrite = maxwrite
|
||||
if thread_available:
|
||||
try:
|
||||
@@ -1077,7 +1085,7 @@ class Server(object):
|
||||
while self._keepGoing:
|
||||
try:
|
||||
r, w, e = select.select([sock], [], [], timeout)
|
||||
except select.error, e:
|
||||
except select.error as e:
|
||||
if e.errno == errno.EINTR:
|
||||
continue
|
||||
raise
|
||||
@@ -1125,13 +1133,13 @@ class Server(object):
|
||||
self._keepGoing = False
|
||||
self._hupReceived = reload
|
||||
|
||||
def handler(self, req):
|
||||
def default_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):
|
||||
"""
|
||||
@@ -1147,8 +1155,7 @@ 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
|
||||
@@ -1156,7 +1163,7 @@ class WSGIServer(Server):
|
||||
|
||||
Set multithreaded to False if your application is not MT-safe.
|
||||
"""
|
||||
if kw.has_key('handler'):
|
||||
if 'handler'in kw:
|
||||
del kw['handler'] # Doesn't make sense to let this through
|
||||
super(WSGIServer, self).__init__(**kw)
|
||||
|
||||
@@ -1170,7 +1177,7 @@ class WSGIServer(Server):
|
||||
# Used to force single-threadedness
|
||||
self._app_lock = thread.allocate_lock()
|
||||
|
||||
def handler(self, req):
|
||||
def default_handler(self, req):
|
||||
"""Special handler for WSGI."""
|
||||
if req.role != FCGI_RESPONDER:
|
||||
return FCGI_UNKNOWN_ROLE, 0
|
||||
@@ -1240,7 +1247,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:
|
||||
@@ -1304,7 +1311,6 @@ 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' \
|
||||
@@ -1313,10 +1319,10 @@ if __name__ == '__main__':
|
||||
names = environ.keys()
|
||||
names.sort()
|
||||
for name in names:
|
||||
yield '<tr><td>%s</td><td>%s</td></tr>\n' % (
|
||||
name, cgi.escape(`environ[name]`))
|
||||
yield '<tr><td>%s</td><td>%s</td></tr>\n' % (name, 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>'
|
||||
|
||||
@@ -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 = idps.keys()[0]
|
||||
entityid = list(idps.keys())[0]
|
||||
bindings = [BINDING_HTTP_REDIRECT, BINDING_HTTP_POST]
|
||||
binding, destination = client.pick_binding(
|
||||
"single_sign_on_service", bindings, "idpsso", entity_id=entityid)
|
||||
|
||||
@@ -15,7 +15,11 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import sys
|
||||
if sys.version > '3':
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
is_py2 = True
|
||||
else:
|
||||
is_py2 = False
|
||||
unicode = str
|
||||
|
||||
|
||||
@@ -160,7 +164,8 @@ 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
|
||||
|
||||
ns = NS_RX.findall(xml)
|
||||
decoded_xml = xml if is_py2 else xml.decode('utf8')
|
||||
ns = NS_RX.findall(decoded_xml)
|
||||
for k, v in ns:
|
||||
if v in self.namespaces.values():
|
||||
_ns_reversed[v] = k
|
||||
@@ -369,23 +374,23 @@ class SoapDispatcher(object):
|
||||
e['name'] = k
|
||||
if array:
|
||||
e[:] = {'minOccurs': "0", 'maxOccurs': "unbounded"}
|
||||
if v in TYPE_MAP.keys():
|
||||
t = 'xsd:%s' % TYPE_MAP[v]
|
||||
elif v is None:
|
||||
if v is None:
|
||||
t = 'xsd:anyType'
|
||||
elif isinstance(v, list):
|
||||
elif type(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 isinstance(v, dict):
|
||||
elif type(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("unknonw type %s for marshalling" % str(v))
|
||||
raise TypeError("unknown type %s for marshalling" % str(v))
|
||||
e.add_attribute('type', t)
|
||||
|
||||
parse_element("%s" % method, args and args.items())
|
||||
|
||||
+9
-1
@@ -242,7 +242,15 @@ 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)
|
||||
dpost = cgi.FieldStorage(fp=body, environ=env, keep_blank_values=1)
|
||||
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)
|
||||
try:
|
||||
post_vars.update(dpost)
|
||||
except:
|
||||
|
||||
+20
-7
@@ -190,7 +190,8 @@ def URL(a=None,
|
||||
port=None,
|
||||
encode_embedded_slash=False,
|
||||
url_encode=True,
|
||||
language=None
|
||||
language=None,
|
||||
hash_extension=True
|
||||
):
|
||||
"""
|
||||
generates a url '/a/c/f' corresponding to application a, controller c
|
||||
@@ -339,7 +340,8 @@ def URL(a=None,
|
||||
if '.' in function:
|
||||
function, extension = function.rsplit('.', 1)
|
||||
|
||||
function2 = '%s.%s' % (function, extension or 'html')
|
||||
# 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
|
||||
|
||||
if not (application and controller and function):
|
||||
raise SyntaxError('not enough information to build the url (%s %s %s)' % (application, controller, function))
|
||||
@@ -416,7 +418,7 @@ def URL(a=None,
|
||||
return url
|
||||
|
||||
|
||||
def verifyURL(request, hmac_key=None, hash_vars=True, salt=None, user_signature=None):
|
||||
def verifyURL(request, hmac_key=None, hash_vars=True, salt=None, user_signature=None, hash_extension=True):
|
||||
"""
|
||||
Verifies that a request's args & vars have not been tampered with by the user
|
||||
|
||||
@@ -477,10 +479,19 @@ 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 ''
|
||||
h_args = '/%s/%s/%s.%s%s' % (request.application,
|
||||
|
||||
# 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,
|
||||
request.controller,
|
||||
request.function,
|
||||
request.extension,
|
||||
h_extension,
|
||||
other)
|
||||
|
||||
# but only include those vars specified (allows more flexibility for use with
|
||||
@@ -1450,8 +1461,10 @@ class SCRIPT(DIV):
|
||||
(fa, co) = self._xml()
|
||||
fa = to_bytes(fa)
|
||||
# no escaping of subcomponents
|
||||
co = b'\n'.join([to_bytes(component) for component in
|
||||
self.components])
|
||||
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)))
|
||||
if co:
|
||||
# <script [attributes]><!--//--><![CDATA[//><!--
|
||||
# script body
|
||||
|
||||
+19
-20
@@ -56,19 +56,18 @@ create_missing_folders()
|
||||
# set up logging for subsequent imports
|
||||
import logging.config
|
||||
|
||||
# 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
|
||||
# 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"
|
||||
|
||||
try:
|
||||
logging.config.fileConfig(abspath("logging.conf"))
|
||||
@@ -76,6 +75,9 @@ 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
|
||||
@@ -99,17 +101,14 @@ requests = 0 # gc timer
|
||||
|
||||
try:
|
||||
version_info = read_file(pjoin(global_settings.gluon_parent, 'VERSION'))
|
||||
raw_version_string = version_info.split()[-1].strip()
|
||||
global_settings.web2py_version = raw_version_string
|
||||
web2py_version = global_settings.web2py_version
|
||||
web2py_version = global_settings.web2py_version = version_info.split()[-1].strip()
|
||||
except:
|
||||
raise RuntimeError("Cannot determine web2py version")
|
||||
|
||||
try:
|
||||
# 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:
|
||||
from gluon import rocket
|
||||
except:
|
||||
if not global_settings.web2py_runtime_gae:
|
||||
logger.warn('unable to import Rocket')
|
||||
|
||||
load_routes()
|
||||
|
||||
|
||||
+1
-1
Submodule gluon/packages/dal updated: f9c870bb3d...f66fb06813
+1
-1
Submodule gluon/packages/yatl updated: 5deb403a9e...6cb27d5ba6
+607
-394
File diff suppressed because it is too large
Load Diff
+5
-1
@@ -23,7 +23,11 @@ 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?
|
||||
IS_JYTHON = platform.system() == 'Java' # Handle special cases for Jython
|
||||
if hasattr(sys, 'frozen'):
|
||||
# py2installer
|
||||
IS_JYTHON = False
|
||||
else:
|
||||
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
|
||||
|
||||
@@ -84,7 +84,7 @@ def custom_json(o):
|
||||
elif isinstance(o, decimal.Decimal):
|
||||
return float(o)
|
||||
elif isinstance(o, (bytes, bytearray)):
|
||||
return str(o)
|
||||
return str(o) if hasattr(str, 'decode') else str(o, encoding='utf-8')
|
||||
elif isinstance(o, lazyT):
|
||||
return str(o)
|
||||
elif isinstance(o, XmlComponent):
|
||||
|
||||
@@ -43,3 +43,7 @@ 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.'
|
||||
|
||||
+20
-1
@@ -20,6 +20,7 @@ import logging
|
||||
import types
|
||||
import re
|
||||
import glob
|
||||
import site
|
||||
import traceback
|
||||
import gluon.fileutils as fileutils
|
||||
from gluon.settings import global_settings
|
||||
@@ -240,13 +241,16 @@ 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)
|
||||
@@ -303,6 +307,11 @@ 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:
|
||||
@@ -312,6 +321,11 @@ 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:
|
||||
@@ -321,6 +335,11 @@ 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:
|
||||
|
||||
+13
-9
@@ -99,7 +99,7 @@ class CacheRepresenter(object):
|
||||
nvalue = field.represent(value, row[field.tablename])
|
||||
except KeyError:
|
||||
nvalue = None
|
||||
if isinstance(field, _repr_ref):
|
||||
if isinstance(field.represent, _repr_ref): # BKR ISSUE/2312 20200422
|
||||
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 self.errors.keys():
|
||||
for key in list(self.errors):
|
||||
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:
|
||||
if record and fieldname not in [x.name for x in extra_fields]:
|
||||
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 and not order == 'None':
|
||||
if order:
|
||||
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 and not order == 'None':
|
||||
if order:
|
||||
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:
|
||||
key, marker = 'None', asc_icon
|
||||
marker = asc_icon
|
||||
else:
|
||||
key, marker = order[1:], desc_icon
|
||||
else:
|
||||
if key == order:
|
||||
key, marker = '~' + order, asc_icon
|
||||
else:
|
||||
key, marker = 'None', desc_icon
|
||||
marker = desc_icon
|
||||
elif inverted and key == str(field):
|
||||
key = '~' + key
|
||||
header = A(header, marker, _href=url(vars=dict(
|
||||
@@ -3393,6 +3393,7 @@ 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",
|
||||
@@ -3428,6 +3429,7 @@ class SQLTABLE(TABLE):
|
||||
linkto=None,
|
||||
upload=None,
|
||||
orderby=None,
|
||||
query='',
|
||||
headers={},
|
||||
truncate=16,
|
||||
columns=None,
|
||||
@@ -3499,8 +3501,10 @@ class SQLTABLE(TABLE):
|
||||
attrcol.update(_class=coldict['class'])
|
||||
row.append(TH(coldict['label'], **attrcol))
|
||||
elif orderby:
|
||||
row.append(TH(A(headers.get(c, c),
|
||||
_href=th_link + '?orderby=' + c, cid=cid)))
|
||||
link = th_link + '?orderby=' + c
|
||||
if query:
|
||||
link += '&query=' + query
|
||||
row.append(TH(A(headers.get(c, c), _href=link, cid=cid)))
|
||||
else:
|
||||
row.append(TH(headers.get(c, re.sub(self.REGEX_ALIAS_MATCH, r'\2', c))))
|
||||
|
||||
|
||||
@@ -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>')
|
||||
|
||||
+15
-10
@@ -816,7 +816,15 @@ class Mail(object):
|
||||
server.login(*self.settings.login.split(':', 1))
|
||||
result = server.sendmail(sender, to, payload.as_string())
|
||||
finally:
|
||||
server.quit()
|
||||
# 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
|
||||
except Exception as e:
|
||||
logger.warning('Mail.send failure:%s' % e)
|
||||
self.result = result
|
||||
@@ -984,15 +992,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 == "bootstrap3_inline":
|
||||
elif style in ("bootstrap3_inline", "bootstrap4_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', _id=_id))
|
||||
elif style == "bootstrap3_stacked":
|
||||
_class='form-group row', _id=_id))
|
||||
elif style in ("bootstrap3_stacked", "bootstrap4_stacked"):
|
||||
form[0].insert(position, DIV(LABEL(a, _class='control-label'),
|
||||
b, SPAN(c, _class='help-block'),
|
||||
_class='form-group', _id=_id))
|
||||
_class='form-group row', _id=_id))
|
||||
else:
|
||||
form[0].insert(position, TR(TD(LABEL(a), _class='w2p_fl'),
|
||||
TD(b, _class='w2p_fw'),
|
||||
@@ -3922,7 +3930,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):
|
||||
def requires_signature(self, otherwise=None, hash_vars=True, hash_extension=True):
|
||||
"""
|
||||
Decorator that prevents access to action if not logged in or
|
||||
if user logged in is not a member of group_id.
|
||||
@@ -3930,7 +3938,7 @@ class Auth(AuthAPI):
|
||||
group_id is calculated.
|
||||
"""
|
||||
def verify():
|
||||
return URL.verify(current.request, user_signature=True, hash_vars=hash_vars)
|
||||
return URL.verify(current.request, user_signature=True, hash_vars=hash_vars, hash_extension=True)
|
||||
return self.requires(verify, otherwise)
|
||||
|
||||
def accessible_query(self, name, table, user_id=None):
|
||||
@@ -5605,9 +5613,6 @@ 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'))
|
||||
|
||||
+13
-9
@@ -704,14 +704,9 @@ def start():
|
||||
run_system_tests(options)
|
||||
|
||||
if options.quiet:
|
||||
# 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
|
||||
# mute existing loggers, to do that iterate
|
||||
# over all loggers (root logger included) and remove
|
||||
# attached logging.StreamHandler instances currently
|
||||
# streaming on sys.stdout or sys.stderr
|
||||
loggers = [logging.getLogger()]
|
||||
loggers.extend(logging.Logger.manager.loggerDict.values())
|
||||
@@ -721,9 +716,18 @@ 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
|
||||
|
||||
if not options.no_banner:
|
||||
elif not options.no_banner:
|
||||
# banner
|
||||
print(ProgramName)
|
||||
print(ProgramAuthor)
|
||||
|
||||
@@ -62,6 +62,9 @@ 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)
|
||||
|
||||
@@ -40,6 +40,9 @@ 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
|
||||
|
||||
@@ -51,7 +54,6 @@ 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()
|
||||
|
||||
@@ -49,14 +49,15 @@ 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, DEBUG) = \
|
||||
('gae:development', True)
|
||||
global_settings.web2py_runtime = 'gae:development'
|
||||
DEBUG = True
|
||||
else:
|
||||
(global_settings.web2py_runtime, DEBUG) = \
|
||||
('gae:production', False)
|
||||
global_settings.web2py_runtime = 'gae:production'
|
||||
DEBUG = False
|
||||
|
||||
|
||||
import gluon.main
|
||||
|
||||
@@ -13,6 +13,8 @@ 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
|
||||
|
||||
@@ -40,6 +40,9 @@ 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
|
||||
|
||||
|
||||
|
||||
@@ -53,6 +53,9 @@ 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
|
||||
@@ -70,7 +73,6 @@ 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
|
||||
|
||||
@@ -21,6 +21,8 @@ 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))
|
||||
|
||||
@@ -26,6 +26,9 @@ 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:
|
||||
@@ -36,5 +39,4 @@ else:
|
||||
application = gluon.main.wsgibase
|
||||
|
||||
if SOFTCRON:
|
||||
from gluon.settings import global_settings
|
||||
global_settings.web2py_crontype = 'soft'
|
||||
|
||||
+12
-12
@@ -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,13 +62,12 @@ 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:
|
||||
@@ -88,16 +87,18 @@ 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' % str(item))
|
||||
print('key: %s' % item)
|
||||
print('expiration: %s seconds' % self.expiration)
|
||||
print('last visit: %s' % str(last_visit))
|
||||
print('last visit: %s' % last_visit)
|
||||
print('age: %s seconds' % age)
|
||||
print('status: %s' % status)
|
||||
print('')
|
||||
elif self.verbose > 0:
|
||||
print('%s %s' % (str(item), status))
|
||||
print('%s %s' % (item, status))
|
||||
|
||||
|
||||
class SessionSetDb(SessionSet):
|
||||
@@ -179,8 +180,8 @@ class SessionFile(object):
|
||||
|
||||
def get(self):
|
||||
session = Storage()
|
||||
with open(self.filename, 'rb+') as f:
|
||||
session.update(cPickle.load(f))
|
||||
with open(self.filename, 'rb') as f:
|
||||
session.update(pickle.load(f))
|
||||
return session
|
||||
|
||||
def last_visit_default(self):
|
||||
@@ -198,8 +199,7 @@ def total_seconds(delta):
|
||||
Args:
|
||||
delta: datetime.timedelta instance.
|
||||
"""
|
||||
return (delta.microseconds + (delta.seconds + (delta.days * 24 * 3600)) *
|
||||
10 ** 6) / 10 ** 6
|
||||
return (delta.microseconds + (delta.seconds + (delta.days * 86400)) * 1000000) / 1e6
|
||||
|
||||
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
|
||||
|
||||
usage = '%prog [options]' + '\nVersion: %s' % VERSION
|
||||
parser = OptionParser(usage=usage)
|
||||
parser = OptionParser(usage="%%prog [options]\nVersion: %s" % VERSION)
|
||||
|
||||
parser.add_option('-f', '--force',
|
||||
action='store_true', dest='force', default=False,
|
||||
|
||||
Reference in New Issue
Block a user