From 2c9767e50059f78d82c3007108396daf229c2192 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Sat, 13 Oct 2012 09:25:32 -0500 Subject: [PATCH 1/5] fixed issue 1081, conflict betweeen web2py css error and bootstrap error classes, thanks Paolo and lapcchan --- VERSION | 2 +- applications/welcome/static/css/web2py_bootstrap.css | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 857a327b..a89ca156 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.1.0 (2012-10-12 22:16:19) dev +Version 2.1.0 (2012-10-13 09:25:28) dev diff --git a/applications/welcome/static/css/web2py_bootstrap.css b/applications/welcome/static/css/web2py_bootstrap.css index ad3e8385..9c6f9bf8 100644 --- a/applications/welcome/static/css/web2py_bootstrap.css +++ b/applications/welcome/static/css/web2py_bootstrap.css @@ -47,7 +47,7 @@ ul#navbar>.auth_navbar{ } /* form errors message box customization */ div.error_wrapper{margin-bottom:9px;} -div.error{ +div.error_wrapper .error{ border-radius: 4px; -o-border-radius: 4px; -moz-border-radius: 4px; @@ -162,6 +162,14 @@ input[type="text"].input-xlarge,input[type="password"].input-xlarge{width:270px; #recaptcha{min-height:30px;display:inline-block;margin-bottom:0;line-height:30px;vertical-align:middle;} td>#recaptcha{margin-bottom:6px;} div>#recaptcha{margin-bottom:9px;} +div.control-group.error{ +width:auto; +background:transparent; +border:0; +color:inherit; +padding:0; +background-repeat:repeat; +} /*============================================================= OTHER RULES From 4d87a90c10cb1ae0173fd2eb781d67e0709fe958 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Sat, 13 Oct 2012 09:26:53 -0500 Subject: [PATCH 2/5] redis session patch, thanks Niphlod --- VERSION | 2 +- gluon/contrib/redis_session.py | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/VERSION b/VERSION index a89ca156..142289f4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.1.0 (2012-10-13 09:25:28) dev +Version 2.1.0 (2012-10-13 09:26:50) dev diff --git a/gluon/contrib/redis_session.py b/gluon/contrib/redis_session.py index f675313e..e8bacfcd 100644 --- a/gluon/contrib/redis_session.py +++ b/gluon/contrib/redis_session.py @@ -19,8 +19,8 @@ locker = thread.allocate_lock() def RedisSession(*args, **vars): """ Usage example: put in models - - sessiondb = RedisSession('localhost:6379',db=0, debug=True) + from gluon.contrib.redis_session import RedisSession + sessiondb = RedisSession('localhost:6379',db=0, session_expiry=False) session.connect(request, response, db = sessiondb) Simple slip-in storage for session @@ -180,7 +180,10 @@ class MockQuery(object): def update(self, **kwargs): #means that the session has been found and needs an update if self.op == 'eq' and self.field == 'id' and self.value: - return self.db.hmset("%s:%s" % (self.keyprefix, self.value), kwargs) + rtn = self.db.hmset("%s:%s" % (self.keyprefix, self.value), kwargs) + if self.session_expiry: + self.db.expire(key, self.session.expiry) + return rtn class RecordDeleter(object): """Dumb record deleter to support sessions2trash.py""" From 6a18539f7ef0740f39704f069a9969ad56dff84d Mon Sep 17 00:00:00 2001 From: mdipierro Date: Sat, 13 Oct 2012 09:37:41 -0500 Subject: [PATCH 3/5] no more custom_import_install in gaehandler.py --- VERSION | 2 +- gaehandler.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 142289f4..b120875e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.1.0 (2012-10-13 09:26:50) dev +Version 2.1.0 (2012-10-13 09:37:38) dev diff --git a/gaehandler.py b/gaehandler.py index 7557a982..70e52806 100755 --- a/gaehandler.py +++ b/gaehandler.py @@ -83,9 +83,7 @@ def wsgiapp(env, res): if global_settings.web2py_runtime == 'gae:development': gluon.admin.create_missing_folders() - from gluon.custom_import import custom_import_install web2py_path = global_settings.applications_parent # backward compatibility - custom_import_install(web2py_path) return gluon.main.wsgibase(env, res) From fab23d210b43cfe02615fff20851a25883e8bf77 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Sat, 13 Oct 2012 10:16:06 -0500 Subject: [PATCH 4/5] removed un-necessary setup_exe_2.6.py --- VERSION | 2 +- setup_exe_2.6.py | 171 ----------------------------------------------- 2 files changed, 1 insertion(+), 172 deletions(-) delete mode 100644 setup_exe_2.6.py diff --git a/VERSION b/VERSION index b120875e..7b567b6e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.1.0 (2012-10-13 09:37:38) dev +Version 2.1.0 (2012-10-13 10:16:02) dev diff --git a/setup_exe_2.6.py b/setup_exe_2.6.py deleted file mode 100644 index cec07199..00000000 --- a/setup_exe_2.6.py +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -Usage: - Install py2exe: http://sourceforge.net/projects/py2exe/files/ - Copy script to the web2py directory - c:\bin\python26\python build_windows_exe.py py2exe - -Adapted from http://bazaar.launchpad.net/~flavour/sahana-eden/trunk/view/head:/static/scripts/tools/standalone_exe.py -""" - -from distutils.core import setup -import py2exe -from gluon.import_all import base_modules, contributed_modules -from glob import glob -import fnmatch -import os -import shutil -import sys -import re -import zipfile - -# Python base version -python_version = sys.version[:3] - -# List of modules deprecated in python2.6 that are in the above set -py26_deprecated = ['mhlib', 'multifile', 'mimify', 'sets', 'MimeWriter'] - -if python_version == '2.6': - base_modules += ['json', 'multiprocessing'] - base_modules = list(set(base_modules).difference(set(py26_deprecated))) - - -#I don't know if this is even necessary -if python_version == '2.6': - # Python26 compatibility: http://www.py2exe.org/index.cgi/Tutorial#Step52 - try: - shutil.copytree('C:\Bin\Microsoft.VC90.CRT', 'dist/') - except: - print "You MUST copy Microsoft.VC90.CRT folder into the dist directory" - -#read web2py version from VERSION file -web2py_version_line = readlines_file('VERSION')[0] -#use regular expression to get just the version number -v_re = re.compile('[0-9]+\.[0-9]+\.[0-9]+') -web2py_version = v_re.search(web2py_version_line).group(0) - -setup( - console=['web2py.py'], - windows=[{'script':'web2py.py', - 'dest_base':'web2py_no_console' # MUST NOT be just 'web2py' otherwise it overrides the standard web2py.exe - }], - name="web2py", - version=web2py_version, - description="web2py web framework", - author="Massimo DiPierro", - license = "LGPL v3", - data_files=[ - 'ABOUT', - 'LICENSE', - 'VERSION', - 'splashlogo.gif', - 'logging.example.conf', - 'options_std.py', - 'app.example.yaml', - 'queue.example.yaml' - ], - options={'py2exe': { - 'packages': contributed_modules, - 'includes': base_modules, - }}, - ) - -print "web2py binary successfully built" - -#offer to remove Windows OS dlls user is unlikely to be able to distribute -print "The process of building a windows executable often includes copying files that belong to Windows." -delete_ms_files = raw_input("Delete API-MS-Win-* files that are probably unsafe for distribution? (Y/n) ") -if delete_ms_files.lower().startswith("y"): - print "Deleted Microsoft files not licensed for open source distribution" - print "You are still responsible for making sure you have the rights to distribute any other included files!" - #delete the API-MS-Win-Core DLLs - for f in glob ('dist/API-MS-Win-*.dll'): - os.unlink (f) - #then delete some other files belonging to Microsoft - other_ms_files = ['KERNELBASE.dll', 'MPR.dll', 'MSWSOCK.dll', 'POWRPROF.dll'] - for f in other_ms_files: - try: - os.unlink(os.path.join('dist',f)) - except: - print "unable to delete dist/"+f - sys.exit(1) - -#Offer to include applications -copy_apps = raw_input("Include your web2py application(s)? (Y/n) ") -if os.path.exists('dist/applications'): - shutil.rmtree('dist/applications') -if copy_apps.lower().startswith("y"): - shutil.copytree('applications', 'dist/applications') - print "Your application(s) have been added" -else: - shutil.copytree('applications/admin', 'dist/applications/admin') - shutil.copytree('applications/welcome', 'dist/applications/welcome') - shutil.copytree('applications/examples', 'dist/applications/examples') - print "Only web2py's admin/welcome/examples applications have been added" -print "" - -#Offer to copy project's site-packages into dist/site-packages -copy_apps = raw_input("Include your web2py site-packages & scripts folders? (Y/n) ") -if copy_apps.lower().startswith("y"): - #copy site-packages - if os.path.exists('dist/site-packages') - shutil.rmtree('dist/site-packages') - shutil.copytree('site-packages', 'dist/site-packages') - #copy scripts - if os.path.exists('dist/scripts'): - shutil.rmtree('dist/scripts') - shutil.copytree('scripts', 'dist/scripts') -else: - #no worries, web2py will create the (empty) folder first run - print "Skipping site-packages & scripts" - pass - - -print "" - -#borrowed from http://bytes.com/topic/python/answers/851018-how-zip-directory-python-using-zipfile -def recursive_zip(zipf, directory, folder = ""): - for item in os.listdir(directory): - if os.path.isfile(os.path.join(directory, item)): - zipf.write(os.path.join(directory, item), folder + os.sep + item) - elif os.path.isdir(os.path.join(directory, item)): - recursive_zip(zipf, os.path.join(directory, item), folder + os.sep + item) - -create_zip = raw_input("Create a zip file of web2py for Windows (Y/n)? ") -if create_zip.lower().startswith("y"): - #to keep consistent with how official web2py windows zip file is setup, - #create a web2py folder & copy dist's files into it - shutil.copytree('dist','zip_temp/web2py') - #create zip file - zipf = zipfile.ZipFile("web2py_win.zip", "w", compression=zipfile.ZIP_DEFLATED ) - path = 'zip_temp' #just temp so the web2py directory is included in our zip file - recursive_zip(zipf, path) #leave the first folder as None, as path is root. - zipf.close() - shutil.rmtree('zip_temp') - print "Your Windows binary version of web2py can be found in web2py_win.zip" - print "You may extract the archive anywhere and then run web2py/web2py.exe" - - # offer to clear up - print "Since you created a zip file you likely do not need the build, deposit and dist folders used while building binary." - clean_up_files = raw_input("Delete these un-necessary folders/files? (Y/n) ") - if clean_up_files.lower().startswith("y"): - shutil.rmtree('build') - shutil.rmtree('deposit') - shutil.rmtree('dist') - else: - print "Your Windows binary & associated files can also be found in /dist" -else: - #Didn't want zip file created - print "" - print "Creation of web2py Windows binary completed." - print "You should copy the /dist directory and its contents." - print "To run use web2py.exe" -print "Finished!" -print "Enjoy web2py " +web2py_version_line - - - - - From b7b534ccf25b2b5a8658a0d1e6797f21391db337 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Sat, 13 Oct 2012 14:36:20 -0500 Subject: [PATCH 5/5] new tests in test_web, tests static/_1.2.3/... --- VERSION | 2 +- gluon/tests/test_web.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 7b567b6e..35d8d2f4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.1.0 (2012-10-13 10:16:02) dev +Version 2.1.0 (2012-10-13 14:36:14) dev diff --git a/gluon/tests/test_web.py b/gluon/tests/test_web.py index 06cf9a4c..53e965dd 100644 --- a/gluon/tests/test_web.py +++ b/gluon/tests/test_web.py @@ -46,6 +46,18 @@ class TestWeb(unittest.TestCase): client.get('site') client.get('design/welcome') +class TestStaticCacheControl(unittest.TestCase): + def testWebClient(self): + s=WebClient('http://127.0.0.1:8000/welcome/') + s.get('static/js/web2py.js') + assert('expires' not in s.headers) + assert(not s.headers['cache-control'].startswith('max-age')) + text = s.text + s.get('static/_1.2.3/js/web2py.js') + assert(text == s.text) + assert('expires' in s.headers) + assert(s.headers['cache-control'].startswith('max-age')) + if __name__ == '__main__': unittest.main()