Compare commits

...

72 Commits

Author SHA1 Message Date
dlage 65ee8d378a update gluon packages. 2020-11-15 09:50:47 +00:00
dlage 98a11a717f Merge remote-tracking branch 'upstream/master' into dev-ah 2020-11-15 09:45:25 +00:00
mdipierro a5007cc1c4 Merge pull request #2345 from bartkraan/issue/2312
issue/2312
2020-09-20 10:02:07 -07:00
mdipierro eb4cc8ceed Merge pull request #2344 from macneiln/master
Add hash_extension functionality to URLs
2020-09-20 10:00:27 -07:00
mdipierro 30707c169e Merge pull request #2340 from jvanbraekel/master
Fix order keyword value in Grid column sort
2020-09-20 09:59:00 -07:00
bartkraan 06209aff29 issue/2312 2020-09-07 11:47:18 +02:00
macneiln d23a6e7b1b Remove missed period from h_args
Update as part of adding hash_extension functionality.
2020-09-07 20:55:21 +12:00
macneiln c23e95a9e2 Add hash_extension functionality
Add hash_extension functionality so _signature can be verified regardless of the extension.
2020-09-07 19:55:59 +12:00
macneiln d13c5349b6 Add hash_extension variable
Add hash_extension variable to requires_signature function so URL _signature can be verified ignoring the given request extension.
2020-09-07 19:48:31 +12:00
jvanbraekel 0ad67ad5c8 Fix order keyword in Grid column sorting
Remove the order = 'None' and corresponding check.  When order is specified its a string of the form  = (~) tablename.coulumnname , where the optional ~ indicate a descending order.
2020-08-06 15:37:38 +02:00
jvanbraekel f875bc1520 Merge pull request #1 from web2py/master
Merge Web2py  upstream
2020-08-06 15:27:26 +02:00
mdipierro d51de88096 fixed whitespaces 2020-06-24 22:10:09 -07:00
mdipierro 0e4964308f various cleanup in strings and regex, thanks Paolo 2020-06-24 21:49:43 -07:00
mdipierro fc7c1bd2de prevent loading un-necssary modules when using a handled, thanks Paolo 2020-06-22 22:39:28 -07:00
mdipierro cf76978a39 enabled admin/appadmin by default from trusted addresses, thanks Paolo 2020-06-22 22:24:49 -07:00
mdipierro 79f64cbe72 fixed handling of smtplib.SMTPException, thanks Paolo 2020-06-14 00:30:56 -07:00
mdipierro ae2425d348 Merge pull request #2328 from manma83/remove-admin-session-query
remove last_query session in admin to prevent massive join when sorting tables in multiple browser tabs #2326
2020-06-13 23:10:55 -07:00
mdipierro d3f4c70e79 fixed some problems wth widget logging, thanks Paolo Pastori 2020-06-13 23:08:06 -07:00
mdipierro ba30988580 fixed SCRIPT(ASSIGNJS(foo=bar)), thanks Paolo Pastori 2020-06-13 23:06:38 -07:00
Mark Ma db6a06b963 remove last_query session in admin to prevent massive join when sorting tables in multiple browser tabs #2326 2020-06-03 16:16:59 -07:00
mdipierro 7427258b90 Merge branch 'master' of github.com:web2py/web2py 2020-05-31 18:22:26 -07:00
mdipierro 1ece50a988 Better handling of quit in Mail, thanks Paolo Pastori 2020-05-31 18:22:00 -07:00
mdipierro 2720f06789 better session2trash logging 2020-05-31 18:20:05 -07:00
mdipierro e89103d796 Merge pull request #2323 from valq7711/patch-1
fix CL-args processing (-f maybe session2trash arg)
2020-05-13 20:55:01 -07:00
mdipierro 60db14b55b Merge pull request #2319 from jpsteil/patch-1
Update appveyor.yml
2020-05-13 20:54:17 -07:00
mdipierro 7a7c84993f Merge pull request #2316 from jpsteil/master
Proposed fix for issue 2315
2020-05-13 20:53:56 -07:00
mdipierro 9eae04d93c Merge pull request #2313 from nicozanf/missing_app
Fix errors with unwanted new app folder
2020-05-13 20:53:35 -07:00
valq7711 2a758d3936 fix CL-args processing (-f maybe session2trash arg) 2020-05-14 03:10:00 +03:00
Jim Steil 44f2860d58 Update appveyor.yml
Removed Python 3.5 per Leonel's recommendation
2020-05-06 08:25:07 -05:00
Jim Steil 64c42f7580 Update appveyor.yml
Removed Python 3.5 checks per Leonel's recommendation
2020-05-06 08:03:01 -05:00
mdipierro 777c3053e8 version 2.20.4 2020-05-02 22:05:37 -07:00
mdipierro 01270ca984 version 2.20.3 2020-05-02 21:35:30 -07:00
mdipierro 9ccbab19f4 version 2.20.2 2020-05-02 19:56:34 -07:00
mdipierro a4246c08ac version 2.20.2 2020-05-02 19:49:56 -07:00
Jim Steil c1df6203b0 Merge pull request #1 from jpsteil/jpsteil-patch-1
Proposed fix for issue 2315
2020-05-01 14:39:39 -05:00
Jim Steil 933e3df9d3 Proposed fix for issue 2315 2020-05-01 14:33:40 -05:00
Nico Zanferrari 9ffce59ddb Update shell.py 2020-04-27 10:20:11 +02:00
Nico Zanferrari 97bb26d452 Fix errors with unwanted new app folder
Replying 'no' or ENTER when asked for the creation of a missing app folder was not properly managed. It gives IOError on Mac and unwanted behaviour on Win
2020-04-26 22:14:36 +02:00
mdipierro ca8b5f6945 move binaries 2020-04-25 20:52:56 -07:00
mdipierro f70f671324 version 2.20.1 2020-04-25 20:06:03 -07:00
mdipierro 2a39a883e8 Merge branch 'master' of github.com:web2py/web2py 2020-04-25 19:57:31 -07:00
mdipierro bb402ff511 Make binaries 2020-04-25 19:57:01 -07:00
mdipierro 0fa639ec57 Merge pull request #2311 from edersonpeka/patch-1
Converts dict_keys object to list (py3)
2020-04-20 21:39:19 -07:00
Ederson Peka 3cbaa7eb5f Converts dict_keys object to list (py3)
In python 3, keys() method returns a dict_keys object instead of a list. Trying to access the zero index causes an error. Converting the dict_keys object to a list is enough to make it work (and still works in python 2).
2020-04-16 20:42:07 -03:00
mdipierro e7dc64f114 Merge pull request #2309 from flavour/patch-1
Workaround Python 3.x CGI bug which causes #2262
2020-04-15 21:11:36 -07:00
mdipierro 987263c028 Merge pull request #2306 from leonelcamara/patch-33
Fix for undefined regex_tables
2020-04-15 21:11:11 -07:00
Fran Boon 5490480906 Workaround Python 3.x CGI bug which causes #2262
Obviously the client also needs to send a Content-Disposition header for this to work
2020-04-13 16:57:36 +01:00
Leonel Câmara 3f2b1fe9ca Fix for undefined regex_tables 2020-04-10 18:48:30 +01:00
mdipierro 405b0b2e68 Merge pull request #2299 from mbelletti/master
Fix typo harattr instead hasattr for pull request #2297
2020-04-05 18:20:03 -07:00
mdipierro b76bc6cc03 Merge pull request #2295 from nicozanf/master
fix web2py 2.19.1 compatibility with PyInstaller
2020-04-05 18:19:35 -07:00
Massimiliano Belletti 1b2d0da909 Fix typo harattr instead hasattr 2020-03-26 12:40:48 +01:00
mdipierro 0e6cc87c8b Merge pull request #2297 from tyrbonit/patch-1
fix Py3 encoding problem
2020-03-25 21:50:37 -07:00
Igor MSK 041ec3c63c fix Py3 encoding problem
Fix for python 3.6
>>>str(b'123')
>>>"b'123'"
>>>str(b'123', encoding='utf-8')
>>>"123"
2020-03-24 22:33:41 +03:00
Nico Zanferrari ef9e2dca1f pyinstaller compatibility fix
pyinstaller with python 2 on Windows does not like it
2020-03-23 14:01:36 +01:00
Nico Zanferrari b4a945b3ae hidden import needed for PyInstaller's binaries
an explicit 'import site' is needed for having a full functional interactive shell in the PyInstaller's binaries
2020-03-23 13:39:47 +01:00
Nico Zanferrari 82cb9011ac Update for web2py 2.19.1 2020-03-23 12:45:23 +01:00
Nico Zanferrari 1ec6411cfb Update for web2py 2.19.1 2020-03-23 12:44:47 +01:00
Nico Zanferrari 31b1f746fe Update for web2py 2.19.1 2020-03-23 12:43:58 +01:00
mdipierro fa6e9b1caf modified fcgi, hopefully works with py3 2020-03-22 14:06:25 -07:00
mdipierro e004215ea6 fixed 0x80000000L -> 0x80000000 for py3 2020-03-21 18:25:34 -07:00
mdipierro bf0cf06343 version 2.19.1 2020-03-21 13:18:43 -07:00
mdipierro 4882890a3c reverting 88ed162dae 2020-03-21 12:50:11 -07:00
mdipierro 6c4649d992 fixed issue #2217, bs4, thanks romicasal 2020-03-21 12:40:23 -07:00
mdipierro 279858b424 fixed pysimplesoap, fixes issues #2254, thanks pgastinger 2020-03-21 12:29:22 -07:00
mdipierro a633bcde7d Expose should not clear session, was a test, fixes #2257, thanks Martin Mosbeck 2020-03-21 12:21:44 -07:00
mdipierro 88ed162dae fixes #2262, body decode on py3, thanks liuyigh 2020-03-21 12:18:15 -07:00
mdipierro 6aff6e1132 fixes #2271, sqlhtml changing dict, thanks macneiln 2020-03-21 12:11:46 -07:00
mdipierro 1ed5117200 re-raise crtl+c, fixes #2292, thanks nursix 2020-03-21 12:09:39 -07:00
mdipierro 97a0eac8ce test python 3.8 2020-03-21 11:47:28 -07:00
mdipierro f1dd7f0d89 updated pydal to 20200321.1 2020-03-21 11:45:36 -07:00
dlage 30a93c49ac Merge branch 'master' into dev-ah 2019-05-23 14:36:44 +01:00
dlage 7699766ff3 Merge branch 'migrator-pr' into dev-ah 2019-05-22 11:19:32 +01:00
44 changed files with 904 additions and 547 deletions
+1 -5
View File
@@ -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 .
+4
View File
@@ -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)
+58 -1
View File
@@ -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
View File
@@ -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(
+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] = regex_tables.findall(data)
defines[m] = re.findall(REGEX_DEFINE_TABLE, data, re.MULTILINE)
defines[m].sort()
# Get all controllers
+7 -1
View File
@@ -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'))
+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,_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(
+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,_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>
+3 -3
View File
@@ -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(
+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,_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/>
-4
View File
@@ -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"
+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', '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',
+1 -1
View File
@@ -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',
+33 -27
View File
@@ -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>'
+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 = 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)
+13 -8
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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()
+607 -394
View File
File diff suppressed because it is too large Load Diff
+5 -1
View File
@@ -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
+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)
return str(o) if hasattr(str, 'decode') else str(o, encoding='utf-8')
elif isinstance(o, lazyT):
return str(o)
elif isinstance(o, XmlComponent):
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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))))
+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>')
+15 -10
View File
@@ -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
View File
@@ -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)
+3
View File
@@ -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)
+3 -1
View File
@@ -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()
+5 -4
View File
@@ -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
+2
View File
@@ -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
+3
View File
@@ -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
+3 -1
View File
@@ -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
+2
View File
@@ -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))
+3 -1
View File
@@ -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
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,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,
+3
View File
@@ -19,6 +19,9 @@ 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: