From d5749db0cd8a5a67ca9e8b2c255c82e1d04a97a9 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Sun, 14 Oct 2012 18:29:17 -0500 Subject: [PATCH 01/49] cron disabled by default unless -H --- VERSION | 2 +- gluon/widget.py | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/VERSION b/VERSION index 968fa96d..80582709 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.1.0 (2012-10-14 16:40:34) dev +Version 2.1.0 (2012-10-14 18:29:10) dev diff --git a/gluon/widget.py b/gluon/widget.py index 241e9fff..b3bfe65d 100644 --- a/gluon/widget.py +++ b/gluon/widget.py @@ -804,10 +804,10 @@ def console(): default=False, help=msg) - parser.add_option('-N', - '--no-cron', + parser.add_option('-H', + '--run-cron', action='store_true', - dest='nocron', + dest='runcron', default=False, help='do not start cron automatically') @@ -904,7 +904,7 @@ def console(): if options.cronjob: global_settings.cronjob = True # tell the world - options.nocron = True # don't start cron jobs + options.run = False # don't start cron jobs options.plain = True # cronjobs use a plain shell options.nobanner = True options.nogui = True @@ -1083,13 +1083,13 @@ def start(cron=True): return - # ## if -N or not cron disable cron in this *process* + # ## if -H cron is enabled in this *process* # ## if --softcron use softcron # ## use hardcron in all other cases - if cron and not options.nocron and options.softcron: + if cron and options.runcron and options.softcron: print 'Using softcron (but this is not very efficient)' global_settings.web2py_crontype = 'soft' - elif cron and not options.nocron: + elif cron and options.runcron: logger.debug('Starting hardcron...') global_settings.web2py_crontype = 'hard' newcron.hardcron(options.folder).start() From 64151a2c3ec28c7f1822d854acfda253fa01c3cb Mon Sep 17 00:00:00 2001 From: mdipierro Date: Sun, 14 Oct 2012 20:07:54 -0500 Subject: [PATCH 02/49] reverted custom_install tests --- VERSION | 2 +- gluon/custom_import.py | 30 +++++++++++------------------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/VERSION b/VERSION index 80582709..49db9ebe 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.1.0 (2012-10-14 18:29:10) dev +Version 2.1.0 (2012-10-14 20:07:50) dev diff --git a/gluon/custom_import.py b/gluon/custom_import.py index b924ae83..4ab746d8 100644 --- a/gluon/custom_import.py +++ b/gluon/custom_import.py @@ -13,7 +13,7 @@ NATIVE_IMPORTER = __builtin__.__import__ TRACK_CHANGES = False INVALID_MODULES = set(sys.modules.keys()).union(('','gluon','applications','custom_import')) -# backward compatibility API +# backward compatibility API def custom_import_install(): __builtin__.__import__ = custom_importer @@ -22,17 +22,14 @@ def track_changes(track=True): global TRACK_CHANGES TRACK_CHANGES = track -def is_tracking_changes(): +def is_tracking_changes(): return TRACK_CHANGES -class CustomImportException(ImportError): - pass - def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1): """ The web2py custom importer. Like the standard Python importer but it tries to transform import statements as something like - "import applications.app_name.modules.x". + "import applications.app_name.modules.x". If the import failed, fall back on naive_importer """ @@ -46,8 +43,7 @@ def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1): if hasattr(current,'request') \ and level<=0 \ and not name.split('.')[0] in INVALID_MODULES \ - and isinstance(globals, dict): - import_tb = None + and isinstance(globals, dict): try: items = current.request.folder.split(os.path.sep) if not items[-1]: items = items[:-1] @@ -56,26 +52,22 @@ def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1): # import like "import x" or "import x.y" result = None for itemname in name.split("."): + new_mod = base_importer( + modules_prefix, globals,locals, [itemname], level) + try: + result = result or new_mod.__dict__[itemname] + except KeyError, e: + raise ImportError, 'Cannot import module %s' % str(e) modules_prefix += "." + itemname - base_importer( - modules_prefix, globals,locals, [], level) return result else: # import like "from x import a, b, ..." pname = modules_prefix + "." + name return base_importer(pname, globals, locals, fromlist, level) except ImportError, e1: - import_tb = sys.exc_info()[2] - try: - return NATIVE_IMPORTER(name,globals,locals,fromlist,level) - except ImportError, e3: - raise ImportError, e1, import_tb.tb_next # there an import error in the module + pass # the module does not exist except Exception, e2: raise e2 # there is an error in the module - finally: - if import_tb: - import_tb = None - return NATIVE_IMPORTER(name,globals,locals,fromlist,level) From 8607b09e64854f73ccf2050f257115895ffaea63 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 15 Oct 2012 05:33:21 -0500 Subject: [PATCH 03/49] -Y starts cron --- VERSION | 2 +- gluon/widget.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 49db9ebe..295ffe02 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.1.0 (2012-10-14 20:07:50) dev +Version 2.1.0 (2012-10-15 05:33:14) dev diff --git a/gluon/widget.py b/gluon/widget.py index b3bfe65d..af9c2e47 100644 --- a/gluon/widget.py +++ b/gluon/widget.py @@ -804,12 +804,12 @@ def console(): default=False, help=msg) - parser.add_option('-H', + parser.add_option('-Y', '--run-cron', action='store_true', dest='runcron', default=False, - help='do not start cron automatically') + help='start the background cron process') parser.add_option('-J', '--cronjob', From b6429ca5fdbdc826e2fe071da927f5e64065c7bc Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 15 Oct 2012 05:46:57 -0500 Subject: [PATCH 04/49] better errors in custom_import, thanks Michele --- VERSION | 2 +- gluon/custom_import.py | 28 +++++++++++++++++++++------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/VERSION b/VERSION index 295ffe02..cb56b666 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.1.0 (2012-10-15 05:33:14) dev +Version 2.1.0 (2012-10-15 05:46:52) dev diff --git a/gluon/custom_import.py b/gluon/custom_import.py index 4ab746d8..af44308b 100644 --- a/gluon/custom_import.py +++ b/gluon/custom_import.py @@ -11,25 +11,30 @@ from gluon import current NATIVE_IMPORTER = __builtin__.__import__ TRACK_CHANGES = False -INVALID_MODULES = set(sys.modules.keys()).union(('','gluon','applications','custom_import')) +INVALID_MODULES = set(('','gluon','applications','custom_import')) -# backward compatibility API +# backward compatibility API def custom_import_install(): - __builtin__.__import__ = custom_importer + if __builtin__.__import__ != custom_importer: + INVALID_MODULES = INVALID_MODULES.union(sys.modules.keys()) + __builtin__.__import__ = custom_importer def track_changes(track=True): assert track in (True,False), "must be True or False" global TRACK_CHANGES TRACK_CHANGES = track -def is_tracking_changes(): +def is_tracking_changes(): return TRACK_CHANGES +class CustomImportException(ImportError): + pass + def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1): """ The web2py custom importer. Like the standard Python importer but it tries to transform import statements as something like - "import applications.app_name.modules.x". + "import applications.app_name.modules.x". If the import failed, fall back on naive_importer """ @@ -43,7 +48,8 @@ def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1): if hasattr(current,'request') \ and level<=0 \ and not name.split('.')[0] in INVALID_MODULES \ - and isinstance(globals, dict): + and isinstance(globals, dict): + import_tb = None try: items = current.request.folder.split(os.path.sep) if not items[-1]: items = items[:-1] @@ -65,9 +71,17 @@ def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1): pname = modules_prefix + "." + name return base_importer(pname, globals, locals, fromlist, level) except ImportError, e1: - pass # the module does not exist + import_tb = sys.exc_info()[2] + try: + return NATIVE_IMPORTER(name,globals,locals,fromlist,level) + except ImportError, e3: + raise ImportError, e1, import_tb # there an import error in the module except Exception, e2: raise e2 # there is an error in the module + finally: + if import_tb: + import_tb = None + return NATIVE_IMPORTER(name,globals,locals,fromlist,level) From 9b7e944dea7801fa2e8dc259c16c6bd6e85450e6 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 15 Oct 2012 05:55:45 -0500 Subject: [PATCH 05/49] improved custom_inport with app-level track changes --- VERSION | 2 +- gluon/custom_import.py | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/VERSION b/VERSION index cb56b666..9a1203ec 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.1.0 (2012-10-15 05:46:52) dev +Version 2.1.0 (2012-10-15 05:55:41) dev diff --git a/gluon/custom_import.py b/gluon/custom_import.py index af44308b..6db23d2e 100644 --- a/gluon/custom_import.py +++ b/gluon/custom_import.py @@ -10,22 +10,20 @@ import traceback from gluon import current NATIVE_IMPORTER = __builtin__.__import__ -TRACK_CHANGES = False INVALID_MODULES = set(('','gluon','applications','custom_import')) # backward compatibility API def custom_import_install(): if __builtin__.__import__ != custom_importer: - INVALID_MODULES = INVALID_MODULES.union(sys.modules.keys()) + INVALID_MODULES.update(sys.modules.keys()) __builtin__.__import__ = custom_importer def track_changes(track=True): assert track in (True,False), "must be True or False" - global TRACK_CHANGES - TRACK_CHANGES = track + current.request._custom_import_track_changes = track def is_tracking_changes(): - return TRACK_CHANGES + return current.request._custom_import_track_changes class CustomImportException(ImportError): pass @@ -42,7 +40,13 @@ def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1): locals = locals or {} fromlist = fromlist or [] - base_importer = TRACK_IMPORTER if TRACK_CHANGES else NATIVE_IMPORTER + try: + if current.request._custom_import_track_changes: + base_importer = TRACK_IMPORTER + else: + base_importer = NATIVE_IMPORTER + except: # there is no current.request (should never happen) + base_importer = NATIVE_IMPORTER # if not relative and not from applications: if hasattr(current,'request') \ From 8e14d1c92e95f846a2c2866f2f9e6def7a4ff878 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 15 Oct 2012 06:15:33 -0500 Subject: [PATCH 06/49] updated changelog --- CHANGELOG | 42 ++++++++++++++++++++++++++---------------- VERSION | 2 +- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8a8548d1..49a97ad1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,25 +1,35 @@ ## 2.1.0 -- if apps are accidentally deleted there is copy left in deposit folder -- db.table.field.epoch() counts seconds from epoch -- fixed many aith.wiki problems -- better welcome layout, thanks Paolo -- db.define_table(...,redefine=True) -- DAL, Row, and Rows object can now be pickled/unpickled, thanks to zombie DAL. -- admin uses codemirror -- support for auth.wiki(render='html') -- upgraded jQuery 1.8 -- upgraded Bootstrap 2.1 -- fixed problem with dropbox_account.py -- cache.with_prefix(cache.ram,'prefix') -- mail.send(...,sender='Mr X <%(sender)s>') -- allow entropy computation in IS_STRONG and web2py.js, thanks Jonathan and Niphlod -- renamed luon/contrib/comet_messaging.py -> gluon/contrib/websocket_messaging.py -- DAL support for SQL CASE, example: db().select(...query.case('true','false)) +- overall faster web2py +- when apps are deleted, a w2p copy left in deposit folder +- change in cron (it is now disabled by default). removed -N option and introduced -Y. - faster web2py_uuid() and request initialization logic, thanks Michele - static asset management, thanks Niphlod - improved mobile admin - request.requires_https and Auth(secure=True), thanks Yarin and Niphlod +- better custom_import (works per app and is faster), thanks Michele +- redis_sesssion.py, thanks Niphlod +- allow entropy computation in IS_STRONG and web2py.js, thanks Jonathan and Niphlod +- fixed many aith.wiki problems +- support for auth.wiki(render='html') +- better welcome layout, thanks Paolo +- db.define_table(...,redefine=True) +- DAL, Row, and Rows object can now be pickled/unpickled, thanks to zombie DAL. +- admin uses codemirror +- allow syntax auth = Auth(db).define_tables() +- better auth.wiki with preview, thanks Alan +- better auth.impersonate, thanks Alan +- upgraded jQuery 1.8 +- upgraded Bootstrap 2.1 +- fixed problem with dropbox_account.py +- many fixes to cache.ram, cache.disk, memcache and gae_memcache +- cache.with_prefix(cache.ram,'prefix') +- db.table.field.epoch() counts seconds from epoch +- DAL support for SQL CASE, example: db().select(...query.case('true','false)) +- DAL(...,do_connect=False) allows faking connections +- DAL(...,auto_import=True) now retieves some fiel attributes +- mail can specify a sender: mail.send(...,sender='Mr X <%(sender)s>') +- renamed gluon/contrib/comet_messaging.py -> gluon/contrib/websocket_messaging.py ## 2.0.1-11 diff --git a/VERSION b/VERSION index 9a1203ec..e545d9c1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.1.0 (2012-10-15 05:55:41) dev +Version 2.1.0 (2012-10-15 06:15:29) dev From 36810aaccc878d74052e3eb103f738caa7c70f99 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 15 Oct 2012 06:36:44 -0500 Subject: [PATCH 07/49] fixed error for missing driver --- VERSION | 2 +- gluon/dal.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index e545d9c1..206f0fea 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.1.0 (2012-10-15 06:15:29) dev +Version 2.1.0 (2012-10-15 06:36:40) dev diff --git a/gluon/dal.py b/gluon/dal.py index 31e068c6..175e3faa 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -691,7 +691,7 @@ class BaseAdapter(ConnectionPool): self.driver_name = drivers_available[0] self.driver = globals().get(self.driver_name) else: - raise RuntimeError, "no driver available %s", self.drivers + raise RuntimeError, "no driver available %s" % self.drivers def __init__(self, db,uri,pool_size=0, folder=None, db_codec='UTF-8', From c2b6c645ef8d0be46e79bb9cf6497ac83bdf37e5 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 15 Oct 2012 06:40:55 -0500 Subject: [PATCH 08/49] R-2.1.1 --- Makefile | 2 +- VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 0a7acd84..6df4f910 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ update: wget -O gluon/contrib/simplejsonrpc.py http://rad2py.googlecode.com/hg/ide2py/simplejsonrpc.py echo "remember that pymysql was tweaked" src: - echo 'Version 2.1.0 ('`date +%Y-%m-%d\ %H:%M:%S`') dev' > VERSION + echo 'Version 2.1.1 ('`date +%Y-%m-%d\ %H:%M:%S`') stable' > VERSION ### rm -f all junk files make clean ### clean up baisc apps diff --git a/VERSION b/VERSION index 206f0fea..8413750a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.1.0 (2012-10-15 06:36:40) dev +Version 2.1.1 (2012-10-15 06:40:52) stable From 9f7fd68728125d8e8e7488ca2c6658279f29f538 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 15 Oct 2012 07:43:23 -0500 Subject: [PATCH 09/49] better markmin with links in links, thanks Vladyslav --- Makefile | 2 +- VERSION | 2 +- gluon/contrib/markmin/markmin2html.py | 31 +++++++++++++++++++-------- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 6df4f910..8b7bb471 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ update: wget -O gluon/contrib/simplejsonrpc.py http://rad2py.googlecode.com/hg/ide2py/simplejsonrpc.py echo "remember that pymysql was tweaked" src: - echo 'Version 2.1.1 ('`date +%Y-%m-%d\ %H:%M:%S`') stable' > VERSION + echo 'Version 2.1.1 ('`date +%Y-%m-%d\ %H:%M:%S`') dev' > VERSION ### rm -f all junk files make clean ### clean up baisc apps diff --git a/VERSION b/VERSION index 8413750a..c7420dbe 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.1.1 (2012-10-15 06:40:52) stable +Version 2.1.1 (2012-10-15 07:43:19) dev diff --git a/gluon/contrib/markmin/markmin2html.py b/gluon/contrib/markmin/markmin2html.py index 78b29748..94084b0b 100755 --- a/gluon/contrib/markmin/markmin2html.py +++ b/gluon/contrib/markmin/markmin2html.py @@ -545,14 +545,14 @@ regex_bq_headline=re.compile('^(?:(\.+|\++|\-+)(\.)?\s+)?(-{3}-*)$') regex_tq=re.compile('^(-{3}-*)(?::(?P[a-zA-Z][_a-zA-Z\-\d]*)(?:\[(?P

[a-zA-Z][_a-zA-Z\-\d]*)\])?)?$') regex_proto = re.compile(r'(?/=])(?P

\w+):(?P\w+://[\w\d\-+=?%&/:.]+)', re.M) regex_auto = re.compile(r'(?/=])(?P\w+://[\w\d\-+_=?%&/:.]+)',re.M) -regex_link=re.compile(r'('+LINK+r')|\[\[(?P.+?)\]\]') -regex_link_level2=re.compile(r'^(?P\S.*?)?(?:\s+\[(?P.+?)\])?(?:\s+(?P\S+))?(?:\s+(?P

popup))?\s*$') -regex_media_level2=re.compile(r'^(?P\S.*?)?(?:\s+\[(?P.+?)\])?(?:\s+(?P\S+))?\s+(?P

img|IMG|left|right|center|video|audio)(?:\s+(?P\d+px))?\s*$') +regex_link=re.compile(r'('+LINK+r')|\[\[(?P.+?)\]\]',re.S) +regex_link_level2=re.compile(r'^(?P\S.*?)?(?:\s+\[(?P.+?)\])?(?:\s+(?P\S+))?(?:\s+(?P

popup))?\s*$',re.S) +regex_media_level2=re.compile(r'^(?P\S.*?)?(?:\s+\[(?P.+?)\])?(?:\s+(?P\S+))?\s+(?P

img|IMG|left|right|center|video|audio)(?:\s+(?P\d+px))?\s*$',re.S) -regex_markmin_escape = re.compile(r"(\\*)(['`:*~\\[\]{}@\$+\-.#])") -regex_backslash = re.compile(r"\\(['`:*~\\[\]{}@\$+\-.#])") -ttab_in = maketrans("'`:*~\\[]{}@$+-.#", '\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b') -ttab_out = maketrans('\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b',"'`:*~\\[]{}@$+-.#") +regex_markmin_escape = re.compile(r"(\\*)(['`:*~\\[\]{}@\$+\-.#\n])") +regex_backslash = re.compile(r"\\(['`:*~\\[\]{}@\$+\-.#\n])") +ttab_in = maketrans("'`:*~\\[]{}@$+-.#\n", '\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x05') +ttab_out = maketrans('\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x05',"'`:*~\\[]{}@$+-.#\n") def markmin_escape(text): """ insert \\ before markmin control characters: '`:*~[]{}@$ """ @@ -686,6 +686,15 @@ def render(text, >>> render("----\\nhello world\\n----\\n") '

hello world
' + >>> render('[[http://example.com]]') + '

' + + >>> render('[[ http://example.com]]') + '

http://example.com

' + + >>> render('[[bookmark [http://example.com] ]]') + '

http://example.com

' + >>> render('[[this is a link http://example.com]]') '

this is a link

' @@ -701,6 +710,9 @@ def render(text, >>> render("[[Your browser doesn't support