From jinty at codespeak.net Mon Apr 3 00:17:17 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Mon Apr 3 00:17:19 2006 Subject: [z3-checkins] r25241 - z3/sqlos/trunk/src/sqlos Message-ID: <20060402221717.298A3100E1@code0.codespeak.net> Author: jinty Date: Mon Apr 3 00:17:15 2006 New Revision: 25241 Modified: z3/sqlos/trunk/src/sqlos/configure.zcml Log: Oops, didnt run the tests properly, removing the zcml refernce to the removed sybase adapter. Modified: z3/sqlos/trunk/src/sqlos/configure.zcml ============================================================================== --- z3/sqlos/trunk/src/sqlos/configure.zcml (original) +++ z3/sqlos/trunk/src/sqlos/configure.zcml Mon Apr 3 00:17:15 2006 @@ -90,13 +90,6 @@ /> - - - - Author: jinty Date: Mon Apr 3 00:21:40 2006 New Revision: 25242 Added: z3/sqlos/trunk/patch-test.py (contents, props changed) Modified: z3/sqlos/trunk/makefile Log: You should now just be able to download the source and run "make test". if I havnt forgotten somethign that is. Modified: z3/sqlos/trunk/makefile ============================================================================== --- z3/sqlos/trunk/makefile (original) +++ z3/sqlos/trunk/makefile Mon Apr 3 00:21:40 2006 @@ -2,7 +2,8 @@ CSV=${HERE}/csv ZP=${HERE}/../ ZH=${HERE}/../../ -PYTHON=python +PYTHON=python2.4 +z3includes=Zope3/zopeskel/etc/package-includes all : test clean @@ -17,11 +18,16 @@ coverage_sorted : coverage sorted -test : - export PYTHONPATH=${ZP} && cd ${ZH} && $(PYTHON) test.py -vpf --all sqlos - -clean : +.PHONY: clean +clean: find . \( -name '*~' -o -name '*.py[co]' -o -name '*.bak' -o -name '#*#' -o -name '\.#*' \) -exec rm {} \; -print + $(PYTHON) setup.py clean + +.PHONY: realclean +realclean: clean + rm -rf dist + rm -rf build + rm -rf Zope3 reindent : ~/src/reindent.py -r -v . @@ -39,22 +45,26 @@ Zope3: $(MAKE) z3-checkout -Zope3/package-includes/sqlos-meta.zcml: Zope3 includes/sqlos-meta.zcml - cp includes/sqlos-meta.zcml Zope3/package-includes - -Zope3/package-includes/sqlos-configure.zcml: Zope3 includes/sqlos-configure.zcml - cp includes/sqlos-configure.zcml Zope3/package-includes +$(z3includes)/sqlos-%.zcml: includes/sqlos-%.zcml Zope3 + cp $< $@ -Zope3/package-includes/sqlos-ftesting.zcml: Zope3 includes/sqlos-ftesting.zcml - cp includes/sqlos-ftesting.zcml Zope3/package-includes +.PHONY: sqlos-meta +sqlos-meta: $(z3includes)/sqlos-meta.zcml $(z3includes)/sqlos-configure.zcml $(z3includes)/sqlos-ftesting.zcml -.PHONY: z3-build -z3-build: Zope3 +.PHONY: develop +develop: Zope3 sqlos-meta cd Zope3 && $(MAKE) PYTHON=$(PYTHON) inplace + touch Zope3/src/easy-install.pth + PYTHONPATH=Zope3/src $(PYTHON) setup.py develop -S Zope3/src --install-dir Zope3/src -.PHONY: test-dist -test-dist: z3-update z3-build \ - Zope3/package-includes/sqlos-meta.zcml\ - Zope3/package-includes/sqlos-configure.zcml\ - Zope3/package-includes/sqlos-ftesting.zcml - cd releases && $(PYTHON) SQLOS-test.py +.PHONY: patch +patch: + # This is butttt ugly pul hopefully temporary + set - e;\ + if [ `grep 'site.addsitedir(src)' Zope3/test.py -c` == 0 ]; then\ + cat patch-test.py | patch -p0;\ + fi + +.PHONY: testall +test: develop patch + cd Zope3 && $(PYTHON) test.py --test-path=../src -s sqlos Added: z3/sqlos/trunk/patch-test.py ============================================================================== --- (empty file) +++ z3/sqlos/trunk/patch-test.py Mon Apr 3 00:21:40 2006 @@ -0,0 +1,13 @@ +Index: Zope3/test.py +=================================================================== +--- Zope3/test.py (revision 65897) ++++ Zope3/test.py (working copy) +@@ -26,6 +26,8 @@ + # add src to path + src = os.path.join(here, 'src') + sys.path.insert(0, src) # put at beginning to avoid one in site_packages ++import site ++site.addsitedir(src) + + from zope.testing import testrunner + From reebalazs at codespeak.net Mon Apr 3 09:44:25 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Mon Apr 3 09:44:26 2006 Subject: [z3-checkins] r25244 - z3/jsonserver/branch/merge/concatresource/compression Message-ID: <20060403074425.44185100E9@code0.codespeak.net> Author: reebalazs Date: Mon Apr 3 09:44:23 2006 New Revision: 25244 Modified: z3/jsonserver/branch/merge/concatresource/compression/css.py z3/jsonserver/branch/merge/concatresource/compression/javascript.py Log: Has to use safe option for compression Modified: z3/jsonserver/branch/merge/concatresource/compression/css.py ============================================================================== --- z3/jsonserver/branch/merge/concatresource/compression/css.py (original) +++ z3/jsonserver/branch/merge/concatresource/compression/css.py Mon Apr 3 09:44:23 2006 @@ -5,7 +5,7 @@ from thirdparty.packer import CSSPacker -csspacker_full = CSSPacker('full') +csspacker_full = CSSPacker('safe') def compress(data): return csspacker_full.pack(data) Modified: z3/jsonserver/branch/merge/concatresource/compression/javascript.py ============================================================================== --- z3/jsonserver/branch/merge/concatresource/compression/javascript.py (original) +++ z3/jsonserver/branch/merge/concatresource/compression/javascript.py Mon Apr 3 09:44:23 2006 @@ -4,7 +4,7 @@ from thirdparty.packer import JavascriptPacker -jspacker_full = JavascriptPacker('full') +jspacker_full = JavascriptPacker('safe') def compress(data): return jspacker_full.pack(data) From reebalazs at codespeak.net Mon Apr 3 15:59:37 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Mon Apr 3 15:59:38 2006 Subject: [z3-checkins] r25255 - z3/jsonserver/branch/merge/concatresource Message-ID: <20060403135937.83A0C100FB@code0.codespeak.net> Author: reebalazs Date: Mon Apr 3 15:59:35 2006 New Revision: 25255 Modified: z3/jsonserver/branch/merge/concatresource/__init__.py z3/jsonserver/branch/merge/concatresource/concatfileresource.py z3/jsonserver/branch/merge/concatresource/configure.zcml z3/jsonserver/branch/merge/concatresource/interfaces.py Log: Allow utility mechanism to extend list of files - Check if files exist on configuration, to report unexistant resource files on startup. - add the utility hook to allow extend filelist by other components - hack the module to be aliased to under "Products", this allows the product to be imported multiple times. Modified: z3/jsonserver/branch/merge/concatresource/__init__.py ============================================================================== --- z3/jsonserver/branch/merge/concatresource/__init__.py (original) +++ z3/jsonserver/branch/merge/concatresource/__init__.py Mon Apr 3 15:59:35 2006 @@ -2,3 +2,8 @@ Product init ''' +# alias myself to Products, directly +import sys, Products +if not hasattr(Products, 'concatresource'): + # only 1st import is aliased. + Products.concatresource = sys.modules['Products.concatresource'] = sys.modules[globals()['__name__']] Modified: z3/jsonserver/branch/merge/concatresource/concatfileresource.py ============================================================================== --- z3/jsonserver/branch/merge/concatresource/concatfileresource.py (original) +++ z3/jsonserver/branch/merge/concatresource/concatfileresource.py Mon Apr 3 15:59:35 2006 @@ -8,30 +8,81 @@ from zope.interface import implements from interfaces import IContextFile +# we are aliased to Products, hence the following absolute import +from Products.concatresource.interfaces import IConcatResourceAddon from fileresource import File from compression import compress +import time +import zope.component +from zope.component.exceptions import ComponentLookupError class ConcatFiles(object): - 'A resource that concatenates files and compresses the result' + '''A resource that concatenates files and compresses the result + + It is also possible to extend the statically given list via + a utility. + ''' implements(IContextFile) def __init__(self, pathlist, name): # Path is now a list. assert isinstance(pathlist, (list, tuple)) - self.pathlist = pathlist + # check all files, just to raise error if don't exist + for path in pathlist: + file(path, 'rb').close() + # + self.pathlist_base = pathlist self.__name__ = name - # Init a list of files. - self.content = [File(path, name) for path in pathlist] + # markers for pathlist modification + self.pathlist = [] + self.fileslist_changed = None + self.fileslist = [] + def getPathList(self): + 'Gets the extended pathlist' + # we allow the list to be extended via an utility + try: + registry = zope.component.getUtility(IConcatResourceAddon, self.__name__) + except ComponentLookupError: + extend = [] + else: + extend = registry.getAddonFiles() + pathlist = self.pathlist_base + extend + return pathlist + + def getFilesList(self): + 'Gets the list of files' + ## # XXX We have two choices: + ## # 1. We only calculate the list once, on startup + ## # that is, we suppose that the file resource is + ## # called up after the extension reg has been finished + ## # and that it never changes later. + ## # 2. but it also could be like this to allow changes later: + pathlist = self.getPathList() + if pathlist != self.pathlist: + ##if not self.pathlist: + ##pathlist = self.getPathList() + # mark pathlist modification + self.pathlist = pathlist + self.fileslist_changed = time.time() + fileslist = self.fileslist = [File(path, self.__name__) for path in pathlist] + else: + fileslist = self.fileslist + return fileslist + def getLastMod(self): - return max([f.getLastMod() for f in self.content]) + # We take in consideration that the pathlist + # itself could have changed too. + return max([f.getLastMod() for f in self.getFilesList()] + + [self.fileslist_changed]) def getContents(self): - assert self.content, 'Must contain at least one resource.' - result = self.content[0].getContents() + fileslist = self.getFilesList() + assert fileslist, 'Must contain at least one resource.' + result = fileslist[0].getContents() content_type = result['content_type'] data = [result['data']] - for subres in self.content[1:]: + for subres in fileslist[1:]: d = subres.getContents() # all elements must have the same content type. assert d['content_type'] == content_type Modified: z3/jsonserver/branch/merge/concatresource/configure.zcml ============================================================================== --- z3/jsonserver/branch/merge/concatresource/configure.zcml (original) +++ z3/jsonserver/branch/merge/concatresource/configure.zcml Mon Apr 3 15:59:35 2006 @@ -7,6 +7,6 @@ /> - + Modified: z3/jsonserver/branch/merge/concatresource/interfaces.py ============================================================================== --- z3/jsonserver/branch/merge/concatresource/interfaces.py (original) +++ z3/jsonserver/branch/merge/concatresource/interfaces.py Mon Apr 3 15:59:35 2006 @@ -22,3 +22,20 @@ def purgeData(self): 'Purges the cached data' + +class IConcatResourceAddon(Interface): + '''Utility to register addons + + This can be used to dynamically extend components for a given resource. + We don't provide implementation for this here, but other + components can implement this to provide dynamic add-ons. + + The name of the utility should be the name of the resource. + ''' + + def getAddonFiles(request): + '''Returns a list of addon files. + This will be concatenated to the end of the static list. + ''' + + From jinty at codespeak.net Wed Apr 5 14:48:34 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Wed Apr 5 14:48:36 2006 Subject: [z3-checkins] r25377 - z3/sqlos/trunk Message-ID: <20060405124834.C3851101DB@code0.codespeak.net> Author: jinty Date: Wed Apr 5 14:48:32 2006 New Revision: 25377 Added: z3/sqlos/trunk/sampleapp.py (contents, props changed) Modified: z3/sqlos/trunk/makefile Log: Add a sampleapp script that allows people to run the functional testing suite as a sample application. Not quite thoroughly tested yet... Modified: z3/sqlos/trunk/makefile ============================================================================== --- z3/sqlos/trunk/makefile (original) +++ z3/sqlos/trunk/makefile Wed Apr 5 14:48:32 2006 @@ -4,6 +4,7 @@ ZH=${HERE}/../../ PYTHON=python2.4 z3includes=Zope3/zopeskel/etc/package-includes +Z3BRANCH=trunk all : test clean @@ -36,7 +37,7 @@ .PHONY: z3-checkout z3-checkout: - -test -d Zope3 || svn co svn://svn.zope.org/repos/main/Zope3/trunk Zope3 + -test -d Zope3 || svn co svn://svn.zope.org/repos/main/Zope3/$(Z3BRANCH) Zope3 .PHONY: z3-update z3-update: z3-checkout @@ -51,9 +52,12 @@ .PHONY: sqlos-meta sqlos-meta: $(z3includes)/sqlos-meta.zcml $(z3includes)/sqlos-configure.zcml $(z3includes)/sqlos-ftesting.zcml -.PHONY: develop -develop: Zope3 sqlos-meta +.PHONY: Zope3-build +Zope3-build: Zope3 cd Zope3 && $(MAKE) PYTHON=$(PYTHON) inplace + +.PHONY: develop +develop: Zope3-build sqlos-meta touch Zope3/src/easy-install.pth PYTHONPATH=Zope3/src $(PYTHON) setup.py develop -S Zope3/src --install-dir Zope3/src @@ -68,3 +72,11 @@ .PHONY: testall test: develop patch cd Zope3 && $(PYTHON) test.py --test-path=../src -s sqlos + +Zope3/principals.zcml: Zope3 Zope3/sample_principals.zcml + cp Zope3/sample_principals.zcml $@ + +.PHONY: run-sample +run-sample: develop Zope3/principals.zcml + cp includes/sqlos-ftesting.zcml $(z3includes)/sqlos.testing-configure.zcml + sampleapp.py ; rm $(z3includes)/sqlos.testing-configure.zcml Added: z3/sqlos/trunk/sampleapp.py ============================================================================== --- (empty file) +++ z3/sqlos/trunk/sampleapp.py Wed Apr 5 14:48:32 2006 @@ -0,0 +1,79 @@ +#!/usr/bin/env python2.4 +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +"""Start script for Zope3: loads configuration and starts the server. + +$Id: z3.py 40235 2005-11-18 21:30:31Z srichter $ +""" +import os +import sys + +basepath = filter(None, sys.path) + +def run(argv=list(sys.argv)): + + if sys.version_info < ( 2,3,5 ): + print """\ + ERROR: Your python version is not supported by Zope3. + Zope3 needs Python 2.3.5 or greater. You are running:""" + sys.version + sys.exit(1) + + # Refuse to run without principals.zcml + if not os.path.exists('principals.zcml'): + print """\ + ERROR: You need to create principals.zcml + + The file principals.zcml contains your "bootstrap" user + database. You aren't going to get very far without it. Start + by copying sample_principals.zcml and then modify the + example principal and role settings. + """ + sys.exit(1) + + # setting python paths + program = argv[0] + if "--build" in argv: + argv.remove("--build") + from distutils.util import get_platform + PLAT_SPEC = "%s-%s" % (get_platform(), sys.version[0:3]) + src = os.path.join("build", "lib.%s" % PLAT_SPEC) + else: + src = 'src' + + here = os.path.dirname(os.path.abspath(program)) + srcdir = os.path.abspath(src) + sys.path = [srcdir] + basepath + sys.path[:] = [p for p in sys.path if os.path.abspath(p) != here] + + # Register the paths + import site + site.addsitedir(srcdir) + + # setup a subscriber to create the sampleperson tables + def setupTestingTables(event): + from sqlos.testing import sampleperson + sampleperson.createTestingTables() + + from zope.app.appsetup.interfaces import IDatabaseOpenedEvent + from zope.component import getGlobalSiteManager + gsm = getGlobalSiteManager() + gsm.subscribe([IDatabaseOpenedEvent], None, setupTestingTables) + + from zope.app.twisted.main import main + main(argv[1:]) + + +if __name__ == '__main__': + os.chdir('Zope3') + run() From jinty at codespeak.net Wed Apr 5 23:09:42 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Wed Apr 5 23:09:44 2006 Subject: [z3-checkins] r25418 - z3/sqlos/trunk/src/sqlos Message-ID: <20060405210942.D4A8410238@code0.codespeak.net> Author: jinty Date: Wed Apr 5 23:09:40 2006 New Revision: 25418 Modified: z3/sqlos/trunk/src/sqlos/configure.zcml Log: Remove the option to add a SQLObject container. It is really useless as it can contain nothing. Modified: z3/sqlos/trunk/src/sqlos/configure.zcml ============================================================================== --- z3/sqlos/trunk/src/sqlos/configure.zcml (original) +++ z3/sqlos/trunk/src/sqlos/configure.zcml Wed Apr 5 23:09:40 2006 @@ -5,13 +5,6 @@ - - @@ -47,6 +40,8 @@ factory=".container.SQLObjectNameChooser" /> + + Author: jinty Date: Wed Apr 5 23:26:55 2006 New Revision: 25420 Modified: z3/sqlos/trunk/src/sqlos/container.py z3/sqlos/trunk/src/sqlos/ftests/adding.txt z3/sqlos/trunk/src/sqlos/testing/sampleperson.py Log: Proibit the sample people (almost like flower people) from being added to any container but a IPersonContainer. Also, unrelatedly, make an event subscriber that will create the testing tables. Modified: z3/sqlos/trunk/src/sqlos/container.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/container.py (original) +++ z3/sqlos/trunk/src/sqlos/container.py Wed Apr 5 23:26:55 2006 @@ -59,13 +59,14 @@ class SQLObjectNameChooser(NameChooser): - + # XXX: This needs unit tests... + def chooseName(self, name, obj): if ISQLObject.providedBy(obj): # Look for the SQLObject class our object is from, so get all # allowed factories for name, factory in zapi.getFactoriesFor(ISQLObject): - if checkFactory(self, None, factory): + if checkFactory(self.context, None, factory): # get the sqlobject class utility = zapi.queryUtility(IISQLObject, name) if utility is None: Modified: z3/sqlos/trunk/src/sqlos/ftests/adding.txt ============================================================================== --- z3/sqlos/trunk/src/sqlos/ftests/adding.txt (original) +++ z3/sqlos/trunk/src/sqlos/ftests/adding.txt Wed Apr 5 23:26:55 2006 @@ -19,6 +19,8 @@ Go to the main interface and add a SQLObject MultiContainer >>> browser.open('http://localhost/manage') + >>> 'SamplePerson' not in str(browser.contents) + True >>> browser.getLink('SQLObject Multi Container').click() >>> browser.getControl(name='new_value').value = 'multicontainer1' >>> browser.getControl('Apply').click() Modified: z3/sqlos/trunk/src/sqlos/testing/sampleperson.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/testing/sampleperson.py (original) +++ z3/sqlos/trunk/src/sqlos/testing/sampleperson.py Wed Apr 5 23:26:55 2006 @@ -1,6 +1,6 @@ from sqlobject import * import transaction -from zope.interface import implements, classProvides +from zope.interface import implements, classProvides, Interface from zope.schema import TextLine, Text, Datetime from zope.app.container import constraints @@ -9,6 +9,10 @@ from sqlos.interfaces.container import ISQLObjectContainer from sqlos.container import SQLObjectContainer, SQLIsolatedContainer +def createTestingTablesSubscriber(obj): + # An event subscriber that can be used to create the testing tables + createTestingTables() + def createTestingTables(): """Creates the tables of the SQLObject calsses defined here.""" transaction.get().commit() @@ -36,18 +40,14 @@ description=u"The user's password") -class SamplePerson(SQLOS): - - implements(IPerson) +class IPersonContainer(ISQLObjectContainer): - fullname = StringCol(length=50, notNull=1) - username = StringCol(length=20, notNull=1) - password = StringCol(length=20, notNull=1) + constraints.contains(IPerson) -class IPersonContainer(ISQLObjectContainer): +class IPersonContained(Interface): - constraints.contains(IPerson) + constraints.containers(IPersonContainer) class SamplePersonContainer(SQLObjectContainer): @@ -55,6 +55,15 @@ implements(IPersonContainer) +class SamplePerson(SQLOS): + + implements(IPerson, IPersonContained) + + fullname = StringCol(length=50, notNull=1) + username = StringCol(length=20, notNull=1) + password = StringCol(length=20, notNull=1) + + class SampleIsolatedPerson(SQLOS): classProvides(IISQLObjectIsolated) @@ -119,7 +128,7 @@ owner = StringCol(length=20, notNull=1) -class IMultiContainer(ISQLObjectContainer): +class IMultiContainer(IPersonContainer): constraints.contains(IDog, IPerson) From jinty at codespeak.net Wed Apr 5 23:28:49 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Wed Apr 5 23:28:50 2006 Subject: [z3-checkins] r25422 - in z3/sqlos/trunk: . includes src/sqlos Message-ID: <20060405212849.0F21D10238@code0.codespeak.net> Author: jinty Date: Wed Apr 5 23:28:44 2006 New Revision: 25422 Added: z3/sqlos/trunk/includes/sqlos.ftesting-configure.zcml - copied, changed from r25354, z3/sqlos/trunk/includes/sqlos-ftesting.zcml z3/sqlos/trunk/src/sqlos/sampleapp.zcml (contents, props changed) Removed: z3/sqlos/trunk/patch-test.py z3/sqlos/trunk/sampleapp.py Modified: z3/sqlos/trunk/makefile z3/sqlos/trunk/src/sqlos/README.txt Log: Re-do the sample application in a better way and actually document it. Copied: z3/sqlos/trunk/includes/sqlos.ftesting-configure.zcml (from r25354, z3/sqlos/trunk/includes/sqlos-ftesting.zcml) ============================================================================== --- z3/sqlos/trunk/includes/sqlos-ftesting.zcml (original) +++ z3/sqlos/trunk/includes/sqlos.ftesting-configure.zcml Wed Apr 5 23:28:44 2006 @@ -1 +1 @@ - + Modified: z3/sqlos/trunk/makefile ============================================================================== --- z3/sqlos/trunk/makefile (original) +++ z3/sqlos/trunk/makefile Wed Apr 5 23:28:44 2006 @@ -30,11 +30,6 @@ rm -rf build rm -rf Zope3 -reindent : - ~/src/reindent.py -r -v . - -reindent_clean : reindent clean - .PHONY: z3-checkout z3-checkout: -test -d Zope3 || svn co svn://svn.zope.org/repos/main/Zope3/$(Z3BRANCH) Zope3 @@ -46,7 +41,7 @@ Zope3: $(MAKE) z3-checkout -$(z3includes)/sqlos-%.zcml: includes/sqlos-%.zcml Zope3 +$(z3includes)/%.zcml: includes/%.zcml Zope3 cp $< $@ .PHONY: sqlos-meta @@ -61,22 +56,13 @@ touch Zope3/src/easy-install.pth PYTHONPATH=Zope3/src $(PYTHON) setup.py develop -S Zope3/src --install-dir Zope3/src -.PHONY: patch -patch: - # This is butttt ugly pul hopefully temporary - set - e;\ - if [ `grep 'site.addsitedir(src)' Zope3/test.py -c` == 0 ]; then\ - cat patch-test.py | patch -p0;\ - fi - .PHONY: testall -test: develop patch +test: develop cd Zope3 && $(PYTHON) test.py --test-path=../src -s sqlos Zope3/principals.zcml: Zope3 Zope3/sample_principals.zcml cp Zope3/sample_principals.zcml $@ -.PHONY: run-sample -run-sample: develop Zope3/principals.zcml - cp includes/sqlos-ftesting.zcml $(z3includes)/sqlos.testing-configure.zcml - sampleapp.py ; rm $(z3includes)/sqlos.testing-configure.zcml +.PHONY: run-sampleapp +run-sampleapp: develop Zope3/principals.zcml $(z3includes)/sqlos.ftesting-configure.zcml + cd Zope3; ./z3.py Deleted: /z3/sqlos/trunk/patch-test.py ============================================================================== --- /z3/sqlos/trunk/patch-test.py Wed Apr 5 23:28:44 2006 +++ (empty file) @@ -1,13 +0,0 @@ -Index: Zope3/test.py -=================================================================== ---- Zope3/test.py (revision 65897) -+++ Zope3/test.py (working copy) -@@ -26,6 +26,8 @@ - # add src to path - src = os.path.join(here, 'src') - sys.path.insert(0, src) # put at beginning to avoid one in site_packages -+import site -+site.addsitedir(src) - - from zope.testing import testrunner - Deleted: /z3/sqlos/trunk/sampleapp.py ============================================================================== --- /z3/sqlos/trunk/sampleapp.py Wed Apr 5 23:28:44 2006 +++ (empty file) @@ -1,79 +0,0 @@ -#!/usr/bin/env python2.4 -############################################################################## -# -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Start script for Zope3: loads configuration and starts the server. - -$Id: z3.py 40235 2005-11-18 21:30:31Z srichter $ -""" -import os -import sys - -basepath = filter(None, sys.path) - -def run(argv=list(sys.argv)): - - if sys.version_info < ( 2,3,5 ): - print """\ - ERROR: Your python version is not supported by Zope3. - Zope3 needs Python 2.3.5 or greater. You are running:""" + sys.version - sys.exit(1) - - # Refuse to run without principals.zcml - if not os.path.exists('principals.zcml'): - print """\ - ERROR: You need to create principals.zcml - - The file principals.zcml contains your "bootstrap" user - database. You aren't going to get very far without it. Start - by copying sample_principals.zcml and then modify the - example principal and role settings. - """ - sys.exit(1) - - # setting python paths - program = argv[0] - if "--build" in argv: - argv.remove("--build") - from distutils.util import get_platform - PLAT_SPEC = "%s-%s" % (get_platform(), sys.version[0:3]) - src = os.path.join("build", "lib.%s" % PLAT_SPEC) - else: - src = 'src' - - here = os.path.dirname(os.path.abspath(program)) - srcdir = os.path.abspath(src) - sys.path = [srcdir] + basepath - sys.path[:] = [p for p in sys.path if os.path.abspath(p) != here] - - # Register the paths - import site - site.addsitedir(srcdir) - - # setup a subscriber to create the sampleperson tables - def setupTestingTables(event): - from sqlos.testing import sampleperson - sampleperson.createTestingTables() - - from zope.app.appsetup.interfaces import IDatabaseOpenedEvent - from zope.component import getGlobalSiteManager - gsm = getGlobalSiteManager() - gsm.subscribe([IDatabaseOpenedEvent], None, setupTestingTables) - - from zope.app.twisted.main import main - main(argv[1:]) - - -if __name__ == '__main__': - os.chdir('Zope3') - run() Modified: z3/sqlos/trunk/src/sqlos/README.txt ============================================================================== --- z3/sqlos/trunk/src/sqlos/README.txt (original) +++ z3/sqlos/trunk/src/sqlos/README.txt Wed Apr 5 23:28:44 2006 @@ -48,6 +48,8 @@ Dependencies ------------ + + setuptools >= 0.6a11 + + SQLObject >= 0.7 Place the sqlobject package somewhere in python's sys.path @@ -107,6 +109,32 @@ connection and any registered class you wish. +A Sample Application +-------------------- + +The functional test setup for sqlos is really a sample application. You can +run and play with this to see how sqlos works. + +First install a Z3 database adapter, create a database, edit +src/sqlos/ftesting.zcml to change the connection settings as +described below in "Setting up a connection for SQLObject". + +NOTE: This currently does not work with the default testing database + (memory based SQLite) due to threading issues. + +Then, from a checkout of sqlos run: + + $ make run-sampleapp + +This should download Zope3 install sqlos and set up the functional +test suite as a sample application. You can then log into zope3 on +http://localhost:8080 with gandalf:123. + +Try adding a "SQLObject MultiContainer" and then some people. + +NOTE: changing debug=1 in src/sqlos/adapter.py will cause the SQL + executed to be printed on the terminal + Setting up a connection for SQLObject ------------------------------------- Added: z3/sqlos/trunk/src/sqlos/sampleapp.zcml ============================================================================== --- (empty file) +++ z3/sqlos/trunk/src/sqlos/sampleapp.zcml Wed Apr 5 23:28:44 2006 @@ -0,0 +1,13 @@ + + + + + + + + + From jinty at codespeak.net Thu Apr 6 12:04:09 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Thu Apr 6 12:04:10 2006 Subject: [z3-checkins] r25435 - z3/sqlos/trunk/Zope2/FiveSQLOS Message-ID: <20060406100409.22ADE10223@code0.codespeak.net> Author: jinty Date: Thu Apr 6 12:04:07 2006 New Revision: 25435 Modified: z3/sqlos/trunk/Zope2/FiveSQLOS/wrapper.py Log: Fix an important bug that was uncovered by the changes to the testing harness in sqlos. Modified: z3/sqlos/trunk/Zope2/FiveSQLOS/wrapper.py ============================================================================== --- z3/sqlos/trunk/Zope2/FiveSQLOS/wrapper.py (original) +++ z3/sqlos/trunk/Zope2/FiveSQLOS/wrapper.py Thu Apr 6 12:04:07 2006 @@ -25,6 +25,7 @@ from zope.app.container.constraints import checkFactory from zope.interface import implements, providedBy, directlyProvides from sqlos.interfaces import ISQLObject, IISQLObject +from zope.app.exception.interfaces import UserError from Products.FiveSQLOS.interfaces import IFiveSQLObject @@ -80,10 +81,12 @@ # Look for the SQLObject class our object is from, so get all # allowed factories for name, factory in zapi.getFactoriesFor(ISQLObject): - if checkFactory(self, None, factory): + if checkFactory(self.aq_parent, None, factory): # get the sqlobject class - factory = zapi.getUtility(IISQLObject, name) - if obj.sqlmeta.table == factory.sqlmeta.table: + utility = zapi.queryUtility(IISQLObject, name) + if utility is None: + continue + if obj.sqlmeta.table == utility.sqlmeta.table: # if the tables names are the same, we assume that the # sqlobject is an instance of that class, perhaps that # is wrong From jinty at codespeak.net Thu Apr 6 21:38:45 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Thu Apr 6 21:38:46 2006 Subject: [z3-checkins] r25463 - in z3/sqlos/trunk: doc/examples src/sqlos Message-ID: <20060406193845.46DA71024C@code0.codespeak.net> Author: jinty Date: Thu Apr 6 21:38:38 2006 New Revision: 25463 Removed: z3/sqlos/trunk/doc/examples/ Modified: z3/sqlos/trunk/src/sqlos/README.txt Log: Rip out the example because it broke and was frustrating first time users. Being untested it is just too much maintainence to fix. Anyway, now we use our functional test setup as an example application and, well, that is tested. Modified: z3/sqlos/trunk/src/sqlos/README.txt ============================================================================== --- z3/sqlos/trunk/src/sqlos/README.txt (original) +++ z3/sqlos/trunk/src/sqlos/README.txt Thu Apr 6 21:38:38 2006 @@ -138,9 +138,6 @@ Setting up a connection for SQLObject ------------------------------------- -NOTE: There is a fully worked out example package in the - doc/examples/sqlos_sample directory. - This example is not complete yet (XXX), but should give you an idea:: Author: jinty Date: Fri Apr 7 02:01:23 2006 New Revision: 25467 Modified: z3/sqlos/trunk/src/sqlos/__init__.py z3/sqlos/trunk/src/sqlos/interfaces/__init__.py Log: Move some strange, untested and probably un-necessary class implements closer to where the interfaces are defined. Modified: z3/sqlos/trunk/src/sqlos/__init__.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/__init__.py (original) +++ z3/sqlos/trunk/src/sqlos/__init__.py Fri Apr 7 02:01:23 2006 @@ -13,27 +13,8 @@ __metaclass__ = type from datetime import datetime, date -from zope.interface import classImplements from zope.app import zapi -from zope.security.checker import NamesChecker, NoProxy, defineChecker - -from sqlobject.dbconnection import DBConnection, DBAPI -from sqlobject import _mysql, _postgres, _sybase -from sqlobject.main import SQLObject, SelectResults -from sqlobject.sqlbuilder import registerConverter, \ - SQLObjectTable -from sqlos.interfaces import IDBConnection, IDBAPI, ISQLConnection -from sqlos.interfaces import IISQLObject, ISQLObject, ISelectResults - -defineChecker(SQLObjectTable, NoProxy) - -classImplements(DBConnection, IDBConnection) -classImplements(DBAPI, IDBAPI) -classImplements(_mysql.builder(), ISQLConnection) -classImplements(_postgres.builder(), ISQLConnection) -classImplements(_sybase.builder(), ISQLConnection) -classImplements(SQLObject, ISQLObject) -classImplements(SelectResults, ISelectResults) +from sqlobject.sqlbuilder import registerConverter from _sqlos import SQLOS Modified: z3/sqlos/trunk/src/sqlos/interfaces/__init__.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/interfaces/__init__.py (original) +++ z3/sqlos/trunk/src/sqlos/interfaces/__init__.py Fri Apr 7 02:01:23 2006 @@ -11,11 +11,17 @@ """ from zope.schema import TextLine from zope.interface import Interface, Attribute -from sqlobject import NoDefault from zope.component import getService, ComponentLookupError +from zope.interface import classImplements +from zope.security.checker import NamesChecker, NoProxy, defineChecker from zope.schema.vocabulary import SimpleVocabulary from zope.schema import Choice, List from zope.app.annotation.interfaces import IAttributeAnnotatable +from sqlobject import NoDefault +from sqlobject.dbconnection import DBConnection, DBAPI +from sqlobject import _mysql, _postgres, _sybase +from sqlobject.main import SQLObject, SelectResults +from sqlobject.sqlbuilder import SQLObjectTable class IConnectionName(Interface): """A marker interface for providing a connection name""" @@ -248,7 +254,7 @@ class IISQLObjectIsolated(IISQLObject): """Support for using this class in isolated containers. - + This interface is necessary to move the SQL query logic to the SQLOS class as it can be implemented in various ways in the class. """ @@ -335,3 +341,17 @@ def next(): """ Iterator """ + +# XXX: Why do we need these???? + +defineChecker(SQLObjectTable, NoProxy) + +classImplements(DBConnection, IDBConnection) +classImplements(DBAPI, IDBAPI) +classImplements(_mysql.builder(), ISQLConnection) +classImplements(_postgres.builder(), ISQLConnection) +classImplements(_sybase.builder(), ISQLConnection) +classImplements(SQLObject, ISQLObject) +classImplements(SelectResults, ISelectResults) + + From jinty at codespeak.net Fri Apr 7 02:03:50 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Fri Apr 7 02:03:58 2006 Subject: [z3-checkins] r25468 - z3/sqlos/trunk/src/sqlos Message-ID: <20060407000350.2629910249@code0.codespeak.net> Author: jinty Date: Fri Apr 7 02:03:40 2006 New Revision: 25468 Modified: z3/sqlos/trunk/src/sqlos/__init__.py Log: Deprecate the unused (in sqlos) sqlos.caller Modified: z3/sqlos/trunk/src/sqlos/__init__.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/__init__.py (original) +++ z3/sqlos/trunk/src/sqlos/__init__.py Fri Apr 7 02:03:40 2006 @@ -52,3 +52,4 @@ factory." deprecated("getFactory", msg) +deprecated("caller", "sqlos.caller is deprecated and will be removed after sqlos 0.2") From jinty at codespeak.net Fri Apr 7 02:17:11 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Fri Apr 7 02:17:13 2006 Subject: [z3-checkins] r25469 - in z3/sqlos/trunk/src/sqlos: . auth ftests Message-ID: <20060407001711.8666010251@code0.codespeak.net> Author: jinty Date: Fri Apr 7 02:17:08 2006 New Revision: 25469 Modified: z3/sqlos/trunk/src/sqlos/__init__.py z3/sqlos/trunk/src/sqlos/auth/__init__.py z3/sqlos/trunk/src/sqlos/connection.py z3/sqlos/trunk/src/sqlos/container.py z3/sqlos/trunk/src/sqlos/ftests/test_transaction.py Log: Remove users of zapi. Modified: z3/sqlos/trunk/src/sqlos/__init__.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/__init__.py (original) +++ z3/sqlos/trunk/src/sqlos/__init__.py Fri Apr 7 02:17:08 2006 @@ -13,7 +13,7 @@ __metaclass__ = type from datetime import datetime, date -from zope.app import zapi +import zope.component from sqlobject.sqlbuilder import registerConverter from _sqlos import SQLOS @@ -41,14 +41,14 @@ def getFactory(name, context=None, default=None): # XXX - deprecated, goes away after sqlos 0.2 - return zapi.queryUtility(IISQLObject, name, default=default, context=context) + return zope.component.queryUtility(IISQLObject, name, default=default, context=context) from zope.deprecation import deprecated msg = "getFactory is depreciated and will go away after sqlos 0.2 you should \ replace this with a direct call to \ -zapi.getUtility(IISQLObject, name, context=context) if you need the \ +zope.component.getUtility(IISQLObject, name, context=context) if you need the \ functionailty of a SQLObject class, or \ -zapi.getUtility(IFactory, name, context=context) if you want to use it as a \ +zope.component.getUtility(IFactory, name, context=context) if you want to use it as a \ factory." deprecated("getFactory", msg) Modified: z3/sqlos/trunk/src/sqlos/auth/__init__.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/auth/__init__.py (original) +++ z3/sqlos/trunk/src/sqlos/auth/__init__.py Fri Apr 7 02:17:08 2006 @@ -13,7 +13,7 @@ from zope.interface import implements -from zope.app import zapi +import zope.component from zope.app.pluggableauth.interfaces import ILoginPasswordPrincipalSource from zope.app.pluggableauth import SimplePrincipal Modified: z3/sqlos/trunk/src/sqlos/connection.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/connection.py (original) +++ z3/sqlos/trunk/src/sqlos/connection.py Fri Apr 7 02:17:08 2006 @@ -15,7 +15,7 @@ import warnings from zope.component import ComponentLookupError -from zope.app import zapi +import zope.component from zope.app.rdb.interfaces import IZopeDatabaseAdapter from zope.thread import local @@ -79,7 +79,7 @@ name = self.name if name is None: try: - ut = zapi.getUtility(IConnectionName) + ut = zope.component.getUtility(IConnectionName) except ComponentLookupError: return self if ut is None: @@ -91,7 +91,7 @@ # try get the connection from the cache, or make a new one conn = conn_cache.queryConnection(name) if conn is None: - zda = zapi.getUtility(IZopeDatabaseAdapter, name) + zda = zope.component.getUtility(IZopeDatabaseAdapter, name) try: conn = IZopeSQLConnection(zda()) except ComponentLookupError: Modified: z3/sqlos/trunk/src/sqlos/container.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/container.py (original) +++ z3/sqlos/trunk/src/sqlos/container.py Fri Apr 7 02:17:08 2006 @@ -18,7 +18,7 @@ from zope.interface import implements from zope.component import IFactory from zope import deprecation -from zope.app import zapi +import zope.component from zope.app.container.interfaces import IContained from zope.app.container.contained import ContainedProxy from zope.app.container.contained import Contained @@ -65,10 +65,10 @@ if ISQLObject.providedBy(obj): # Look for the SQLObject class our object is from, so get all # allowed factories - for name, factory in zapi.getFactoriesFor(ISQLObject): + for name, factory in zope.component.getFactoriesFor(ISQLObject): if checkFactory(self.context, None, factory): # get the sqlobject class - utility = zapi.queryUtility(IISQLObject, name) + utility = zope.component.queryUtility(IISQLObject, name) if utility is None: continue if obj.sqlmeta.table == utility.sqlmeta.table: @@ -87,7 +87,7 @@ pass def _allowedFactories(self): - for name, factory in zapi.getFactoriesFor(ISQLObject): + for name, factory in zope.component.getFactoriesFor(ISQLObject): if checkFactory(self, None, factory): yield name allowedFactories = deprecation.deprecated(_allowedFactories, @@ -95,9 +95,9 @@ ' please use _getAllowedIISQLObjectUtilities instead.') def _getAllowedIISQLObjectUtilities(self): - for name, factory in zapi.getFactoriesFor(ISQLObject): + for name, factory in zope.component.getFactoriesFor(ISQLObject): if checkFactory(self, None, factory): - utility = zapi.queryUtility(IISQLObject, name) + utility = zope.component.queryUtility(IISQLObject, name) # Someone might have registered a factory implementing # IISQLObject using for whatever reason. # in this case queryUtility returns None and we can just @@ -212,7 +212,7 @@ def allowedFactories(self): # Ignore all factories not implementing ISQLObjectIsolated for f in SQLObjectContainer._allowedFactories(self): - implemented = zapi.getFactoryInterfaces(f) + implemented = zope.component.getFactoryInterfaces(f) if implemented.isOrExtends(ISQLObjectIsolated): yield f allowedFactories = deprecation.deprecated(allowedFactories, Modified: z3/sqlos/trunk/src/sqlos/ftests/test_transaction.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/ftests/test_transaction.py (original) +++ z3/sqlos/trunk/src/sqlos/ftests/test_transaction.py Fri Apr 7 02:17:08 2006 @@ -16,7 +16,7 @@ from transaction import get, begin from zope.app.testing.functional import BrowserTestCase -from zope.app import zapi +import zope.component from zope.app.rdb.interfaces import IZopeDatabaseAdapter from sqlos.interfaces import IConnectionName @@ -98,8 +98,8 @@ This is a regression test for if the cache makes breaks the isolation between threads. """ - ut = zapi.getUtility(IConnectionName) - adapter = zapi.queryUtility(IZopeDatabaseAdapter, ut.name) + ut = zope.component.getUtility(IConnectionName) + adapter = zope.component.queryUtility(IZopeDatabaseAdapter, ut.name) if adapter.getDSN() == 'dbi://:memory:': import warnings warnings.warn('Warning, not testing Cache Isolation') @@ -130,8 +130,8 @@ happen even if the thread is not the main thread. (Just in case some dodo only registers the cache clearer in the main thread.) """ - ut = zapi.getUtility(IConnectionName) - adapter = zapi.queryUtility(IZopeDatabaseAdapter, ut.name) + ut = zope.component.getUtility(IConnectionName) + adapter = zope.component.queryUtility(IZopeDatabaseAdapter, ut.name) if adapter.getDSN() == 'dbi://:memory:': import warnings warnings.warn('Warning, not testing Cache Isolation') From reebalazs at codespeak.net Sun Apr 9 21:37:11 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Sun Apr 9 21:37:11 2006 Subject: [z3-checkins] r25638 - z3/jsonserver/branch/zope2_test Message-ID: <20060409193711.0F0F310169@code0.codespeak.net> Author: reebalazs Date: Sun Apr 9 21:37:09 2006 New Revision: 25638 Modified: z3/jsonserver/branch/zope2_test/configure.zcml Log: include browser package was missing Modified: z3/jsonserver/branch/zope2_test/configure.zcml ============================================================================== --- z3/jsonserver/branch/zope2_test/configure.zcml (original) +++ z3/jsonserver/branch/zope2_test/configure.zcml Sun Apr 9 21:37:09 2006 @@ -8,6 +8,7 @@ + - - - - From regebro at codespeak.net Tue Apr 11 20:25:57 2006 From: regebro at codespeak.net (regebro@codespeak.net) Date: Tue Apr 11 20:25:58 2006 Subject: [z3-checkins] r25706 - z3/CMFonFive/trunk Message-ID: <20060411182557.9581510177@code0.codespeak.net> Author: regebro Date: Tue Apr 11 20:25:57 2006 New Revision: 25706 Modified: z3/CMFonFive/trunk/CHANGES.txt z3/CMFonFive/trunk/fiveactionstool.py z3/CMFonFive/trunk/version.txt Log: The generated id of the icons is now consistent. Modified: z3/CMFonFive/trunk/CHANGES.txt ============================================================================== --- z3/CMFonFive/trunk/CHANGES.txt (original) +++ z3/CMFonFive/trunk/CHANGES.txt Tue Apr 11 20:25:57 2006 @@ -1,7 +1,17 @@ CMFonFive Product Changelog + CMFonFive 1.3.3 (2005-04-11) + + - The id of the action is now generated from the last part of the interface + the menu item is defined for, and the last part of the action. This should + generate enough uniqueness so that action id's does not clash too much, while + never generating two different ids. + + The reason for this change is that it enables you to add icons with the CMF + ActionIconsTool. + CMFonFive 1.3.2 (2005-02-22) - + - GenericSetup calls all action providers with both object and info as None, which resulted in an attribute error. Modified: z3/CMFonFive/trunk/fiveactionstool.py ============================================================================== --- z3/CMFonFive/trunk/fiveactionstool.py (original) +++ z3/CMFonFive/trunk/fiveactionstool.py Tue Apr 11 20:25:57 2006 @@ -21,13 +21,52 @@ from Products.CMFCore.Expression import Expression from Products.CMFCore.utils import UniqueObject +from zope.interface import providedBy from zope.app import zapi from zope.app.publisher.interfaces.browser import IBrowserMenu -from zope.app.publisher.browser.menu import getMenu - +from zope.app.publisher.interfaces.browser import IBrowserSubMenuItem +from zope.security.proxy import removeSecurityProxy + def _listMenuIds(): return [id for id, utility in zapi.getUtilitiesFor(IBrowserMenu)] +def getMenu(id, object, request): + """Return menu item entries in a TAL-friendly form.""" + menu = zapi.getUtility(IBrowserMenu, id) + + result = [] + for name, item in zapi.getAdapters((object, request), + menu.getMenuItemType()): + if item.available(): + result.append(item) + + # Now order the result. This is not as easy as it seems. + # + # (1) Look at the interfaces and put the more specific menu entries + # to the front. + # (2) Sort unabigious entries by order and then by title. + ifaces = list(providedBy(removeSecurityProxy(object)).__iro__) + result = [(ifaces.index(item._for or Interface), + item.order, item.title, item) for item in result] + result.sort() + + res = [] + for index, order, title, item in result: + identifier = '%s_%s' % (item._for.__identifier__.split('.')[-1], + item.action.split('/')[-1]) + identifier = identifier.replace(' ', '_').lower() + res.append({'title': item.title, + 'description': item.description, + 'action': item.action, + 'selected': (item.selected() and u'selected') or u'', + 'icon': item.icon, + 'extra': item.extra, + 'submenu': (IBrowserSubMenuItem.providedBy(item) and + getMenu(item.submenuId, object, request)) or None, + 'identifier': identifier, + }) + return res + from Products.Five import security import zope.thread @@ -61,10 +100,8 @@ # from the object_id and the action url. That is sure # to be unique. action = str(entry['action']) - if object is None: - act_id = 'action_%s' % action - else: - act_id = 'action_%s_%s' % (object.getId(), action) + meta_type = getattr(object, 'meta_type', '') + act_id = entry['identifier'] if entry.get('filter') is None: filter = None Modified: z3/CMFonFive/trunk/version.txt ============================================================================== --- z3/CMFonFive/trunk/version.txt (original) +++ z3/CMFonFive/trunk/version.txt Tue Apr 11 20:25:57 2006 @@ -1 +1 @@ -CMFonFive-1.3.2 +CMFonFive-1.3.3 From regebro at codespeak.net Wed Apr 12 12:01:34 2006 From: regebro at codespeak.net (regebro@codespeak.net) Date: Wed Apr 12 12:01:35 2006 Subject: [z3-checkins] r25714 - z3/CMFonFive/trunk Message-ID: <20060412100134.7A74910149@code0.codespeak.net> Author: regebro Date: Wed Apr 12 12:01:34 2006 New Revision: 25714 Modified: z3/CMFonFive/trunk/CHANGES.txt z3/CMFonFive/trunk/version.txt Log: Decided not to release it now, but before CPS 3.4.1 (or if somebody asks me too). Modified: z3/CMFonFive/trunk/CHANGES.txt ============================================================================== --- z3/CMFonFive/trunk/CHANGES.txt (original) +++ z3/CMFonFive/trunk/CHANGES.txt Wed Apr 12 12:01:34 2006 @@ -1,6 +1,6 @@ CMFonFive Product Changelog - CMFonFive 1.3.3 (2005-04-11) + CMFonFive 1.3.3 (unreleased) - The id of the action is now generated from the last part of the interface the menu item is defined for, and the last part of the action. This should Modified: z3/CMFonFive/trunk/version.txt ============================================================================== --- z3/CMFonFive/trunk/version.txt (original) +++ z3/CMFonFive/trunk/version.txt Wed Apr 12 12:01:34 2006 @@ -1 +1 @@ -CMFonFive-1.3.3 +CMFonFive-1.3.2+ From jinty at codespeak.net Thu Apr 13 00:15:54 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Thu Apr 13 00:15:56 2006 Subject: [z3-checkins] r25747 - z3/sqlos/trunk/src/sqlos Message-ID: <20060412221554.C8161101A9@code0.codespeak.net> Author: jinty Date: Thu Apr 13 00:15:53 2006 New Revision: 25747 Modified: z3/sqlos/trunk/src/sqlos/README.txt Log: Be consistent Modified: z3/sqlos/trunk/src/sqlos/README.txt ============================================================================== --- z3/sqlos/trunk/src/sqlos/README.txt (original) +++ z3/sqlos/trunk/src/sqlos/README.txt Thu Apr 13 00:15:53 2006 @@ -13,21 +13,21 @@ ``sqlos`` is a toolkit for using SQLObject_ (an Object Relational Mapper) inside Zope 3 or Zope 2. It tries to take care of many of the fiddly details that always seem to take a lot of time. The major ways -it helps are:: +it helps are: - * Integrates the Zope transaction system and SQLObject, allowing - SQLObject to be used in lazyUpdate mode. + + Integrates the Zope transaction system and SQLObject, allowing + SQLObject to be used in lazyUpdate mode. + + + Uses Zope Database adapters in SQLObject. - * Uses Zope Database adapters in SQLObject. + + Provide zcml configuration directives. - * Provide zcml configuration directives. + + Provide ZODB persistent objects that can act as a "window" into + the database. - * Provide ZODB persistent objects that can act as a "window" into - the database. + + A testing infrastructure for testing SQLObject based applications. - * A testing infrastructure for testing SQLObject based applications. - - * Caches SQLObjects and database connections to improve performance. + + Caches SQLObjects and database connections to improve performance. .. _SQLObject: http://sqlobject.org From jinty at codespeak.net Thu Apr 13 01:05:58 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Thu Apr 13 01:05:59 2006 Subject: [z3-checkins] r25751 - in z3/sqlos/trunk/src/sqlos: . auth Message-ID: <20060412230558.84476101AF@code0.codespeak.net> Author: jinty Date: Thu Apr 13 01:05:56 2006 New Revision: 25751 Removed: z3/sqlos/trunk/src/sqlos/annotations.py z3/sqlos/trunk/src/sqlos/attributeannotations.py z3/sqlos/trunk/src/sqlos/auth/ Modified: z3/sqlos/trunk/src/sqlos/configure.zcml Log: Rip out sqlos.auth, sqlos.annotations and sqlos.attributeannotations as they were competely untested, prbably broken and nobody stepped up to do anything about it. Deleted: /z3/sqlos/trunk/src/sqlos/annotations.py ============================================================================== --- /z3/sqlos/trunk/src/sqlos/annotations.py Thu Apr 13 01:05:56 2006 +++ (empty file) @@ -1,18 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004 Enfold Systems LLC. All rights reserved. -# -# This software is distributed under the terms of the Zope Public -# License (ZPL) v2.1. See COPYING.txt for more information. -# -############################################################################## -""" -$Id: adapter.py 5212 2004-06-21 18:09:05Z philikon $ -""" -from sqlobject import * - -class Annotations(SQLObject): - - location = StringCol('location', length=255, notNull=1) - key = StringCol('key', length=255, notNull=1) - value = StringCol('value', notNull=0) Deleted: /z3/sqlos/trunk/src/sqlos/attributeannotations.py ============================================================================== --- /z3/sqlos/trunk/src/sqlos/attributeannotations.py Thu Apr 13 01:05:56 2006 +++ (empty file) @@ -1,135 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004 Enfold Systems LLC. All rights reserved. -# -# This software is distributed under the terms of the Zope Public -# License (ZPL) v2.1. See COPYING.txt for more information. -# -############################################################################## -""" -$Id: adapter.py 5212 2004-06-21 18:09:05Z philikon $ -""" - -import pickle - -from sqlobject import * -from zope.app.interfaces.annotation import IAnnotations -from zope.app import zapi -from zope.proxy import removeAllProxies -from zope.interface import implements -from zope.app.interfaces.location import ILocation -from zope.app.location import Location - -from sqlos import getFactory - - -class AnnotationProxy(object): - - def __init__(self, parent, key, context): - self.__parent = parent - self.__key = key - self.__context = context - - def __getattr__(self, name): - if name in ('_AnnotationProxy__parent', - '_AnnotationProxy__key', - '_AnnotationProxy__context'): - return object.__getattribute__(self, name) - return getattr(self.__context, name) - - def __setattr__(self, name, value): - if name in ('_AnnotationProxy__parent', - '_AnnotationProxy__key', - '_AnnotationProxy__context'): - object.__setattr__(self, name, value) - else: - setattr(self.__context, name, value) - self.__parent[self.__key] = self.__context - - def __setitem__(self, name, value): - if name in ('_AnnotationProxy__parent', - '_AnnotationProxy__key', - '_AnnotationProxy__context'): - object.__setattr__(self, name, value) - else: - self.__context[name] = value - self.__parent[self.__key] = self.__context - - -class AnnotationSource(Location): - - def __init__(self, context): - self.context = context - self.location = "%s/%s" % (zapi.getName(zapi.getParent(context)), - zapi.getName(context)) - self.__parent__ = context - self.__name__ = '__annotations_source__' - self.className = 'Annotations' - - def __getitem__(self, name): - factory = getFactory(self.className) - clause = "location = %r and key = %r" % (str(self.location), - str(name)) - result = factory.select(clause = clause) - if not len(result): - raise KeyError, name - return AnnotationProxy(self, name, pickle.loads(result[0].value)) - - def get(self, name, default): - try: - item = self[name] - except KeyError: - return default - return item - - def __setitem__(self, name, value): - factory = getFactory(self.className) - clause = "location = %r and key = %r" % (str(self.location), - str(name)) - result = factory.select(clause = clause) - if not len(result): - item = factory.new(location=self.location, - key=name, - value=None) - else: - item = result[0] - - assert pickle.loads(pickle.dumps(value)) == value - value = pickle.dumps(value) - item.value = value - - -class SQLAttributeAnnotations: - """ - Store annotations in the annotations table, keyed by - table_name/id on a IAttributeAnnotatable object. - """ - - implements(IAnnotations) - - def __init__(self, obj): - self.wrapped_obj = obj - self.unwrapped_obj = removeAllProxies(obj) - - def __getitem__(self, key): - annotations = AnnotationSource(self.wrapped_obj) - if annotations is None: - raise KeyError, key - return annotations[key] - - def __setitem__(self, key, value): - if ILocation.providedBy(value): - value.__parent__ = self.unwrapped_obj - - annotations = AnnotationSource(self.wrapped_obj) - annotations[key] = value - - def get(self, key, default=None): - annotations = AnnotationSource(self.wrapped_obj) - return annotations.get(key, default) - - def __getattr__(self, name): - # this method is for getting methods and attributes of the - # mapping object used to store annotations. - annotations = AnnotationSource(self.wrapped_obj) - return getattr(annotations, name) Modified: z3/sqlos/trunk/src/sqlos/configure.zcml ============================================================================== --- z3/sqlos/trunk/src/sqlos/configure.zcml (original) +++ z3/sqlos/trunk/src/sqlos/configure.zcml Thu Apr 13 01:05:56 2006 @@ -3,8 +3,6 @@ xmlns:browser="http://namespaces.zope.org/browser" i18n_domain="sqlos"> - - @@ -56,21 +54,6 @@ attribute="contents" /> - - - - - - - - - - - - - - - Author: jinty Date: Thu Apr 13 01:27:53 2006 New Revision: 25753 Modified: z3/sqlos/trunk/src/sqlos/README.txt Log: Steal the compatibilty matrix from Five Modified: z3/sqlos/trunk/src/sqlos/README.txt ============================================================================== --- z3/sqlos/trunk/src/sqlos/README.txt (original) +++ z3/sqlos/trunk/src/sqlos/README.txt Thu Apr 13 01:27:53 2006 @@ -17,7 +17,7 @@ + Integrates the Zope transaction system and SQLObject, allowing SQLObject to be used in lazyUpdate mode. - + + Uses Zope Database adapters in SQLObject. + Provide zcml configuration directives. @@ -42,6 +42,17 @@ but it can be used with Zope 2. Heavily leveraging the work by the Five project, a Zope 2 product (FiveSQLOS) was created to enable this. +The following table shows which sqlos version can and should be used +with which Zope 2 and Zope 3 versions. + +============ ======== +. Zope 2.9 +------------ -------- +. Zope 3.2 +============ ======== +sqlos 0.2 X +============ ======== + .. _FiveSQLOS: http://codespeak.net/svn/z3/sqlos/trunk/Zope2/FiveSQLOS/ From jinty at codespeak.net Thu Apr 13 01:33:49 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Thu Apr 13 01:33:50 2006 Subject: [z3-checkins] r25754 - z3/www/trunk Message-ID: <20060412233349.00FF5101B3@code0.codespeak.net> Author: jinty Date: Thu Apr 13 01:33:47 2006 New Revision: 25754 Modified: z3/www/trunk/mkwebsite.py Log: Remove the Five 1.0.3 release which isnt in the zope.org repository. Modified: z3/www/trunk/mkwebsite.py ============================================================================== --- z3/www/trunk/mkwebsite.py (original) +++ z3/www/trunk/mkwebsite.py Thu Apr 13 01:33:47 2006 @@ -152,8 +152,6 @@ site.registerReleases([ Z3ReleaseResource( - 'Five', 'svn://svn.zope.org/repos/main/Products.Five/tags/1.0.3'), - Z3ReleaseResource( 'Five', 'svn://svn.zope.org/repos/main/Products.Five/tags/1.1'), Z3ReleaseResource( 'Five', 'svn://svn.zope.org/repos/main/Products.Five/tags/1.2.2'), From jinty at codespeak.net Thu Apr 13 01:37:59 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Thu Apr 13 01:38:00 2006 Subject: [z3-checkins] r25755 - z3/sqlos/branch/0.2 Message-ID: <20060412233759.3FB25101B3@code0.codespeak.net> Author: jinty Date: Thu Apr 13 01:37:56 2006 New Revision: 25755 Added: z3/sqlos/branch/0.2/ - copied from r25754, z3/sqlos/trunk/ Log: Make a 0.2 maintainence branch. From jinty at codespeak.net Thu Apr 13 01:42:01 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Thu Apr 13 01:42:02 2006 Subject: [z3-checkins] r25756 - z3/sqlos/branch/0.2 Message-ID: <20060412234201.44D5C101B3@code0.codespeak.net> Author: jinty Date: Thu Apr 13 01:41:59 2006 New Revision: 25756 Removed: z3/sqlos/branch/0.2/setup.cfg Modified: z3/sqlos/branch/0.2/makefile z3/sqlos/branch/0.2/setup.py Log: Mark 0.2 as a release. Modified: z3/sqlos/branch/0.2/makefile ============================================================================== --- z3/sqlos/branch/0.2/makefile (original) +++ z3/sqlos/branch/0.2/makefile Thu Apr 13 01:41:59 2006 @@ -4,7 +4,7 @@ ZH=${HERE}/../../ PYTHON=python2.4 z3includes=Zope3/zopeskel/etc/package-includes -Z3BRANCH=trunk +Z3BRANCH=branches/0,2 all : test clean Deleted: /z3/sqlos/branch/0.2/setup.cfg ============================================================================== --- /z3/sqlos/branch/0.2/setup.cfg Thu Apr 13 01:41:59 2006 +++ (empty file) @@ -1,2 +0,0 @@ -[egg-info] -tag_svn_revision = 1 Modified: z3/sqlos/branch/0.2/setup.py ============================================================================== --- z3/sqlos/branch/0.2/setup.py (original) +++ z3/sqlos/branch/0.2/setup.py Thu Apr 13 01:41:59 2006 @@ -3,7 +3,7 @@ setup( name="sqlos", description="an integration package for Zope3 and SQLObject", - version="0.1", + version="0.2", license="ZPL", package_dir={'':'src'}, packages=find_packages('src'), From jinty at codespeak.net Thu Apr 13 01:50:27 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Thu Apr 13 01:50:28 2006 Subject: [z3-checkins] r25757 - z3/sqlos/trunk Message-ID: <20060412235027.604D6101B3@code0.codespeak.net> Author: jinty Date: Thu Apr 13 01:50:24 2006 New Revision: 25757 Modified: z3/sqlos/trunk/setup.py Log: Add some more metadata to the setup.py Modified: z3/sqlos/trunk/setup.py ============================================================================== --- z3/sqlos/trunk/setup.py (original) +++ z3/sqlos/trunk/setup.py Thu Apr 13 01:50:24 2006 @@ -3,8 +3,17 @@ setup( name="sqlos", description="an integration package for Zope3 and SQLObject", + long_description=""" +sqlos is a toolkit for using SQLObject (an Object Relational +Mapper) inside Zope 3 or Zope 2. It tries to take care of many of the +fiddly details that always seem to take a lot of time. +""", + url='http://codespeak.net/z3/sqlos/', version="0.1", license="ZPL", + maintainer="SQLOS development team", + maintainer_email="z3-sqlos@codespeak.net", + platforms=["any"], package_dir={'':'src'}, packages=find_packages('src'), zip_safe=False, From jinty at codespeak.net Thu Apr 13 01:51:48 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Thu Apr 13 01:51:49 2006 Subject: [z3-checkins] r25758 - z3/sqlos/branch/0.2 Message-ID: <20060412235148.3D75B101B3@code0.codespeak.net> Author: jinty Date: Thu Apr 13 01:51:46 2006 New Revision: 25758 Modified: z3/sqlos/branch/0.2/setup.py Log: Merge 25757 from trunk. Modified: z3/sqlos/branch/0.2/setup.py ============================================================================== --- z3/sqlos/branch/0.2/setup.py (original) +++ z3/sqlos/branch/0.2/setup.py Thu Apr 13 01:51:46 2006 @@ -3,8 +3,17 @@ setup( name="sqlos", description="an integration package for Zope3 and SQLObject", + long_description=""" +sqlos is a toolkit for using SQLObject (an Object Relational +Mapper) inside Zope 3 or Zope 2. It tries to take care of many of the +fiddly details that always seem to take a lot of time. +""", + url='http://codespeak.net/z3/sqlos/', version="0.2", license="ZPL", + maintainer="SQLOS development team", + maintainer_email="z3-sqlos@codespeak.net", + platforms=["any"], package_dir={'':'src'}, packages=find_packages('src'), zip_safe=False, From jinty at codespeak.net Thu Apr 13 20:42:13 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Thu Apr 13 20:42:15 2006 Subject: [z3-checkins] r25812 - z3/sqlos/branch/0.2 Message-ID: <20060413184213.A6A1D1007D@code0.codespeak.net> Author: jinty Date: Thu Apr 13 20:42:11 2006 New Revision: 25812 Modified: z3/sqlos/branch/0.2/makefile z3/sqlos/branch/0.2/setup.py Log: Fix the version no and makefile. Modified: z3/sqlos/branch/0.2/makefile ============================================================================== --- z3/sqlos/branch/0.2/makefile (original) +++ z3/sqlos/branch/0.2/makefile Thu Apr 13 20:42:11 2006 @@ -4,7 +4,7 @@ ZH=${HERE}/../../ PYTHON=python2.4 z3includes=Zope3/zopeskel/etc/package-includes -Z3BRANCH=branches/0,2 +Z3BRANCH=branches/3.2 all : test clean Modified: z3/sqlos/branch/0.2/setup.py ============================================================================== --- z3/sqlos/branch/0.2/setup.py (original) +++ z3/sqlos/branch/0.2/setup.py Thu Apr 13 20:42:11 2006 @@ -9,7 +9,7 @@ fiddly details that always seem to take a lot of time. """, url='http://codespeak.net/z3/sqlos/', - version="0.2", + version="0.2.0", license="ZPL", maintainer="SQLOS development team", maintainer_email="z3-sqlos@codespeak.net", From jinty at codespeak.net Thu Apr 13 20:46:45 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Thu Apr 13 20:46:46 2006 Subject: [z3-checkins] r25813 - z3/sqlos/tag/0.2.0 Message-ID: <20060413184645.42FCC10081@code0.codespeak.net> Author: jinty Date: Thu Apr 13 20:46:41 2006 New Revision: 25813 Added: z3/sqlos/tag/0.2.0/ - copied from r25812, z3/sqlos/branch/0.2/ Log: Tag 0.2.0 From jinty at codespeak.net Thu Apr 13 20:54:34 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Thu Apr 13 20:54:35 2006 Subject: [z3-checkins] r25814 - z3/sqlos/trunk/doc Message-ID: <20060413185434.6CB3810081@code0.codespeak.net> Author: jinty Date: Thu Apr 13 20:54:31 2006 New Revision: 25814 Added: z3/sqlos/trunk/doc/HowToMakeARealease.rst Log: Make a release howto. Added: z3/sqlos/trunk/doc/HowToMakeARealease.rst ============================================================================== --- (empty file) +++ z3/sqlos/trunk/doc/HowToMakeARealease.rst Thu Apr 13 20:54:31 2006 @@ -0,0 +1,60 @@ +How to make a SQLOS release +=========================== + +Firstly, this document is only a guide, feel free to correct/add to it. + + +Major release ++++++++++++++ + +Step 1 - Update Documentation +----------------------------- + +Update the documents in the source: + 1. trunk/src/sqlos/README.txt - Th compatibility matrix. + + +Step 2 - Make a maintenance branch for the release +-------------------------------------------------- + +Copy the branch: + 1. `svn cp https://codespeak.net/svn/z3/sqlos/trunk https://codespeak.net/svn/z3/sqlos/branch/x.y` + +Check it out: + 1. `svn co https://codespeak.net/svn/z3/sqlos/branch/x.y x.y` + 2. `cd x.y` + +Mark as a release as follows: + 1. svn rm setup.cfg + 2. update the version number in setup.py + 3. set the Z3BRANCH makefile variable so that the makefile points at the + compatible zope release branch + +Test the branch against Zope3 and Zope2: + 1. use `make test` to test the branch against the compatible version of Zope3 + 2. TODO - develop a procedure for testing against Zope2 + + +Step 3 - Tag the branch as a release +------------------------------------ + +Copy the branch: + 1. `svn cp https://codespeak.net/svn/z3/sqlos/branch/x.y https://codespeak.net/svn/z3/sqlos/tag/x.y.z` + +Step 4 - Upload to the python cheese shop +----------------------------------------- + +Simple: + 1. `svn co https://codespeak.net/svn/z3/sqlos/tag/x.y.z` + 2. cd x.y.z + 3. pythonX.X setup.py register sdist bdist_egg upload + +Step 5 - Send announcements +--------------------------- + +To: + z3-sqlos@codespeak.net + TODO: More? + +Template: + TODO From jinty at codespeak.net Thu Apr 13 21:04:54 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Thu Apr 13 21:04:55 2006 Subject: [z3-checkins] r25815 - z3/www/trunk Message-ID: <20060413190454.A110A10080@code0.codespeak.net> Author: jinty Date: Thu Apr 13 21:04:53 2006 New Revision: 25815 Modified: z3/www/trunk/mkwebsite.py Log: Add a quick link to the sqlos 0.2.0 release. Modified: z3/www/trunk/mkwebsite.py ============================================================================== --- z3/www/trunk/mkwebsite.py (original) +++ z3/www/trunk/mkwebsite.py Thu Apr 13 21:04:53 2006 @@ -225,6 +225,8 @@ ('sqlos main', 'index.html'), ] quick_links = [ + ('sqlos 0.2.0 release (compatible with SQLObject 0.7)', + 'http://cheeseshop.python.org/pypi/sqlos/0.2.0'), ('sqlos 0.1 release (compatible with SQLObject 0.6)', 'release/sqlos-0.1.tgz'), ('svn (the code)', From jinty at codespeak.net Thu Apr 13 21:16:24 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Thu Apr 13 21:16:25 2006 Subject: [z3-checkins] r25816 - z3/www/trunk Message-ID: <20060413191624.50EBE1007C@code0.codespeak.net> Author: jinty Date: Thu Apr 13 21:16:22 2006 New Revision: 25816 Modified: z3/www/trunk/mkwebsite.py Log: Add a link to the sqlos mailing list. Modified: z3/www/trunk/mkwebsite.py ============================================================================== --- z3/www/trunk/mkwebsite.py (original) +++ z3/www/trunk/mkwebsite.py Thu Apr 13 21:16:22 2006 @@ -223,6 +223,7 @@ def sqlos_site(site, project): nav_links = [ ('sqlos main', 'index.html'), + ('mailing list', '/mailman/listinfo/z3-sqlos'), ] quick_links = [ ('sqlos 0.2.0 release (compatible with SQLObject 0.7)', From jinty at codespeak.net Mon Apr 17 01:46:27 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Mon Apr 17 01:46:30 2006 Subject: [z3-checkins] r25876 - in z3/sqlos/trunk: . src/sqlos Message-ID: <20060416234627.36781100A3@code0.codespeak.net> Author: jinty Date: Mon Apr 17 01:46:21 2006 New Revision: 25876 Modified: z3/sqlos/trunk/TODO.txt z3/sqlos/trunk/src/sqlos/README.txt z3/sqlos/trunk/src/sqlos/_transaction.py z3/sqlos/trunk/src/sqlos/adapter.py z3/sqlos/trunk/src/sqlos/connection.py Log: Add some documntation Modified: z3/sqlos/trunk/TODO.txt ============================================================================== --- z3/sqlos/trunk/TODO.txt (original) +++ z3/sqlos/trunk/TODO.txt Mon Apr 17 01:46:21 2006 @@ -4,9 +4,6 @@ Features -------- -* Continuing quest to make sqlos containers more like zope persistent - containers. - * Make it un-necessary to register the db adapter class in zcml. This is required right now as there is no 'correct' way to tell which database a IZopeConnection is for. @@ -15,6 +12,3 @@ Bugs ---- - -* the sqlos.auth, sqlos.annotations and sqlos.attributeannotations modules - are completely un-tested and wait for someone to love them. Modified: z3/sqlos/trunk/src/sqlos/README.txt ============================================================================== --- z3/sqlos/trunk/src/sqlos/README.txt (original) +++ z3/sqlos/trunk/src/sqlos/README.txt Mon Apr 17 01:46:21 2006 @@ -59,9 +59,9 @@ Dependencies ------------ - + setuptools >= 0.6a11 + + setuptools_ >= 0.6a11 - + SQLObject >= 0.7 + + SQLObject_ >= 0.7 Place the sqlobject package somewhere in python's sys.path ($ZOPEHOME/lib/python is a good location). @@ -74,6 +74,7 @@ repository. .. _zopeproducts: http://cvs.zope.org/zopeproducts/ +.. _setuptools: http://www.python.org/pypi/setuptools Background Modified: z3/sqlos/trunk/src/sqlos/_transaction.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/_transaction.py (original) +++ z3/sqlos/trunk/src/sqlos/_transaction.py Mon Apr 17 01:46:21 2006 @@ -7,7 +7,21 @@ # License (ZPL) v2.1. See COPYING.txt for more information. # ############################################################################## -""" +"""Transaction management. + +This module integrates Zope and SQLObject's transaction management. It does 3 +things: + + * Creates a thread local cache of SQLObjects so that cached objects do not + leak into other threads as they would in pure SQLObject. + * Clears the thread local cache at the start of each new transaction. + * When an object is modified, it registers itself with the data manager + which, in turn, registers a pre-commit hook. This hook sync's the object + sending all the SQL down the line before the two phase commit starts. + +XXX - There was a reason why we couldn't do this without a data manager, but I + cannot remember it now. -jinty + $Id$ """ Modified: z3/sqlos/trunk/src/sqlos/adapter.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/adapter.py (original) +++ z3/sqlos/trunk/src/sqlos/adapter.py Mon Apr 17 01:46:21 2006 @@ -7,14 +7,18 @@ # License (ZPL) v2.1. See COPYING.txt for more information. # ############################################################################## -""" +"""Connection adapters for sqlos. + +These adapters adapt Zope RDB Connections to SQLObject connections by +sub-classing the SQLObject connection classes. + $Id$ """ __metaclass__ = type from sqlobject.dbconnection import DBAPI -from sqlobject import _mysql, _postgres, _sybase, _sqlite +from sqlobject import _mysql, _postgres, _sqlite from sqlobject.converters import registerConverter from sqlobject.mysql import mysqlconnection from zope.app.rdb.interfaces import DatabaseException Modified: z3/sqlos/trunk/src/sqlos/connection.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/connection.py (original) +++ z3/sqlos/trunk/src/sqlos/connection.py Mon Apr 17 01:46:21 2006 @@ -8,6 +8,15 @@ # ############################################################################## """ +Connection management. + +This module defines the connection descriptor used as the connection in a +a sqlos SQLObject. This is responsible for getting the Zope connection and +adapting it to look like a SQLObject connection. + +Connections are cached as experience has shown that all the utility and +adapter utilities have a significant effect on speed. + $Id: factory.py 5216 2004-06-21 18:33:07Z dreamcatcher $ """ __metaclass__ = type From reebalazs at codespeak.net Tue Apr 18 08:31:59 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Tue Apr 18 08:32:00 2006 Subject: [z3-checkins] r25926 - z3/jsonserver/branch/merge/browser Message-ID: <20060418063159.8D8A31008F@code0.codespeak.net> Author: reebalazs Date: Tue Apr 18 08:31:58 2006 New Revision: 25926 Modified: z3/jsonserver/branch/merge/browser/json.js z3/jsonserver/branch/merge/browser/xmlhttp.js Log: Critical: in XMLHttp change parameters and headers to Object from Array! Because it is handled with for(xx in obj), they must be created as Object. Problem is, that Sarissa puts extra functions in the Array prototype, and these would come up in the iteration: - causing an exception at setHeader, - and snapping a &xxx=xxx...etc part to the end of the json variable, causing a decode error on the server side. The problem only instantiated (strangely) when we were logged in as a plone user, in the kukitportlets demo. Modified: z3/jsonserver/branch/merge/browser/json.js ============================================================================== --- z3/jsonserver/branch/merge/browser/json.js (original) +++ z3/jsonserver/branch/merge/browser/json.js Tue Apr 18 08:31:58 2006 @@ -164,7 +164,7 @@ JSONRPCMethod.prototype.postData = function(url, user, pass, data, timeout, callback) { var xmlhttp = new XMLHttp(url); - var header = new Array() + var header = new Object() header["Content-Type"] = "application/json-rpc"; xmlhttp.setHeaders(header); xmlhttp.user = user; @@ -291,7 +291,7 @@ var v = []; for(attr in o) { if(o[attr] == null) v.push("\"" + attr + "\": null"); - else if(typeof o[attr] == "function"); // skip + else if(typeof(o[attr]) == "function"); // skip else v.push(escapeJSONString(attr) + ": " + toJSON(o[attr])); } return "{" + v.join(", ") + "}"; Modified: z3/jsonserver/branch/merge/browser/xmlhttp.js ============================================================================== --- z3/jsonserver/branch/merge/browser/xmlhttp.js (original) +++ z3/jsonserver/branch/merge/browser/xmlhttp.js Tue Apr 18 08:31:58 2006 @@ -27,8 +27,8 @@ this.password = null; this.timeout = null; this.argString = ""; - this.parameters = new Array(); - this.headers = new Array(); + this.parameters = new Object(); + this.headers = new Object(); this.headers['Content-Type'] = 'application/x-www-form-urlencoded' /* internal status flags */ From reebalazs at codespeak.net Tue Apr 18 17:11:19 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Tue Apr 18 17:11:20 2006 Subject: [z3-checkins] r25954 - z3/jsonserver/branch/merge/browser Message-ID: <20060418151119.4EC851008E@code0.codespeak.net> Author: reebalazs Date: Tue Apr 18 17:11:16 2006 New Revision: 25954 Added: z3/jsonserver/branch/merge/browser/logging.js z3/jsonserver/branch/merge/browser/requestmanager.js Modified: z3/jsonserver/branch/merge/browser/configure.zcml z3/jsonserver/branch/merge/browser/json.js Log: Add logging and simple support for simple request queue management Modified: z3/jsonserver/branch/merge/browser/configure.zcml ============================================================================== --- z3/jsonserver/branch/merge/browser/configure.zcml (original) +++ z3/jsonserver/branch/merge/browser/configure.zcml Tue Apr 18 17:11:16 2006 @@ -4,9 +4,11 @@ - \ No newline at end of file + Modified: z3/jsonserver/branch/merge/browser/json.js ============================================================================== --- z3/jsonserver/branch/merge/browser/json.js (original) +++ z3/jsonserver/branch/merge/browser/json.js Tue Apr 18 17:11:16 2006 @@ -51,6 +51,21 @@ function JSONSupplement(data, id) { return new json.SupplementWrapper(data, id); } + +// Direct method creation, by creating an implicit proxy +// if methodName == '' then the url is taken as full url +function makeJSONRPCMethod(url, methodName, callback, error, timeout, supplementData, + requestId, requestManager, user, pass) { + if (typeof(methodName) == 'undefined' || methodName == null || methodName == '') { + var pieces = url.split('/'); + methodName = pieces.pop(); + url = pieces.join('/'); + } + var proxy = new JSONRPC(url); + proxy.addMethod(methodName, callback, error, timeout, supplementData, + requestId, requestManager, user, pass); + return proxy[methodName]; +} function JSONRPC(url) { this._url = url; @@ -63,7 +78,7 @@ return new JSONRPC(url); } -JSONRPC.prototype.addMethod = function(name, callback, errHandler, timeout, supplementData, requestId) { +JSONRPC.prototype.addMethod = function(name, callback, errHandler, timeout, supplementData, requestId, requestManager) { if (typeof(errHandler) == 'undefined') { errHandler = null; } @@ -76,9 +91,13 @@ if (typeof(requestId) == 'undefined' || requestId == null) { requestId = "jsonRequest"; } + if (typeof(requestManager) == 'undefined' || requestManager == null) { + requestManager = _dummyRequestManager; + } var self = this; if(!self[name]){ - var method = new JSONRPCMethod(this._url, name, callback, errHandler, timeout, supplementData, requestId, this._user, this._password); + var method = new JSONRPCMethod(this._url, name, callback, errHandler, timeout, supplementData, requestId, + requestManager, this._user, this._password); self[name] = method; this._methods.push(method); } @@ -92,12 +111,26 @@ } } -function JSONRPCMethod(url, methodName, callback, errHandler, timeout, supplementData, requestId, user, pass) { +function _DummyRequestManager() { + } + +_DummyRequestManager.prototype.notifyServer = function(method_with_parms, url) { + method_with_parms(); + } + +_DummyRequestManager.prototype.receivedResult = function() { + } + +var _dummyRequestManager = _DummyRequestManager(); + +function JSONRPCMethod(url, methodName, callback, errHandler, timeout, supplementData, requestId, + requestManager, user, pass) { this.methodName = methodName; this.callback = callback; this.errHandler = errHandler; this.supplementData = supplementData; this.requestId = requestId; + this.requestManager = requestManager; this.url = url; this.user = user; this.password = pass; @@ -132,26 +165,30 @@ } if(self.callback) { var data = self.jsonRequest(requestId, self.methodName, args); - self.postData(self.url, self.user, self.password, data, timeout, function(resp){ - var res = null; - var exc = null; - try { - res = self.handleResponse(resp); - } catch(e) { - if (e.name == 'JSONRPCError' && self.errHandler) { - exc = e; + var do_postdata = function() { + self.postData(self.url, self.user, self.password, data, timeout, function(resp){ + var res = null; + var exc = null; + try { + res = self.handleResponse(resp); + } catch(e) { + if (e.name == 'JSONRPCError' && self.errHandler) { + exc = e; + } else { + throw(e); + } + } + self.requestManager.receivedResult(); + if (exc == null) { + self.callback(res, supplementData, requestId); } else { - throw(e); + self.errHandler(exc, supplementData, requestId); } - } - if (exc == null) { - self.callback(res, supplementData, requestId); - } else { - self.errHandler(exc, supplementData, requestId); - } - args = null; - resp = null; - }); + args = null; + resp = null; + }); + } + self.requestManager.notifyServer(do_postdata, self.url + '/' + self.methodName); } else { var data = self.jsonRequest(requestId, self.methodName, args); var resp = self.postData(self.url, self.user, self.password, data, timeout); @@ -159,7 +196,6 @@ } } return fn; - } JSONRPCMethod.prototype.postData = function(url, user, pass, data, timeout, callback) { Added: z3/jsonserver/branch/merge/browser/logging.js ============================================================================== --- (empty file) +++ z3/jsonserver/branch/merge/browser/logging.js Tue Apr 18 17:11:16 2006 @@ -0,0 +1,23 @@ +/* Set up logging with Mochikit, if that is installed */ + +/* Create jsonrpc namespace */ + +if (typeof(jsonrpc) == 'undefined') { + var jsonrpc = {}; +} + +/* check whether the logging stuff of MochiKit is available */ +try { + MochiKit.Logging.log('Initializing jsonrpc'); + jsonrpc.log = MochiKit.Logging.log; + jsonrpc.logError = MochiKit.Logging.logError; + jsonrpc.logDebug = MochiKit.Logging.logDebug; + jsonrpc.logFatal = MochiKit.Logging.logFatal; + jsonrpc.logWarning = MochiKit.Logging.logWarning; +} catch(e) { + jsonrpc.log = function(str){}; + jsonrpc.logError = jsonrpc.log; + jsonrpc.logDebug = jsonrpc.log; + jsonrpc.logFatal = jsonrpc.log; + jsonrpc.logWarning = jsonrpc.log; +} Added: z3/jsonserver/branch/merge/browser/requestmanager.js ============================================================================== --- (empty file) +++ z3/jsonserver/branch/merge/browser/requestmanager.js Tue Apr 18 17:11:16 2006 @@ -0,0 +1,141 @@ +/* Request manager + +This limits the number of outgoing requests. Extra +requests are stored and sent out on demand. + +XXX Requests never, at the moment, time out from the queue +TODO should take care of this. + +It is possible to have more instances and have different methods +queue up in different queues. + +Usage: + +- instantiate a queue +- use it as a parameter for addMethod +- it will only queue async requests. + +Usage manually: + +- notifyServer(func, url) , where func is a partial containing + all parameters, +- receivedResult() when result is received or an error is signalled. + +*/ + +jsonrpc.RequestManager = function (name, maxNr) { + this.waitingQueue = new jsonrpc.FifoQueue(); + this.sentNr = 0; + if (typeof(name) == undefined) { + name = null; + } + this.name = name; + var namestr = ''; + if (name != null) { + namestr = '[' + name + '] ' + } + this.namestr = namestr; + if (typeof(maxNr) != undefined && maxNr != null) { + this.maxNr = maxNr; + } +} + +// max request nr +jsonrpc.RequestManager.prototype.maxNr = 4; + +jsonrpc.RequestManager.prototype.getInfo = function() { + return '(RQ: ' + this.sentNr + ' OUT, ' + this.waitingQueue.size() + ' WAI)'; +} + +jsonrpc.RequestManager.prototype.log = function(txt) { + jsonrpc.logDebug('RequestManager ' + this.namestr + txt + ' ' + this.getInfo()); +} + +jsonrpc.RequestManager.prototype.pushWaitingRequest = function(func, url) { + this.waitingQueue.push([func, url]); +} + +jsonrpc.RequestManager.prototype.popWaitingRequest = function() { + return this.waitingQueue.pop(); +} + +jsonrpc.RequestManager.prototype.isWaitingRequestQueueEmpty = function() { + return this.waitingQueue.empty(); +} + +jsonrpc.RequestManager.prototype.pushSentRequest = function(func, url) { + // we do not store the elems, since they are not needed now + this.sentNr = this.sentNr + 1; +} + +jsonrpc.RequestManager.prototype.popSentRequest = function() { + this.sentNr = this.sentNr - 1; +} + +jsonrpc.RequestManager.prototype.isSentRequestQueueFull = function() { + return (this.sentNr >= this.maxNr) +} + +/* request manager notification API */ + +jsonrpc.RequestManager.prototype.notifyServer = function(func, url) { + // func must be a partial (e.g. use Mochikit or wrap up) + // here url is only for the logging + if (! jsonrpc.requestManager.isSentRequestQueueFull()) { + // can be sent if we are not over the limit. + this.pushSentRequest(func, url); + this.log('Notify server at ' + url); + func(); + } else { + this.pushWaitingRequest(func, url); + this.log('Queue server notification at ' + url); + } +} + +jsonrpc.RequestManager.prototype.receivedResult = function() { + // must be called when one result arrived + // Mark that we have one less request out. + jsonrpc.requestManager.popSentRequest(); + if (! jsonrpc.requestManager.isWaitingRequestQueueEmpty()) { + // see if we can send another request in place of the received one + // request is waiting, send it. + var waiting = jsonrpc.requestManager.popWaitingRequest(); + var func = waiting[0]; + var url = waiting[1]; + jsonrpc.requestManager.pushSentRequest(func, url); + this.log("Send queued notification to server at " + url); + func(); + } else { + this.log("Request queue empty."); + } +} + +/* simple FIFO queue */ + +jsonrpc.FifoQueue = function () { + this.reset(); +} + +jsonrpc.FifoQueue.prototype.reset = function() { + this.elements = new Array(); +} + +jsonrpc.FifoQueue.prototype.push = function(obj) { + this.elements.push(obj); +} + +jsonrpc.FifoQueue.prototype.pop = function() { + return this.elements.shift(); +} + +jsonrpc.FifoQueue.prototype.empty = function() { + return ! this.elements.length; +} + +jsonrpc.FifoQueue.prototype.size = function() { + return this.elements.length; +} + +jsonrpc.FifoQueue.prototype.front = function() { + return this.elements[0]; +} From reebalazs at codespeak.net Tue Apr 18 17:24:58 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Tue Apr 18 17:24:59 2006 Subject: [z3-checkins] r25957 - z3/jsonserver/branch/merge/browser Message-ID: <20060418152458.4EE041009C@code0.codespeak.net> Author: reebalazs Date: Tue Apr 18 17:24:57 2006 New Revision: 25957 Modified: z3/jsonserver/branch/merge/browser/requestmanager.js Log: Fix request manager Modified: z3/jsonserver/branch/merge/browser/requestmanager.js ============================================================================== --- z3/jsonserver/branch/merge/browser/requestmanager.js (original) +++ z3/jsonserver/branch/merge/browser/requestmanager.js Tue Apr 18 17:24:57 2006 @@ -81,7 +81,7 @@ jsonrpc.RequestManager.prototype.notifyServer = function(func, url) { // func must be a partial (e.g. use Mochikit or wrap up) // here url is only for the logging - if (! jsonrpc.requestManager.isSentRequestQueueFull()) { + if (! this.isSentRequestQueueFull()) { // can be sent if we are not over the limit. this.pushSentRequest(func, url); this.log('Notify server at ' + url); @@ -95,14 +95,14 @@ jsonrpc.RequestManager.prototype.receivedResult = function() { // must be called when one result arrived // Mark that we have one less request out. - jsonrpc.requestManager.popSentRequest(); - if (! jsonrpc.requestManager.isWaitingRequestQueueEmpty()) { + this.popSentRequest(); + if (! this.isWaitingRequestQueueEmpty()) { // see if we can send another request in place of the received one // request is waiting, send it. - var waiting = jsonrpc.requestManager.popWaitingRequest(); + var waiting = this.popWaitingRequest(); var func = waiting[0]; var url = waiting[1]; - jsonrpc.requestManager.pushSentRequest(func, url); + this.pushSentRequest(func, url); this.log("Send queued notification to server at " + url); func(); } else { From reebalazs at codespeak.net Thu Apr 20 08:24:18 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Thu Apr 20 08:24:21 2006 Subject: [z3-checkins] r26014 - z3/jsonserver/branch/merge/concatresource Message-ID: <20060420062418.9E24E100C6@code0.codespeak.net> Author: reebalazs Date: Thu Apr 20 08:24:15 2006 New Revision: 26014 Modified: z3/jsonserver/branch/merge/concatresource/concatresource.py Log: Adjust Five import to Zope 2.9 / Five 1.3 Modified: z3/jsonserver/branch/merge/concatresource/concatresource.py ============================================================================== --- z3/jsonserver/branch/merge/concatresource/concatresource.py (original) +++ z3/jsonserver/branch/merge/concatresource/concatresource.py Thu Apr 20 08:24:15 2006 @@ -13,7 +13,14 @@ from zope.app.publisher.browser.resource import Resource else: __five__ = True - from Products.Five.resource import Resource + try: + # Zope 2.8 / Five 1.0.2 + from Products.Five.resource import Resource + __five_pre_1_3_ = True + except ImportError: + # Zope 2.9 / Five 1.3 + from Products.Five.browser.resource import Resource + __five_pre_1_3__ = False class GenericResource(BrowserView, Resource): """A publishable resource""" From reebalazs at codespeak.net Thu Apr 20 10:53:49 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Thu Apr 20 10:53:50 2006 Subject: [z3-checkins] r26020 - z3/jsonserver/branch/merge/browser Message-ID: <20060420085349.DE93410087@code0.codespeak.net> Author: reebalazs Date: Thu Apr 20 10:53:48 2006 New Revision: 26020 Modified: z3/jsonserver/branch/merge/browser/json.js Log: Critical fix (self.requestManager has no properties) Modified: z3/jsonserver/branch/merge/browser/json.js ============================================================================== --- z3/jsonserver/branch/merge/browser/json.js (original) +++ z3/jsonserver/branch/merge/browser/json.js Thu Apr 20 10:53:48 2006 @@ -121,7 +121,7 @@ _DummyRequestManager.prototype.receivedResult = function() { } -var _dummyRequestManager = _DummyRequestManager(); +var _dummyRequestManager = new _DummyRequestManager(); function JSONRPCMethod(url, methodName, callback, errHandler, timeout, supplementData, requestId, requestManager, user, pass) { From reebalazs at codespeak.net Thu Apr 20 12:08:26 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Thu Apr 20 12:08:28 2006 Subject: [z3-checkins] r26026 - z3/jsonserver/branch/zope2_test Message-ID: <20060420100826.D51C31008D@code0.codespeak.net> Author: reebalazs Date: Thu Apr 20 12:08:25 2006 New Revision: 26026 Modified: z3/jsonserver/branch/zope2_test/jsonrpc.py Log: Make the IJsonRequest interface bound in Zope 2.9 In 2.9 I realized that the interface binding does not work somehow directlyProvides attaches the interfact but it disappears later where I want to use it for an adapter lookup. Now we provide the interface in the class level and override __class__ of the request object on the run. Modified: z3/jsonserver/branch/zope2_test/jsonrpc.py ============================================================================== --- z3/jsonserver/branch/zope2_test/jsonrpc.py (original) +++ z3/jsonserver/branch/zope2_test/jsonrpc.py Thu Apr 20 12:08:25 2006 @@ -21,8 +21,10 @@ from zLOG import LOG, INFO, DEBUG, WARNING, ERROR from cgi import FieldStorage import ZPublisher.HTTPResponse -from zope.interface import directlyProvides, directlyProvidedBy +##from zope.interface import directlyProvides, directlyProvidedBy +from zope.interface import implements from interfaces import IJsonRequest +from ZPublisher.HTTPRequest import HTTPRequest # this is used to identify incoming requests request_content_type = 'application/json-rpc' @@ -198,6 +200,11 @@ # Patching processInputs of ZPublisher.HTTPRequest # -- +class JsonRpcRequest(HTTPRequest): + 'JSON-RPC HTTP request' + # this is just used to force the interface on the object + implements(IJsonRequest) + re_content_type= re.compile(r'charset\s*=\s*([^;]+)') def processInputs(self, **kw): @@ -245,9 +252,13 @@ # set the marker that can be used to check if we are in json mode other['JSON_MODE'] = self.json_mode = True # also set the request interface - interfaces = directlyProvidedBy(self) - interfaces += IJsonRequest - directlyProvides(self, interfaces) + # XXX this would be good but for some reason gets "swallowed" + # by the time we get there, so we override the class instead. + # This error first manifested in Zope2.9, it was ok. till 2.8. + ##interfaces = directlyProvidedBy(self) + ##interfaces += IJsonRequest + ##directlyProvides(self, interfaces) + self.__class__ = JsonRpcRequest # response = Response(response, jsonID) other['RESPONSE'] = self.response = response @@ -264,7 +275,6 @@ self.stdin.seek(0) return self._processInputs_jsonrc_patched(**kw) -from ZPublisher.HTTPRequest import HTTPRequest def patch_HTTPRequest(): 'This will patch HTTPRequest to enable json-rpc handling' HTTPRequest._processInputs_jsonrc_patched, HTTPRequest.processInputs = \ From reebalazs at codespeak.net Fri Apr 21 09:32:09 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Fri Apr 21 09:32:12 2006 Subject: [z3-checkins] r26075 - in z3/jsonserver/branch/merge/concatresource: . compression test Message-ID: <20060421073209.DC6DB1007D@code0.codespeak.net> Author: reebalazs Date: Fri Apr 21 09:32:05 2006 New Revision: 26075 Added: z3/jsonserver/branch/merge/concatresource/README Modified: z3/jsonserver/branch/merge/concatresource/compression/__init__.py z3/jsonserver/branch/merge/concatresource/compression/css.py z3/jsonserver/branch/merge/concatresource/compression/javascript.py z3/jsonserver/branch/merge/concatresource/concatfileresource.py z3/jsonserver/branch/merge/concatresource/concatresource.py z3/jsonserver/branch/merge/concatresource/directives.py z3/jsonserver/branch/merge/concatresource/meta.py z3/jsonserver/branch/merge/concatresource/test/configure.zcml Log: Adding compress_level as attribute, choices are "none", "safe", "full" Added: z3/jsonserver/branch/merge/concatresource/README ============================================================================== --- (empty file) +++ z3/jsonserver/branch/merge/concatresource/README Fri Apr 21 09:32:05 2006 @@ -0,0 +1,72 @@ + +Objectives +---------- + +I made this utility for the works in the jsonserver integration and +AZAX/kukit. This was meant to be a temporary, lightweight solution but it +has long term merits too. I needed this because I wanted a solution that +works right now, works on zope3 and zope 2.8 even (so zc.resourcelibraries +was not a choice), does not depend on Plone (so ResourceRegistries is out +too). + +The interesting point of the utility is: instead of building registries to +emit include tags in the HTML, it simply makes one resource that needs to +be imported in a single line:: + + + +Also: + +- it compresses the JS or CSS files with Florian Schulze's compressor + from ResourceRegistries + +- it contains an utility interface that another component can implement + to dynamically extend the list of files (like I did with AZAX). So the + "registry" is not really implemented but can be plugged in. + +- it is tested (although not much) to work with Zope 2.8, 2.9, 3.1, 3.2 + +Meanwhile I implemented the cache headers for the resources correctly +here, the current implementation of caching is broken in Five and I +believe in Z3 resources as well; beware that I considered the original +Zope3 code only and did not look at additional utilities. According to my +observation: in Z3 the original resources attempt to handle the cache +headers correctly but never really check if the file gets changed on the +filesystem (only on restart). If this is really a problem and not just I +believe, then it is fixed in my code. + +More information on this issue: + +http://article.gmane.org/gmane.comp.web.zope.z3base.general/53 + +Compression +----------- + +You can use more levels of compressions with the compress_level attribute. + + + +Some explanation: + +- compression is only implemented for JavaScript and CSS + +- The default level is "safe", this is useable with all scripts + +- The "full" level gives even better compression by taking out all newlines + and mangling private variable names, but some preparation must be made + in the scripts for that (like putting a ; after }-s I think, and + also maybe more). + +- Specifying "none" will leave your resource uncompressed. This + can be useful for debugging. + + Modified: z3/jsonserver/branch/merge/concatresource/compression/__init__.py ============================================================================== --- z3/jsonserver/branch/merge/concatresource/compression/__init__.py (original) +++ z3/jsonserver/branch/merge/concatresource/compression/__init__.py Fri Apr 21 09:32:05 2006 @@ -14,7 +14,7 @@ default_compress_method = lambda text: text -def compress(data, content_type): +def compress(data, content_type, compress_level): 'Returns compressed text for a given content type' method = compress_methods.get(content_type, default_compress_method) - return method(data) + return method(data, compress_level) Modified: z3/jsonserver/branch/merge/concatresource/compression/css.py ============================================================================== --- z3/jsonserver/branch/merge/concatresource/compression/css.py (original) +++ z3/jsonserver/branch/merge/concatresource/compression/css.py Fri Apr 21 09:32:05 2006 @@ -5,7 +5,14 @@ from thirdparty.packer import CSSPacker -csspacker_full = CSSPacker('safe') +csspacker_safe = CSSPacker('safe') +csspacker_full = CSSPacker('full') -def compress(data): - return csspacker_full.pack(data) +def compress(data, compress_level): + if compress_level == "safe": + return csspacker_safe.pack(data) + elif compress_level == "full": + return csspacker_full.pack(data) + else: + # none + return data Modified: z3/jsonserver/branch/merge/concatresource/compression/javascript.py ============================================================================== --- z3/jsonserver/branch/merge/concatresource/compression/javascript.py (original) +++ z3/jsonserver/branch/merge/concatresource/compression/javascript.py Fri Apr 21 09:32:05 2006 @@ -4,7 +4,14 @@ from thirdparty.packer import JavascriptPacker -jspacker_full = JavascriptPacker('safe') +jspacker_safe = JavascriptPacker('safe') +jspacker_full = JavascriptPacker('full') -def compress(data): - return jspacker_full.pack(data) +def compress(data, compress_level): + if compress_level == "safe": + return jspacker_safe.pack(data) + elif compress_level == "full": + return jspacker_full.pack(data) + else: + # none + return data Modified: z3/jsonserver/branch/merge/concatresource/concatfileresource.py ============================================================================== --- z3/jsonserver/branch/merge/concatresource/concatfileresource.py (original) +++ z3/jsonserver/branch/merge/concatresource/concatfileresource.py Fri Apr 21 09:32:05 2006 @@ -24,7 +24,7 @@ ''' implements(IContextFile) - def __init__(self, pathlist, name): + def __init__(self, pathlist, name, compress_level): # Path is now a list. assert isinstance(pathlist, (list, tuple)) # check all files, just to raise error if don't exist @@ -33,6 +33,7 @@ # self.pathlist_base = pathlist self.__name__ = name + self.compress_level = compress_level # markers for pathlist modification self.pathlist = [] self.fileslist_changed = None @@ -88,6 +89,7 @@ assert d['content_type'] == content_type data.append(d['data']) result['data'] = '\n'.join(data) + result['compress_level'] = self.compress_level # Do compression on the result result['data'] = compress(**result) return result Modified: z3/jsonserver/branch/merge/concatresource/concatresource.py ============================================================================== --- z3/jsonserver/branch/merge/concatresource/concatresource.py (original) +++ z3/jsonserver/branch/merge/concatresource/concatresource.py Fri Apr 21 09:32:05 2006 @@ -104,9 +104,10 @@ factory = None resource = None - def __init__(self, path, name, resource_factory=None, checker=None): + def __init__(self, path, name, compress_level, resource_factory=None, checker=None): self.__name = name self.__path = path + self.__compress_level = compress_level if resource_factory is not None: self.resource = resource_factory # z3 only @@ -117,7 +118,7 @@ rsrc = self.__rsrc except AttributeError: # Delayed creation. That assures that registry is set up by this time. - rsrc = self.__rsrc = ICachedResource(self.factory(self.__path, self.__name)) + rsrc = self.__rsrc = ICachedResource(self.factory(self.__path, self.__name, self.__compress_level)) resource = self.resource(rsrc, request) # z3 only resource.__name__ = self.__name Modified: z3/jsonserver/branch/merge/concatresource/directives.py ============================================================================== --- z3/jsonserver/branch/merge/concatresource/directives.py (original) +++ z3/jsonserver/branch/merge/concatresource/directives.py Fri Apr 21 09:32:05 2006 @@ -1,7 +1,7 @@ from zope.interface import Interface from zope.configuration.fields import GlobalObject, Tokens, Path, \ PythonIdentifier, MessageID -from zope.schema import TextLine, Text, Id +from zope.schema import TextLine, Text, Id, Choice from zope.app.security.fields import Permission from fields import PathList from zope.app.component.metadirectives import IBasicViewInformation @@ -29,3 +29,10 @@ description=u"A space separated list of resource files", required=True ) + + compress_level = Choice( + title=u"Compress level", + description=u"Level of compression applied, by default 'safe'.", + values=(u'none', u'safe', u'full'), + required=False, + ) Modified: z3/jsonserver/branch/merge/concatresource/meta.py ============================================================================== --- z3/jsonserver/branch/merge/concatresource/meta.py (original) +++ z3/jsonserver/branch/merge/concatresource/meta.py Fri Apr 21 09:32:05 2006 @@ -39,7 +39,7 @@ }, } -def concatresource(_context, name, files=None, layer=_layer, permission='zope.Public'): +def concatresource(_context, name, files=None, compress_level='safe', layer=_layer, permission='zope.Public'): if not files: raise ConfigurationError( @@ -78,7 +78,7 @@ checker = NamesChecker(allowed_names, permission) - factory = res_factory(res, name, resource_factory=new_class, checker=checker) + factory = res_factory(res, name, compress_level, resource_factory=new_class, checker=checker) if __pre_3_2__: _context.action( Modified: z3/jsonserver/branch/merge/concatresource/test/configure.zcml ============================================================================== --- z3/jsonserver/branch/merge/concatresource/test/configure.zcml (original) +++ z3/jsonserver/branch/merge/concatresource/test/configure.zcml Fri Apr 21 09:32:05 2006 @@ -8,4 +8,11 @@ test2.js" /> + + From jinty at codespeak.net Fri Apr 21 15:15:08 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Fri Apr 21 15:15:11 2006 Subject: [z3-checkins] r26099 - in z3/sqlos/trunk/src/sqlos: . testing tests Message-ID: <20060421131508.B733310084@code0.codespeak.net> Author: jinty Date: Fri Apr 21 15:14:55 2006 New Revision: 26099 Modified: z3/sqlos/trunk/src/sqlos/README.txt z3/sqlos/trunk/src/sqlos/__init__.py z3/sqlos/trunk/src/sqlos/testing/sampleperson.py z3/sqlos/trunk/src/sqlos/tests/test_doctests.py Log: move sqlos._sqlos to sqlos.zsqlobject and softly deprecate the import of SQLOS from sqlos. Modified: z3/sqlos/trunk/src/sqlos/README.txt ============================================================================== --- z3/sqlos/trunk/src/sqlos/README.txt (original) +++ z3/sqlos/trunk/src/sqlos/README.txt Fri Apr 21 15:14:55 2006 @@ -198,7 +198,7 @@ >>> from zope.interface import implements >>> from sqlobject import * - >>> from sqlos import SQLOS + >>> from sqlos.zsqlobject import SQLOS >>> class Person(SQLOS): ... implements(IPerson) Modified: z3/sqlos/trunk/src/sqlos/__init__.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/__init__.py (original) +++ z3/sqlos/trunk/src/sqlos/__init__.py Fri Apr 21 15:14:55 2006 @@ -16,7 +16,10 @@ import zope.component from sqlobject.sqlbuilder import registerConverter -from _sqlos import SQLOS +# sqlos.SQLOS is softly deprecated, will go away sometime +# (after at least one major release with deprecation warnings) +# import directly from sqlos.zsqlobject +from sqlos.zsqlobject import SQLOS def caller(n=1): """Return the name of the calling function n levels up in the frame stack. Modified: z3/sqlos/trunk/src/sqlos/testing/sampleperson.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/testing/sampleperson.py (original) +++ z3/sqlos/trunk/src/sqlos/testing/sampleperson.py Fri Apr 21 15:14:55 2006 @@ -4,7 +4,7 @@ from zope.schema import TextLine, Text, Datetime from zope.app.container import constraints -from sqlos import SQLOS +from sqlos.zsqlobject import SQLOS from sqlos.interfaces import ISQLSchema, IISQLObjectIsolated, ISQLObjectIsolated from sqlos.interfaces.container import ISQLObjectContainer from sqlos.container import SQLObjectContainer, SQLIsolatedContainer Modified: z3/sqlos/trunk/src/sqlos/tests/test_doctests.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/tests/test_doctests.py (original) +++ z3/sqlos/trunk/src/sqlos/tests/test_doctests.py Fri Apr 21 15:14:55 2006 @@ -26,5 +26,5 @@ DocTestSuite('sqlos.container', optionflags=doctest.ELLIPSIS), DocTestSuite('sqlos.connection'), DocTestSuite('sqlos._transaction'), - DocTestSuite('sqlos._sqlos') + DocTestSuite('sqlos.zsqlobject') ]) From jinty at codespeak.net Fri Apr 21 15:23:02 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Fri Apr 21 15:23:03 2006 Subject: [z3-checkins] r26100 - z3/sqlos/trunk/src/sqlos Message-ID: <20060421132302.83ADD10084@code0.codespeak.net> Author: jinty Date: Fri Apr 21 15:22:59 2006 New Revision: 26100 Modified: z3/sqlos/trunk/src/sqlos/__init__.py Log: Remove cruft and deprecated code. Also drop an XXX for untested code. Modified: z3/sqlos/trunk/src/sqlos/__init__.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/__init__.py (original) +++ z3/sqlos/trunk/src/sqlos/__init__.py Fri Apr 21 15:22:59 2006 @@ -10,10 +10,7 @@ $Id$ """ -__metaclass__ = type - from datetime import datetime, date -import zope.component from sqlobject.sqlbuilder import registerConverter # sqlos.SQLOS is softly deprecated, will go away sometime @@ -21,14 +18,8 @@ # import directly from sqlos.zsqlobject from sqlos.zsqlobject import SQLOS -def caller(n=1): - """Return the name of the calling function n levels up in the frame stack. - Ex: caller(0) ==> 'caller'; def f(): return caller(); f() ==> 'f' - """ - import inspect - return inspect.getouterframes(inspect.currentframe())[n][3] - +## XXX: What are these?? I am sure there are no tests for them. - jinty def DateTimeConverter(value, db=None): return repr(value.isoformat()) @@ -40,19 +31,3 @@ return repr(value.isoformat()) registerConverter(date, DateConverter) - - -def getFactory(name, context=None, default=None): - # XXX - deprecated, goes away after sqlos 0.2 - return zope.component.queryUtility(IISQLObject, name, default=default, context=context) - -from zope.deprecation import deprecated -msg = "getFactory is depreciated and will go away after sqlos 0.2 you should \ -replace this with a direct call to \ -zope.component.getUtility(IISQLObject, name, context=context) if you need the \ -functionailty of a SQLObject class, or \ -zope.component.getUtility(IFactory, name, context=context) if you want to use it as a \ -factory." - -deprecated("getFactory", msg) -deprecated("caller", "sqlos.caller is deprecated and will be removed after sqlos 0.2") From jinty at codespeak.net Fri Apr 21 15:28:47 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Fri Apr 21 15:28:48 2006 Subject: [z3-checkins] r26101 - z3/sqlos/trunk/src/sqlos Message-ID: <20060421132847.95ACE10084@code0.codespeak.net> Author: jinty Date: Fri Apr 21 15:28:44 2006 New Revision: 26101 Modified: z3/sqlos/trunk/src/sqlos/container.py Log: Remove the deprecated allowedFactories method. Modified: z3/sqlos/trunk/src/sqlos/container.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/container.py (original) +++ z3/sqlos/trunk/src/sqlos/container.py Fri Apr 21 15:28:44 2006 @@ -17,7 +17,6 @@ from persistent import Persistent from zope.interface import implements from zope.component import IFactory -from zope import deprecation import zope.component from zope.app.container.interfaces import IContained from zope.app.container.contained import ContainedProxy @@ -86,14 +85,6 @@ def __init__(self): pass - def _allowedFactories(self): - for name, factory in zope.component.getFactoriesFor(ISQLObject): - if checkFactory(self, None, factory): - yield name - allowedFactories = deprecation.deprecated(_allowedFactories, - 'allowedFactories is deprecated and will be removed after sqlos 0.2' - ' please use _getAllowedIISQLObjectUtilities instead.') - def _getAllowedIISQLObjectUtilities(self): for name, factory in zope.component.getFactoriesFor(ISQLObject): if checkFactory(self, None, factory): @@ -209,16 +200,6 @@ _container_id = None - def allowedFactories(self): - # Ignore all factories not implementing ISQLObjectIsolated - for f in SQLObjectContainer._allowedFactories(self): - implemented = zope.component.getFactoryInterfaces(f) - if implemented.isOrExtends(ISQLObjectIsolated): - yield f - allowedFactories = deprecation.deprecated(allowedFactories, - 'allowedFactories is deprecated and will be removed after sqlos 0.2' - ' please use _getAllowedIISQLObjectUtilities instead.') - def _getAllowedIISQLObjectUtilities(self): # Ignore all utilities not implementing ISQLObjectIsolated for name, utility in SQLObjectContainer._getAllowedIISQLObjectUtilities(self): From reebalazs at codespeak.net Sat Apr 22 11:38:13 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Sat Apr 22 11:38:14 2006 Subject: [z3-checkins] r26122 - z3/jsonserver/branch/merge/utils Message-ID: <20060422093813.22ACE1008D@code0.codespeak.net> Author: reebalazs Date: Sat Apr 22 11:38:12 2006 New Revision: 26122 Added: z3/jsonserver/branch/merge/utils/ Log: create utils subdir From reebalazs at codespeak.net Sat Apr 22 11:38:20 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Sat Apr 22 11:38:21 2006 Subject: [z3-checkins] r26123 - z3/jsonserver/branch/merge/utils Message-ID: <20060422093820.6EC4310097@code0.codespeak.net> Author: reebalazs Date: Sat Apr 22 11:38:18 2006 New Revision: 26123 Added: z3/jsonserver/branch/merge/utils/pyclient - copied unchanged from r26122, z3/jsonserver/branch/zope2_test/pyclient.py Log: move file to utils From reebalazs at codespeak.net Sat Apr 22 11:42:03 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Sat Apr 22 11:42:05 2006 Subject: [z3-checkins] r26125 - z3/jsonserver/branch/merge/utils Message-ID: <20060422094203.DE93710098@code0.codespeak.net> Author: reebalazs Date: Sat Apr 22 11:42:02 2006 New Revision: 26125 Modified: z3/jsonserver/branch/merge/utils/pyclient Log: Add comment to pyclient Modified: z3/jsonserver/branch/merge/utils/pyclient ============================================================================== --- z3/jsonserver/branch/merge/utils/pyclient (original) +++ z3/jsonserver/branch/merge/utils/pyclient Sat Apr 22 11:42:02 2006 @@ -1,15 +1,25 @@ +#! /usr/bin/python '''\ A python client for jsonserver. -This is a separate file that is not needed for jsonserver to work. +This is a separate utility that is not needed for jsonserver to work. It can be used to - test json components from the command line - create a standalone python json-rpc client. -This file needs to import minjson.py, it uses nothing else -from the server. +This utility will only work if the following packages are +importable from python: + + minjson + zope.component + zope.interface + +Since neither minjson nor the zope component architecture +are distributed as standalone at the moment, +you have to arrange this yourself (e.g. symlinking to +site-packages) ''' import urllib2 From reebalazs at codespeak.net Sat Apr 22 11:47:05 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Sat Apr 22 11:47:08 2006 Subject: [z3-checkins] r26126 - z3/jsonserver/branch/merge/utils Message-ID: <20060422094705.EDBAD1009B@code0.codespeak.net> Author: reebalazs Date: Sat Apr 22 11:47:04 2006 New Revision: 26126 Added: z3/jsonserver/branch/merge/utils/tcpwatch (contents, props changed) Log: Include tcpwatch original version Added: z3/jsonserver/branch/merge/utils/tcpwatch ============================================================================== --- (empty file) +++ z3/jsonserver/branch/merge/utils/tcpwatch Sat Apr 22 11:47:04 2006 @@ -0,0 +1,1485 @@ +#!/usr/bin/python + +############################################################################# +# +# Zope Public License (ZPL) Version 2.0 +# ----------------------------------------------- +# +# This software is Copyright (c) Zope Corporation (tm) and +# Contributors. All rights reserved. +# +# This license has been certified as open source. It has also +# been designated as GPL compatible by the Free Software +# Foundation (FSF). +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the +# following conditions are met: +# +# 1. Redistributions in source code must retain the above +# copyright notice, this list of conditions, and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions, and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# 3. The name Zope Corporation (tm) must not be used to +# endorse or promote products derived from this software +# without prior written permission from Zope Corporation. +# +# 4. The right to distribute this software or to use it for +# any purpose does not give you the right to use Servicemarks +# (sm) or Trademarks (tm) of Zope Corporation. Use of them is +# covered in a separate agreement (see +# http://www.zope.com/Marks). +# +# 5. If any files are modified, you must cause the modified +# files to carry prominent notices stating that you changed +# the files and the date of any change. +# +# Disclaimer +# +# THIS SOFTWARE IS PROVIDED BY ZOPE CORPORATION ``AS IS'' +# AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT +# NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN +# NO EVENT SHALL ZOPE CORPORATION OR ITS CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +# DAMAGE. +# +# +# This software consists of contributions made by Zope +# Corporation and many individuals on behalf of Zope +# Corporation. Specific attributions are listed in the +# accompanying credits file. +# +############################################################################# +"""TCPWatch, a connection forwarder and HTTP proxy for monitoring connections. + +Requires Python 2.1 or above. + +Revision information: +$Id: tcpwatch.py,v 1.9 2004/06/17 00:03:46 shane Exp $ +""" + +from __future__ import nested_scopes + +VERSION = '1.3' +COPYRIGHT = ( + 'TCPWatch %s Copyright 2001 Shane Hathaway, Zope Corporation' + % VERSION) + +import sys +import os +import socket +import asyncore +import getopt +from time import time, localtime + + +RECV_BUFFER_SIZE = 8192 +show_cr = 0 + + +############################################################################# +# +# Connection forwarder +# +############################################################################# + + +class ForwardingEndpoint (asyncore.dispatcher): + """A socket wrapper that accepts and generates stream messages. + """ + _dests = () + + def __init__(self, conn=None): + self._outbuf = [] + asyncore.dispatcher.__init__(self, conn) + + def set_dests(self, dests): + """Sets the destination streams. + """ + self._dests = dests + + def write(self, data): + if data: + self._outbuf.append(data) + self.handle_write() + + def readable(self): + return 1 + + def writable(self): + return not self.connected or len(self._outbuf) > 0 + + def handle_connect(self): + for d in self._dests: + d.write('') # A blank string means the socket just connected. + + def received(self, data): + if data: + for d in self._dests: + d.write(data) + + def handle_read(self): + data = self.recv(RECV_BUFFER_SIZE) + self.received(data) + + def handle_write(self): + if not self.connected: + # Wait for a connection. + return + buf = self._outbuf + while buf: + data = buf.pop(0) + if data: + sent = self.send(data) + if sent < len(data): + buf.insert(0, data[sent:]) + break + + def handle_close (self): + dests = self._dests + self._dests = () + for d in dests: + d.close() + self.close() + + def handle_error(self): + t, v = sys.exc_info()[:2] + for d in self._dests: + if hasattr(d, 'error'): + d.error(t, v) + self.handle_close() + + + +class EndpointObserver: + """Sends stream events to a ConnectionObserver. + + Streams don't distinguish sources, while ConnectionObservers do. + This adapter adds source information to stream events. + """ + + def __init__(self, obs, from_client): + self.obs = obs + self.from_client = from_client + + def write(self, data): + if data: + self.obs.received(data, self.from_client) + else: + self.obs.connected(self.from_client) + + def close(self): + self.obs.closed(self.from_client) + + def error(self, t, v): + self.obs.error(self.from_client, t, v) + + + +class ForwardedConnectionInfo: + transaction = 1 + + def __init__(self, connection_number, client_addr, server_addr=None): + self.opened = time() + self.connection_number = connection_number + self.client_addr = client_addr + self.server_addr = server_addr + + def dup(self): + return ForwardedConnectionInfo(self.connection_number, + self.client_addr, + self.server_addr) + + + +class ForwardingService (asyncore.dispatcher): + + _counter = 0 + + def __init__(self, listen_host, listen_port, dest_host, dest_port, + observer_factory=None): + self._obs_factory = observer_factory + self._dest = (dest_host, dest_port) + asyncore.dispatcher.__init__(self) + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.set_reuse_addr() + self.bind((listen_host, listen_port)) + self.listen(5) + + def handle_accept(self): + info = self.accept() + if info: + # Got a connection. + conn, addr = info + conn.setblocking(0) + + ep1 = ForwardingEndpoint() # connects client to self + ep2 = ForwardingEndpoint() # connects self to server + + counter = self._counter + 1 + self._counter = counter + factory = self._obs_factory + if factory is not None: + fci = ForwardedConnectionInfo(counter, addr, self._dest) + obs = factory(fci) + dests1 = (ep2, EndpointObserver(obs, 1)) + dests2 = (ep1, EndpointObserver(obs, 0)) + else: + dests1 = (ep2,) + dests2 = (ep1,) + + ep1.set_dests(dests1) + ep2.set_dests(dests2) + + # Now everything is hooked up. Let data pass. + ep2.create_socket(socket.AF_INET, socket.SOCK_STREAM) + ep1.set_socket(conn) + ep1.connected = 1 # We already know the client connected. + ep2.connect(self._dest) + + def handle_error(self): + # Don't stop the server. + import traceback + traceback.print_exc() + + + +class IConnectionObserver: + + def connected(from_client): + """Called when the client or the server connects. + """ + + def received(data, from_client): + """Called when the client or the server sends data. + """ + + def closed(from_client): + """Called when the client or the server closes the channel. + """ + + def error(from_client, type, value): + """Called when an error occurs in the client or the server channel. + """ + + +############################################################################# +# +# Basic abstract connection observer and stdout observer +# +############################################################################# + + +def escape(s): + # XXX This might be a brittle trick. :-( + return repr('"\'' + str(s))[4:-1] + + +class BasicObserver: + + continuing_line = -1 # Tracks when a line isn't finished. + arrows = ('<==', '==>') + + def __init__(self): + self._start = time() + + def _output_message(self, m, from_client): + if self.continuing_line >= 0: + self.write('\n') + self.continuing_line = -1 + if from_client: + who = 'client' + else: + who = 'server' + + t = time() - self._start + min, sec = divmod(t, 60) + self.write('[%02d:%06.3f - %s %s]\n' % (min, sec, who, m)) + self.flush() + + def connection_from(self, fci): + if fci.server_addr is not None: + self._output_message( + '%s:%s forwarded to %s:%s' % + (tuple(fci.client_addr) + tuple(fci.server_addr)), 1) + else: + self._output_message( + 'connection from %s:%s' % + (tuple(fci.client_addr)), 1) + + if fci.transaction > 1: + self._output_message( + ('HTTP transaction #%d' % fci.transaction), 1) + + def connected(self, from_client): + self._output_message('connected', from_client) + + def received(self, data, from_client): + arrow = self.arrows[from_client] + cl = self.continuing_line + if cl >= 0: + if cl != from_client: + # Switching directions. + self.write('\n%s' % arrow) + else: + self.write(arrow) + + if data.endswith('\n'): + data = data[:-1] + newline = 1 + else: + newline = 0 + + if not show_cr: + data = data.replace('\r', '') + lines = data.split('\n') + lines = map(escape, lines) + s = ('\n%s' % arrow).join(lines) + self.write(s) + + if newline: + self.write('\n') + self.continuing_line = -1 + else: + self.continuing_line = from_client + self.flush() + + def closed(self, from_client): + self._output_message('closed', from_client) + + def error(self, from_client, type, value): + self._output_message( + 'connection error %s: %s' % (type, value), from_client) + + def write(self, s): + raise NotImplementedError + + def flush(self): + raise NotImplementedError + + +class StdoutObserver (BasicObserver): + + # __implements__ = IConnectionObserver + + def __init__(self, fci): + BasicObserver.__init__(self) + self.connection_from(fci) + + def write(self, s): + sys.stdout.write(s) + + def flush(self): + sys.stdout.flush() + + +# 'log_number' is a log file counter used for naming log files. +log_number = 0 + +def nextLogNumber(): + global log_number + log_number = log_number + 1 + return log_number + + +class RecordingObserver (BasicObserver): + """Log request to a file. + + o Filenames mangle connection and transaction numbers from the + ForwardedConnectionInfo passed as 'fci'. + + o Decorates an underlying observer, created via the passed 'sub_factory'. + + o Files are created in the supplied 'record_directory'. + + o Unless suppressed, log response and error to corresponding files. + """ + _ERROR_SOURCES = ('Server', 'Client') + + # __implements__ = IConnectionObserver + + def __init__(self, fci, sub_factory, record_directory, + record_prefix='watch', record_responses=1, record_errors=1): + self._log_number = nextLogNumber() + self._decorated = sub_factory(fci) + self._directory = record_directory + self._prefix = record_prefix + self._response = record_responses + self._errors = record_errors + + def connected(self, from_client): + """See IConnectionObserver. + """ + self._decorated.connected(from_client) + + def received(self, data, from_client): + """See IConnectionObserver. + """ + if from_client or self._response: + extension = from_client and 'request' or 'response' + file = self._openForAppend(extension=extension) + file.write(data) + file.close() + self._decorated.received(data, from_client) + + def closed(self, from_client): + """See IConnectionObserver. + """ + self._decorated.closed(from_client) + + def error(self, from_client, type, value): + """See IConnectionObserver. + """ + if self._errors: + file = self._openForAppend(extension='errors') + file.write('(%s) %s: %s\n' % (self._ERROR_SOURCES[from_client], + type, value)) + self._decorated.error(from_client, type, value) + + def _openForAppend(self, extension): + """Open a file with the given extension for appending. + + o File should be in the directory indicated by self._directory. + + o File should have a filename '_.'. + """ + filename = '%s%04d.%s' % (self._prefix, self._log_number, extension) + fqpath = os.path.join(self._directory, filename) + return open(fqpath, 'a') + + +############################################################################# +# +# Tkinter GUI +# +############################################################################# + + +def setupTk(titlepart, config_info, colorized=1): + """Starts the Tk application and returns an observer factory. + """ + + import Tkinter + from ScrolledText import ScrolledText + from Queue import Queue, Empty + try: + from cStringIO import StringIO + except ImportError: + from StringIO import StringIO + + startup_text = COPYRIGHT + (""" + +Use your client to connect to the proxied port(s) then click +the list on the left to see the data transferred. + +%s +""" % config_info) + + + class TkTCPWatch (Tkinter.Frame): + '''The tcpwatch top-level window. + ''' + def __init__(self, master): + Tkinter.Frame.__init__(self, master) + self.createWidgets() + # connections maps ids to TkConnectionObservers. + self.connections = {} + self.showingid = '' + self.queue = Queue() + self.processQueue() + + def createWidgets(self): + listframe = Tkinter.Frame(self) + listframe.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) + scrollbar = Tkinter.Scrollbar(listframe, orient=Tkinter.VERTICAL) + self.connectlist = Tkinter.Listbox( + listframe, yscrollcommand=scrollbar.set, exportselection=0) + scrollbar.config(command=self.connectlist.yview) + scrollbar.pack(side=Tkinter.RIGHT, fill=Tkinter.Y) + self.connectlist.pack( + side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1) + self.connectlist.bind('', self.mouseListSelect) + self.textbox = ScrolledText(self, background="#ffffff") + self.textbox.tag_config("message", foreground="#000000") + self.textbox.tag_config("client", foreground="#007700") + self.textbox.tag_config( + "clientesc", foreground="#007700", background="#dddddd") + self.textbox.tag_config("server", foreground="#770000") + self.textbox.tag_config( + "serveresc", foreground="#770000", background="#dddddd") + self.textbox.insert(Tkinter.END, startup_text, "message") + self.textbox.pack(side='right', fill=Tkinter.BOTH, expand=1) + self.pack(fill=Tkinter.BOTH, expand=1) + + def addConnection(self, id, conn): + self.connections[id] = conn + connectlist = self.connectlist + connectlist.insert(Tkinter.END, id) + + def updateConnection(self, id, output): + if id == self.showingid: + textbox = self.textbox + for data, style in output: + textbox.insert(Tkinter.END, data, style) + + def mouseListSelect(self, event=None): + connectlist = self.connectlist + idx = connectlist.nearest(event.y) + sel = connectlist.get(idx) + connections = self.connections + if connections.has_key(sel): + self.showingid = '' + output = connections[sel].getOutput() + self.textbox.delete(1.0, Tkinter.END) + for data, style in output: + self.textbox.insert(Tkinter.END, data, style) + self.showingid = sel + + def processQueue(self): + try: + if not self.queue.empty(): + # Process messages for up to 1/4 second + from time import time + limit = time() + 0.25 + while time() < limit: + try: + f, args = self.queue.get_nowait() + except Empty: + break + f(*args) + finally: + self.master.after(50, self.processQueue) + + + class TkConnectionObserver (BasicObserver): + '''A connection observer which shows captured data in a TCPWatch + frame. The data is mangled for presentation. + ''' + # __implements__ = IConnectionObserver + + def __init__(self, frame, fci, colorized=1): + BasicObserver.__init__(self) + self._output = [] # list of tuples containing (text, style) + self._frame = frame + self._colorized = colorized + t = localtime(fci.opened) + if fci.transaction > 1: + base_id = '%03d-%02d' % ( + fci.connection_number, fci.transaction) + else: + base_id = '%03d' % fci.connection_number + id = '%s (%02d:%02d:%02d)' % (base_id, t[3], t[4], t[5]) + self._id = id + frame.queue.put((frame.addConnection, (id, self))) + self.connection_from(fci) + + def write(self, s): + output = [(s, "message")] + self._output.extend(output) + self._frame.queue.put( + (self._frame.updateConnection, (self._id, output))) + + def flush(self): + pass + + def received(self, data, from_client): + if not self._colorized: + BasicObserver.received(self, data, from_client) + return + + if not show_cr: + data = data.replace('\r', '') + + output = [] + + extra_color = (self._colorized == 2) + + if extra_color: + # 4 colors: Change the color client/server and escaped chars + def append(ss, escaped, output=output, + from_client=from_client, escape=escape): + if escaped: + output.append((escape(ss), from_client + and 'clientesc' or 'serveresc')) + else: + output.append((ss, from_client + and 'client' or 'server')) + else: + # 2 colors: Only change color for client/server + segments = [] + def append(ss, escaped, segments=segments, + escape=escape): + if escaped: + segments.append(escape(ss)) + else: + segments.append(ss) + + # Escape the input data. + was_escaped = 0 + start_idx = 0 + for idx in xrange(len(data)): + c = data[idx] + escaped = (c < ' ' and c != '\n') or c >= '\x80' + if was_escaped != escaped: + ss = data[start_idx:idx] + if ss: + append(ss, was_escaped) + was_escaped = escaped + start_idx = idx + ss = data[start_idx:] + if ss: + append(ss, was_escaped) + + if not extra_color: + output.append((''.join(segments), + from_client and 'client' or 'server')) + + # Send output to the frame. + self._output.extend(output) + self._frame.queue.put( + (self._frame.updateConnection, (self._id, output))) + if data.endswith('\n'): + self.continuing_line = -1 + else: + self.continuing_line = from_client + + def getOutput(self): + return self._output + + + def createApp(titlepart): + master = Tkinter.Tk() + app = TkTCPWatch(master) + try: + wm_title = app.master.wm_title + except AttributeError: + pass # No wm_title method available. + else: + wm_title('TCPWatch [%s]' % titlepart) + return app + + app = createApp(titlepart) + + def tkObserverFactory(fci, app=app, colorized=colorized): + return TkConnectionObserver(app, fci, colorized) + + return tkObserverFactory, app.mainloop + + + +############################################################################# +# +# The HTTP splitter +# +# Derived from Zope.Server.HTTPServer. +# +############################################################################# + + +def find_double_newline(s): + """Returns the position just after the double newline.""" + pos1 = s.find('\n\r\n') # One kind of double newline + if pos1 >= 0: + pos1 += 3 + pos2 = s.find('\n\n') # Another kind of double newline + if pos2 >= 0: + pos2 += 2 + + if pos1 >= 0: + if pos2 >= 0: + return min(pos1, pos2) + else: + return pos1 + else: + return pos2 + + + +class StreamedReceiver: + """Accepts data up to a specific limit.""" + + completed = 0 + + def __init__(self, cl, buf=None): + self.remain = cl + self.buf = buf + if cl < 1: + self.completed = 1 + + def received(self, data): + rm = self.remain + if rm < 1: + self.completed = 1 # Avoid any chance of spinning + return 0 + buf = self.buf + datalen = len(data) + if rm <= datalen: + if buf is not None: + buf.append(data[:rm]) + self.remain = 0 + self.completed = 1 + return rm + else: + if buf is not None: + buf.append(data) + self.remain -= datalen + return datalen + + + +class UnlimitedReceiver: + """Accepts data without limits.""" + + completed = 0 + + def received(self, data): + # always consume everything + return len(data) + + + +class ChunkedReceiver: + """Accepts all chunks.""" + + chunk_remainder = 0 + control_line = '' + all_chunks_received = 0 + trailer = '' + completed = 0 + + + def __init__(self, buf=None): + self.buf = buf + + def received(self, s): + # Returns the number of bytes consumed. + if self.completed: + return 0 + orig_size = len(s) + while s: + rm = self.chunk_remainder + if rm > 0: + # Receive the remainder of a chunk. + to_write = s[:rm] + if self.buf is not None: + self.buf.append(to_write) + written = len(to_write) + s = s[written:] + self.chunk_remainder -= written + elif not self.all_chunks_received: + # Receive a control line. + s = self.control_line + s + pos = s.find('\n') + if pos < 0: + # Control line not finished. + self.control_line = s + s = '' + else: + # Control line finished. + line = s[:pos] + s = s[pos + 1:] + self.control_line = '' + line = line.strip() + if line: + # Begin a new chunk. + semi = line.find(';') + if semi >= 0: + # discard extension info. + line = line[:semi] + sz = int(line.strip(), 16) # hexadecimal + if sz > 0: + # Start a new chunk. + self.chunk_remainder = sz + else: + # Finished chunks. + self.all_chunks_received = 1 + # else expect a control line. + else: + # Receive the trailer. + trailer = self.trailer + s + if trailer[:2] == '\r\n': + # No trailer. + self.completed = 1 + return orig_size - (len(trailer) - 2) + elif trailer[:1] == '\n': + # No trailer. + self.completed = 1 + return orig_size - (len(trailer) - 1) + pos = find_double_newline(trailer) + if pos < 0: + # Trailer not finished. + self.trailer = trailer + s = '' + else: + # Finished the trailer. + self.completed = 1 + self.trailer = trailer[:pos] + return orig_size - (len(trailer) - pos) + return orig_size + + + +class HTTPStreamParser: + """A structure that parses the HTTP stream. + """ + + completed = 0 # Set once request is completed. + empty = 0 # Set if no request was made. + header_plus = '' + chunked = 0 + content_length = 0 + body_rcv = None + + # headers is a mapping containing keys translated to uppercase + # with dashes turned into underscores. + + def __init__(self, is_a_request): + self.headers = {} + self.is_a_request = is_a_request + self.body_data = [] + + def received(self, data): + """Receives the HTTP stream for one request. + + Returns the number of bytes consumed. + Sets the completed flag once both the header and the + body have been received. + """ + if self.completed: + return 0 # Can't consume any more. + datalen = len(data) + br = self.body_rcv + if br is None: + # In header. + s = self.header_plus + data + index = find_double_newline(s) + if index >= 0: + # Header finished. + header_plus = s[:index] + consumed = len(data) - (len(s) - index) + self.in_header = 0 + # Remove preceeding blank lines. + header_plus = header_plus.lstrip() + if not header_plus: + self.empty = 1 + self.completed = 1 + else: + self.parse_header(header_plus) + if self.body_rcv is None or self.body_rcv.completed: + self.completed = 1 + return consumed + else: + # Header not finished yet. + self.header_plus = s + return datalen + else: + # In body. + consumed = br.received(data) + self.body_data.append(data[:consumed]) + if br.completed: + self.completed = 1 + return consumed + + + def parse_header(self, header_plus): + """Parses the header_plus block of text. + + (header_plus is the headers plus the first line of the request). + """ + index = header_plus.find('\n') + if index >= 0: + first_line = header_plus[:index] + header = header_plus[index + 1:] + else: + first_line = header_plus + header = '' + self.first_line = first_line + self.header = header + + lines = self.get_header_lines() + headers = self.headers + for line in lines: + index = line.find(':') + if index > 0: + key = line[:index] + value = line[index + 1:].strip() + key1 = key.upper().replace('-', '_') + headers[key1] = value + # else there's garbage in the headers? + + if not self.is_a_request: + # Check for a 304 response. + parts = first_line.split() + if len(parts) >= 2 and parts[1] == '304': + # Expect no body. + self.body_rcv = StreamedReceiver(0) + + if self.body_rcv is None: + # Ignore the HTTP version and just assume + # that the Transfer-Encoding header, when supplied, is valid. + te = headers.get('TRANSFER_ENCODING', '') + if te == 'chunked': + self.chunked = 1 + self.body_rcv = ChunkedReceiver() + if not self.chunked: + cl = int(headers.get('CONTENT_LENGTH', -1)) + self.content_length = cl + if cl >= 0 or self.is_a_request: + self.body_rcv = StreamedReceiver(cl) + else: + # No content length and this is a response. + # We have to assume unlimited content length. + self.body_rcv = UnlimitedReceiver() + + + def get_header_lines(self): + """Splits the header into lines, putting multi-line headers together. + """ + r = [] + lines = self.header.split('\n') + for line in lines: + if line.endswith('\r'): + line = line[:-1] + if line and line[0] in ' \t': + r[-1] = r[-1] + line[1:] + else: + r.append(line) + return r + + + +class HTTPConnectionSplitter: + """Makes a new observer for each HTTP subconnection and forwards events. + """ + + # __implements__ = IConnectionObserver + req_index = 0 + resp_index = 0 + + def __init__(self, sub_factory, fci): + self.sub_factory = sub_factory + self.transactions = [] # (observer, request_data, response_data) + self.fci = fci + self._newTransaction() + + def _newTransaction(self): + fci = self.fci.dup() + fci.transaction = len(self.transactions) + 1 + obs = self.sub_factory(fci) + req = HTTPStreamParser(1) + resp = HTTPStreamParser(0) + self.transactions.append((obs, req, resp)) + + def _mostRecentObs(self): + return self.transactions[-1][0] + + def connected(self, from_client): + self._mostRecentObs().connected(from_client) + + def closed(self, from_client): + self._mostRecentObs().closed(from_client) + + def error(self, from_client, type, value): + self._mostRecentObs().error(from_client, type, value) + + def received(self, data, from_client): + transactions = self.transactions + while data: + if from_client: + index = self.req_index + else: + index = self.resp_index + if index >= len(transactions): + self._newTransaction() + + obs, req, resp = transactions[index] + if from_client: + parser = req + else: + parser = resp + + consumed = parser.received(data) + obs.received(data[:consumed], from_client) + data = data[consumed:] + if parser.completed: + new_index = index + 1 + if from_client: + self.req_index = new_index + else: + self.resp_index = new_index + + +############################################################################# +# +# HTTP proxy +# +############################################################################# + + +class HTTPProxyToServerConnection (ForwardingEndpoint): + """Ensures that responses to a persistent HTTP connection occur + in the correct order.""" + + finished = 0 + + def __init__(self, proxy_conn, dests=()): + ForwardingEndpoint.__init__(self) + self.response_parser = HTTPStreamParser(0) + self.proxy_conn = proxy_conn + self.set_dests(dests) + + # Data for the client held until previous responses are sent + self.held = [] + + def _isMyTurn(self): + """Returns a true value if it's time for this response + to respond to the client.""" + order = self.proxy_conn._response_order + if order: + return (order[0] is self) + return 1 + + def received(self, data): + """Receives data from the HTTP server to be sent back to the client.""" + while 1: + parser = self.response_parser + if parser.completed: + self.finished = 1 + self.flush() + # Note that any extra data returned from the server is + # ignored. Should it be? :-( + return + if not data: + break + consumed = parser.received(data) + fragment = data[:consumed] + data = data[consumed:] + ForwardingEndpoint.received(self, fragment) + self.held.append(fragment) + self.flush() + + def flush(self): + """Flushes buffers and, if the response has been sent, allows + the next response to take over. + """ + if self.held and self._isMyTurn(): + data = ''.join(self.held) + del self.held[:] + self.proxy_conn.write(data) + if self.finished: + order = self.proxy_conn._response_order + if order and order[0] is self: + del order[0] + if order: + order[0].flush() # kick! + + def handle_close(self): + """The HTTP server closed the connection. + """ + ForwardingEndpoint.handle_close(self) + if not self.finished: + # Cancel the proxy connection, even if there are responses + # pending, since the HTTP spec provides no way to recover + # from an unfinished response. + self.proxy_conn.close() + + def close(self): + """Close the connection to the server. + + If there is unsent response data, an error is generated. + """ + self.flush() + if not self.finished: + t = IOError + v = 'Closed without finishing response to client' + for d in self._dests: + if hasattr(d, 'error'): + d.error(t, v) + ForwardingEndpoint.close(self) + + + +class HTTPProxyToClientConnection (ForwardingEndpoint): + """A connection from a client to the proxy server""" + + _req_parser = None + _transaction = 0 + _obs = None + + def __init__(self, conn, factory, counter, addr): + ForwardingEndpoint.__init__(self, conn) + self._obs_factory = factory + self._counter = counter + self._client_addr = addr + self._response_order = [] + self._newRequest() + + def _newRequest(self): + """Starts a new request on a persistent connection.""" + if self._req_parser is None: + self._req_parser = HTTPStreamParser(1) + factory = self._obs_factory + if factory is not None: + fci = ForwardedConnectionInfo(self._counter, self._client_addr) + self._transaction = self._transaction + 1 + fci.transaction = self._transaction + obs = factory(fci) + self._obs = obs + self.set_dests((EndpointObserver(obs, 1),)) + + def received(self, data): + """Accepts data received from the client.""" + while data: + parser = self._req_parser + if parser is None: + # Begin another request. + self._newRequest() + parser = self._req_parser + if not parser.completed: + # Waiting for a complete request. + consumed = parser.received(data) + ForwardingEndpoint.received(self, data[:consumed]) + data = data[consumed:] + if parser.completed: + # Connect to a server. + self.openProxyConnection(parser) + # Expect a new request or a closed connection. + self._req_parser = None + + def openProxyConnection(self, request): + """Parses the client connection and opens a connection to an + HTTP server. + """ + first_line = request.first_line.strip() + if not ' ' in first_line: + raise ValueError, ('Malformed request: %s' % first_line) + command, url = first_line.split(' ', 1) + pos = url.rfind(' HTTP/') + if pos >= 0: + protocol = url[pos + 1:] + url = url[:pos].rstrip() + else: + protocol = 'HTTP/1.0' + if url.startswith('http://'): + # Standard proxy + urlpart = url[7:] + if '/' in urlpart: + host, path = url[7:].split('/', 1) + path = '/' + path + else: + host = urlpart + path = '/' + else: + # Transparent proxy + host = request.headers.get('HOST') + path = url + if not host: + raise ValueError, ('Request type not supported: %s' % url) + + if ':' in host: + host, port = host.split(':') + port = int(port) + else: + port = 80 + + if '@' in host: + username, host = host.split('@') + + obs = self._obs + if obs is not None: + eo = EndpointObserver(obs, 0) + ptos = HTTPProxyToServerConnection(self, (eo,)) + else: + ptos = HTTPProxyToServerConnection(self) + + self._response_order.append(ptos) + + ptos.write('%s %s %s\r\n' % (command, path, protocol)) + # Duplicate the headers sent by the client. + if request.header: + ptos.write(request.header) + else: + ptos.write('\r\n') + if request.body_data: + ptos.write(''.join(request.body_data)) + ptos.create_socket(socket.AF_INET, socket.SOCK_STREAM) + ptos.connect((host, port)) + + def close(self): + """Closes the connection to the client. + + If there are open connections to proxy servers, the server + connections are also closed. + """ + ForwardingEndpoint.close(self) + for ptos in self._response_order: + ptos.close() + del self._response_order[:] + + +class HTTPProxyService (asyncore.dispatcher): + """A minimal HTTP proxy server""" + + connection_class = HTTPProxyToClientConnection + + _counter = 0 + + def __init__(self, listen_host, listen_port, observer_factory=None): + self._obs_factory = observer_factory + asyncore.dispatcher.__init__(self) + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.set_reuse_addr() + self.bind((listen_host, listen_port)) + self.listen(5) + + def handle_accept(self): + info = self.accept() + if info: + # Got a connection. + conn, addr = info + conn.setblocking(0) + counter = self._counter + 1 + self._counter = counter + self.connection_class(conn, self._obs_factory, counter, addr) + + def handle_error(self): + # Don't stop the server. + import traceback + traceback.print_exc() + + +############################################################################# +# +# Command-line interface +# +############################################################################# + +def usage(): + sys.stderr.write(COPYRIGHT + '\n') + sys.stderr.write( + """TCP monitoring and logging tool with support for HTTP 1.1 +Simple usage: tcpwatch.py -L listen_port:dest_hostname:dest_port + +TCP forwarded connection setup: + -L : + Set up a local forwarded connection + -L :: + Set up a forwarded connection to a specified host + -L ::: + Set up a forwarded connection to a specified host, bound to an interface + +HTTP setup: + -h (or --http) Split forwarded HTTP persistent connections + -p [:] Run an HTTP proxy + +Output options: + -s Output to stdout instead of a Tkinter window + -n No color in GUI (faster and consumes less RAM) + -c Extra color (colorizes escaped characters) + --cr Show carriage returns (ASCII 13) + --help Show usage information + +Recording options: + -r (synonyms: -R, --record-directory) + Write recorded data to . By default, creates request and + response files for each request, and writes a corresponding error file + for any error detected by tcpwatch. + --record-prefix= + Use as the file prefix for logged request / response / error + files (defaults to 'watch'). + --no-record-responses + Suppress writing '.response' files. + --no-record-errors + Suppress writing '.error' files. +""") + sys.exit() + + +def usageError(s): + sys.stderr.write(str(s) + '\n\n') + usage() + + +def main(args): + global show_cr + + try: + optlist, extra = getopt.getopt(args, 'chL:np:r:R:s', + ['help', 'http', 'cr', + 'record-directory=', + 'record-prefix=', + 'no-record-responses', + 'no-record-errors', + ]) + except getopt.GetoptError, msg: + usageError(msg) + + fwd_params = [] + proxy_params = [] + obs_factory = None + show_config = 0 + split_http = 0 + colorized = 1 + record_directory = None + record_prefix = 'watch' + record_responses = 1 + record_errors = 1 + recording = {} + + for option, value in optlist: + if option == '--help': + usage() + elif option == '--http' or option == '-h': + split_http = 1 + elif option == '-n': + colorized = 0 + elif option == '-c': + colorized = 2 + elif option == '--cr': + show_cr = 1 + elif option == '-s': + show_config = 1 + obs_factory = StdoutObserver + elif option == '-p': + # HTTP proxy + info = value.split(':') + listen_host = '' + if len(info) == 1: + listen_port = int(info[0]) + elif len(info) == 2: + listen_host = info[0] + listen_port = int(info[1]) + else: + usageError('-p requires a port or a host:port parameter') + proxy_params.append((listen_host, listen_port)) + elif option == '-L': + # TCP forwarder + info = value.split(':') + listen_host = '' + dest_host = '' + if len(info) == 2: + listen_port = int(info[0]) + dest_port = int(info[1]) + elif len(info) == 3: + listen_port = int(info[0]) + dest_host = info[1] + dest_port = int(info[2]) + elif len(info) == 4: + listen_host = info[0] + listen_port = int(info[1]) + dest_host = info[2] + dest_port = int(info[3]) + else: + usageError('-L requires 2, 3, or 4 colon-separated parameters') + fwd_params.append( + (listen_host, listen_port, dest_host, dest_port)) + elif (option == '-r' + or option == '-R' + or option == '--record-directory'): + record_directory = value + elif option == '--record-prefix': + record_prefix = value + elif option == '--no-record-responses': + record_responses = 0 + elif option == '--no-record-errors': + record_errors = 0 + + if not fwd_params and not proxy_params: + usageError("At least one -L or -p option is required.") + + # Prepare the configuration display. + config_info_lines = [] + title_lst = [] + if fwd_params: + config_info_lines.extend(map( + lambda args: 'Forwarding %s:%d -> %s:%d' % args, fwd_params)) + title_lst.extend(map( + lambda args: '%s:%d -> %s:%d' % args, fwd_params)) + if proxy_params: + config_info_lines.extend(map( + lambda args: 'HTTP proxy listening on %s:%d' % args, proxy_params)) + title_lst.extend(map( + lambda args: '%s:%d -> proxy' % args, proxy_params)) + if split_http: + config_info_lines.append('HTTP connection splitting enabled.') + if record_directory: + config_info_lines.append( + 'Recording to directory %s.' % record_directory) + config_info = '\n'.join(config_info_lines) + titlepart = ', '.join(title_lst) + mainloop = None + + if obs_factory is None: + # If no observer factory has been specified, use Tkinter. + obs_factory, mainloop = setupTk(titlepart, config_info, colorized) + + if record_directory: + def _decorateRecorder(fci, sub_factory=obs_factory, + record_directory=record_directory, + record_prefix=record_prefix, + record_responses=record_responses, + record_errors=record_errors): + return RecordingObserver(fci, sub_factory, record_directory, + record_prefix, record_responses, + record_errors) + obs_factory = _decorateRecorder + + chosen_factory = obs_factory + if split_http: + # Put an HTTPConnectionSplitter between the events and the output. + def _factory(fci, sub_factory=obs_factory): + return HTTPConnectionSplitter(sub_factory, fci) + chosen_factory = _factory + # obs_factory is the connection observer factory without HTTP + # connection splitting, while chosen_factory may have connection + # splitting. Proxy services use obs_factory rather than the full + # chosen_factory because proxy services perform connection + # splitting internally. + + services = [] + try: + # Start forwarding services. + for params in fwd_params: + args = params + (chosen_factory,) + s = ForwardingService(*args) + services.append(s) + + # Start proxy services. + for params in proxy_params: + args = params + (obs_factory,) + s = HTTPProxyService(*args) + services.append(s) + + if show_config: + sys.stderr.write(config_info + '\n') + + # Run the main loop. + try: + if mainloop is not None: + import thread + thread.start_new_thread(asyncore.loop, (), {'timeout': 1.0}) + mainloop() + else: + asyncore.loop(timeout=1.0) + except KeyboardInterrupt: + sys.stderr.write('TCPWatch finished.\n') + finally: + for s in services: + s.close() + + +if __name__ == '__main__': + main(sys.argv[1:]) From reebalazs at codespeak.net Sat Apr 22 11:48:10 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Sat Apr 22 11:48:11 2006 Subject: [z3-checkins] r26127 - z3/jsonserver/branch/merge/utils Message-ID: <20060422094810.DC5771009F@code0.codespeak.net> Author: reebalazs Date: Sat Apr 22 11:48:09 2006 New Revision: 26127 Modified: z3/jsonserver/branch/merge/utils/tcpwatch Log: Add json support to tcpwatch Modified: z3/jsonserver/branch/merge/utils/tcpwatch ============================================================================== --- z3/jsonserver/branch/merge/utils/tcpwatch (original) +++ z3/jsonserver/branch/merge/utils/tcpwatch Sat Apr 22 11:48:09 2006 @@ -89,6 +89,134 @@ RECV_BUFFER_SIZE = 8192 show_cr = 0 +# Support for jsonic read +# To use the json_read, minjson, zope.component and zope.interface +# must be installable from the python level. If this does not happen, +# we provide a simple conversion that however will not always work. +try: + from minjson import read as json_read + # best to try these imports too, right away + import zope.component + import zope.interface +except ImportError: + print "Could not import minjson, applying fallback function." + def json_read(txt): + class Null: + def __repr__(self): + return 'null' + class True: + def __repr__(self): + return 'true' + class False: + def __repr__(self): + return 'false' + return eval(txt, {'null': Null(), 'true': True(), 'false': False()}, {}) + +def json_prettify(line): + # Try to prettify JSON output + # return None if unsuccesful + try: + ob = json_read(line) + except: + pass + else: + stream = StringIO() + writer = Writer(stream) + prettify(writer, ob) + return stream.getvalue() + +# -- +# Prettifyer +# -- + +import re +from textwrap import dedent +from cStringIO import StringIO + +class Writer: + + def __init__(self, stream, baseindent=4): + self.stream = stream + self.indent = 0 + self.baseindent = baseindent + self.isnewline = True + self.nrnewlines = 0 + + re_multi = re.compile(r'(\n)') + + def write(self, txt, keepindents=False): + if self.isnewline: + self.stream.write('\n' * self.nrnewlines) + self.stream.write(' ' * self.indent) + self.isnewline = False + self.nrnewlines = 0 + else: + # if a continuation line, then we always keep indents. + keepindents = True + if not keepindents: + # (new lines are getting dedented, continuations not.) + txt = dedent(txt) + # see if there are more lines + lines = self.re_multi.split(txt) + if len(lines) > 1: + # more lines + for line in lines: + if line == '\n': + self.newline() + else: + self.write(line, keepindents=True) + else: + # single line + self.stream.write(txt) + + def newline(self): + self.isnewline = True + self.nrnewlines += 1 + + def indenton(self, levels=1): + self.indent += self.baseindent * levels + + def indentoff(self, levels=1): + self.indent -= self.baseindent * levels + + def add_remark(self, text, remark, pos=65): + if remark is not None: + # remark will be indented to position, or later if text is longer. + return text.ljust(pos - 2 - self.indent) + ' # ' + remark + else: + return text + +def prettify(writer, value): + if isinstance(value, (list, tuple)): + writer.indenton() + if isinstance(value, list): + writer.write('[') + else: + writer.write('(') + writer.newline() + for elem in value: + prettify(writer, elem) + writer.write(',') + writer.newline() + if isinstance(value, list): + writer.write(']') + else: + writer.write(')') + writer.indentoff() + elif isinstance(value, dict): + writer.indenton() + writer.write('{') + writer.newline() + for k, v in value.iteritems(): + prettify(writer, k) + writer.write(': ') + prettify(writer, v) + writer.write(',') + writer.newline() + writer.write('}') + writer.indentoff() + else: + writer.write(repr(value)) ############################################################################# # @@ -347,6 +475,18 @@ data = data.replace('\r', '') lines = data.split('\n') lines = map(escape, lines) + # Try to prettify JSON output + if lines: + result = json_prettify(lines[-1]) + if result: + if getattr(self, '_colorized', True): + if from_client: + result = '\x1b[0;32m' + result + '\x1b[0m' + else: + result = '\x1b[0;31m' + result + '\x1b[0m' + del lines[-1] + lines.extend(result.splitlines()) + s = ('\n%s' % arrow).join(lines) self.write(s) @@ -520,6 +660,8 @@ self.textbox.tag_config("server", foreground="#770000") self.textbox.tag_config( "serveresc", foreground="#770000", background="#dddddd") + self.textbox.tag_config("clientjson", foreground="#00dd00") + self.textbox.tag_config("serverjson", foreground="#dd0000") self.textbox.insert(Tkinter.END, startup_text, "message") self.textbox.pack(side='right', fill=Tkinter.BOTH, expand=1) self.pack(fill=Tkinter.BOTH, expand=1) @@ -627,6 +769,17 @@ else: segments.append(ss) + + # Try to prettify JSON output + jsondata = None + if data: + lines = data.splitlines() + result = json_prettify(lines[-1]) + if result: + data = '\n'.join(lines[:-1]) + '\n' + jsondata = result + '\n' + print data + # Escape the input data. was_escaped = 0 start_idx = 0 @@ -646,6 +799,10 @@ if not extra_color: output.append((''.join(segments), from_client and 'client' or 'server')) + + # Append the json data + if jsondata: + output.append((jsondata, from_client and 'clientjson' or 'serverjson')) # Send output to the frame. self._output.extend(output) From reebalazs at codespeak.net Sat Apr 22 11:52:47 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Sat Apr 22 11:52:47 2006 Subject: [z3-checkins] r26129 - z3/jsonserver/branch/zope2_test Message-ID: <20060422095247.0EF41100AC@code0.codespeak.net> Author: reebalazs Date: Sat Apr 22 11:52:45 2006 New Revision: 26129 Removed: z3/jsonserver/branch/zope2_test/pyclient.py Modified: z3/jsonserver/branch/zope2_test/ (props changed) z3/jsonserver/branch/zope2_test/EXTERNALS.TXT Log: external link to utils in the merge branch Modified: z3/jsonserver/branch/zope2_test/EXTERNALS.TXT ============================================================================== --- z3/jsonserver/branch/zope2_test/EXTERNALS.TXT (original) +++ z3/jsonserver/branch/zope2_test/EXTERNALS.TXT Sat Apr 22 11:52:45 2006 @@ -7,3 +7,5 @@ # browser http://codespeak.net/svn/z3/jsonserver/branch/merge/browser concatresource http://codespeak.net/svn/z3/jsonserver/branch/merge/concatresource +utils http://codespeak.net/svn/z3/jsonserver/branch/merge/utils + Deleted: /z3/jsonserver/branch/zope2_test/pyclient.py ============================================================================== --- /z3/jsonserver/branch/zope2_test/pyclient.py Sat Apr 22 11:52:45 2006 +++ (empty file) @@ -1,84 +0,0 @@ -'''\ -A python client for jsonserver. - -This is a separate file that is not needed for jsonserver to work. - -It can be used to - -- test json components from the command line -- create a standalone python json-rpc client. - -This file needs to import minjson.py, it uses nothing else -from the server. -''' - -import urllib2 -from minjson import read, write - -request_content_type = 'application/json-rpc' -pythonkwmarker = 'pythonKwMaRkEr' - -class JsonRpcError(Exception): - pass - -class JsonserverClient(object): - '''A Jsonserver client. - - On creation it is bound to an url and you - can call up methods on it. - - Example:: - - c = JsonserverClient('http://localhost:9777/xx1/edit_title_content') - result = c.title_widget(widget_mode=1) - - ''' - - class Opener(object): - - def __init__(self, baseurl, method): - self.baseurl = baseurl - self.method = method - - def __call__(self, *args, **kw): - # build the data - if kw: - args += ({pythonkwmarker: kw}, ) - data = { - 'id': 'httpReq', - 'method': self.method, - 'params': args, - } - raw_data = write(data, 'utf-8', 'utf-8') - # - headers={'Content-Type': request_content_type} - r = urllib2.Request(self.baseurl, raw_data, headers=headers) - f = urllib2.urlopen(r) - # - raw_response = f.read() - response = read(raw_response, 'utf-8') - if response['error']: - raise JsonRpcError, 'Error: %s' % (response['error'], ) - result = response['result'] - return result - - def __init__(self, baseurl): - '''Create a Jsonserver client class - - Then you can call methods on this class - ''' - self._baseurl = baseurl - - def __getattr__(self, name): - # If a new method is called up, a descriptor is created for it - # and it is stored in the class. - if not name or name[0] == '_': - raise JsonRpcError('Method names cannot start with "_". (%s)' % (name, )) - method = self.Opener(self._baseurl, name) - setattr(self, name, method) - return method - -if __name__ == '__main__': - c = JsonserverClient('http://localhost:9676/xx1/edit_title_content') - result = c.title_widget(widget_mode=1) - print result From reebalazs at codespeak.net Sat Apr 22 11:54:26 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Sat Apr 22 11:54:26 2006 Subject: [z3-checkins] r26130 - z3/jsonserver/branch/merge/utils Message-ID: <20060422095426.24FEA100B5@code0.codespeak.net> Author: reebalazs Date: Sat Apr 22 11:54:25 2006 New Revision: 26130 Modified: z3/jsonserver/branch/merge/utils/pyclient (props changed) Log: Setting up utils From reebalazs at codespeak.net Sat Apr 22 12:31:48 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Sat Apr 22 12:31:50 2006 Subject: [z3-checkins] r26131 - z3/jsonserver/branch/merge/utils Message-ID: <20060422103148.EDD8F100B7@code0.codespeak.net> Author: reebalazs Date: Sat Apr 22 12:31:48 2006 New Revision: 26131 Modified: z3/jsonserver/branch/merge/utils/tcpwatch Log: Fix tcpwatch Modified: z3/jsonserver/branch/merge/utils/tcpwatch ============================================================================== --- z3/jsonserver/branch/merge/utils/tcpwatch (original) +++ z3/jsonserver/branch/merge/utils/tcpwatch Sat Apr 22 12:31:48 2006 @@ -93,6 +93,9 @@ # To use the json_read, minjson, zope.component and zope.interface # must be installable from the python level. If this does not happen, # we provide a simple conversion that however will not always work. +# +# XXX other problem: +# longer streams can be split. That destroys conversion. try: from minjson import read as json_read # best to try these imports too, right away @@ -215,6 +218,8 @@ writer.newline() writer.write('}') writer.indentoff() + elif isinstance(value, unicode): + writer.write('"%s"' % (value.encode('utf8', )) else: writer.write(repr(value)) @@ -477,14 +482,18 @@ lines = map(escape, lines) # Try to prettify JSON output if lines: - result = json_prettify(lines[-1]) + # find where to start from + for i, line in enumerate(lines): + if not line: + break + result = json_prettify('\n'.join(lines[i+1:])) if result: if getattr(self, '_colorized', True): if from_client: result = '\x1b[0;32m' + result + '\x1b[0m' else: result = '\x1b[0;31m' + result + '\x1b[0m' - del lines[-1] + del lines[i+1:] lines.extend(result.splitlines()) s = ('\n%s' % arrow).join(lines) From reebalazs at codespeak.net Sat Apr 22 12:52:05 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Sat Apr 22 12:52:06 2006 Subject: [z3-checkins] r26133 - z3/jsonserver/branch/merge/utils Message-ID: <20060422105205.246D9100C2@code0.codespeak.net> Author: reebalazs Date: Sat Apr 22 12:52:03 2006 New Revision: 26133 Modified: z3/jsonserver/branch/merge/utils/tcpwatch Log: fix Modified: z3/jsonserver/branch/merge/utils/tcpwatch ============================================================================== --- z3/jsonserver/branch/merge/utils/tcpwatch (original) +++ z3/jsonserver/branch/merge/utils/tcpwatch Sat Apr 22 12:52:03 2006 @@ -219,7 +219,7 @@ writer.write('}') writer.indentoff() elif isinstance(value, unicode): - writer.write('"%s"' % (value.encode('utf8', )) + writer.write('"%s"' % (value.encode('utf8', ))) else: writer.write(repr(value)) From reebalazs at codespeak.net Sat Apr 22 13:41:40 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Sat Apr 22 13:41:42 2006 Subject: [z3-checkins] r26140 - z3/jsonserver/branch/merge/utils Message-ID: <20060422114140.92D3110087@code0.codespeak.net> Author: reebalazs Date: Sat Apr 22 13:41:39 2006 New Revision: 26140 Modified: z3/jsonserver/branch/merge/utils/tcpwatch Log: fix Modified: z3/jsonserver/branch/merge/utils/tcpwatch ============================================================================== --- z3/jsonserver/branch/merge/utils/tcpwatch (original) +++ z3/jsonserver/branch/merge/utils/tcpwatch Sat Apr 22 13:41:39 2006 @@ -218,8 +218,6 @@ writer.newline() writer.write('}') writer.indentoff() - elif isinstance(value, unicode): - writer.write('"%s"' % (value.encode('utf8', ))) else: writer.write(repr(value)) @@ -486,6 +484,9 @@ for i, line in enumerate(lines): if not line: break + else: + # no line found - take the whole buffer + i = -1 result = json_prettify('\n'.join(lines[i+1:])) if result: if getattr(self, '_colorized', True): From rocky at codespeak.net Sat Apr 22 16:56:56 2006 From: rocky at codespeak.net (rocky@codespeak.net) Date: Sat Apr 22 16:56:58 2006 Subject: [z3-checkins] r26143 - z3/pythonproducts/trunk Message-ID: <20060422145656.02B3E10076@code0.codespeak.net> Author: rocky Date: Sat Apr 22 16:37:03 2006 New Revision: 26143 Modified: z3/pythonproducts/trunk/ (props changed) z3/pythonproducts/trunk/README.txt z3/pythonproducts/trunk/setup.py Log: Preparing for 1.0beta1 release. Modified: z3/pythonproducts/trunk/README.txt ============================================================================== --- z3/pythonproducts/trunk/README.txt (original) +++ z3/pythonproducts/trunk/README.txt Sat Apr 22 16:37:03 2006 @@ -17,7 +17,7 @@ Requirements - Python 2.3.5 or higher in 2.3.x series - - Zope 2.8.4 or higher in 2.8.x series + - Zope 2.8 or 2.9 - Five 1.2 or higher Installing @@ -55,4 +55,3 @@ Step 3: The standard way of registering a package with Zope 3 is to create a ZCML "slug" in the $INSTANCE_HOME/etc/package-includes directory. This file can be called anything as long as it ends with "-configure.zcml". - \ No newline at end of file Modified: z3/pythonproducts/trunk/setup.py ============================================================================== --- z3/pythonproducts/trunk/setup.py (original) +++ z3/pythonproducts/trunk/setup.py Sat Apr 22 16:37:03 2006 @@ -96,7 +96,7 @@ setup(cmdclass={'install': Installer}, name='pythonproducts', - version='1.0alpha1', + version='1.0beta1', description='A mechanism to construct Zope 2 products as regular ' 'python packages', author='Rocky Burt', From jinty at codespeak.net Mon Apr 24 01:31:40 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Mon Apr 24 01:31:44 2006 Subject: [z3-checkins] r26204 - z3/sqlos/trunk/src/sqlos Message-ID: <20060423233140.67FB810081@code0.codespeak.net> Author: jinty Date: Mon Apr 24 01:31:35 2006 New Revision: 26204 Added: z3/sqlos/trunk/src/sqlos/zsqlobject.py - copied unchanged from r26203, z3/sqlos/trunk/src/sqlos/_sqlos.py Removed: z3/sqlos/trunk/src/sqlos/_sqlos.py Log: Forgotten in the last commit Deleted: /z3/sqlos/trunk/src/sqlos/_sqlos.py ============================================================================== --- /z3/sqlos/trunk/src/sqlos/_sqlos.py Mon Apr 24 01:31:35 2006 +++ (empty file) @@ -1,85 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004 Enfold Systems LLC. All rights reserved. -# -# This software is distributed under the terms of the Zope Public -# License (ZPL) v2.1. See COPYING.txt for more information. -# -############################################################################## -""" -$Id: __init__.py 5216 2004-06-21 18:33:07Z dreamcatcher $ -""" - -from zope.interface import implements -from sqlobject.main import SQLObject -from sqlobject import StringCol - -from sqlos.connection import ConnectionDescriptor -from sqlos.interfaces import ISQLObject - -class SQLOS(SQLObject): - """Subclass SQLObject to enable ``lazy updates`` by default, - as well as adding knowledge to register ``dirty`` objects - with SQLObjectTransactionManager so they get sync'd on transaction - boundaries. - - First, make a test data base: - - >>> from sqlos import testing - >>> testdb = testing.TestDB([SQLOS]) - - Test the interface: - - >>> s = SQLOS() - >>> from zope.interface.verify import verifyObject - >>> verifyObject(ISQLObject, s) - True - - And finally call tearDown and cleanup: - - >>> testdb.tearDown() - """ - implements(ISQLObject) - _connection = ConnectionDescriptor() - - class sqlmeta: - lazyUpdate = True - - def _set_dirty(self, value): - if value: - self._connection._dm.register(self) - # This breaks the transaction functional tests and seems to be an - # optimization only. So I've commented it out. - jinty 2005-10-5 - #else: - # # XXX: 'objects' shouldn't really be fiddled directly like this. - # # Probably there should be an unregister function. - # # - Andrew Bennetts, 2005-01-05 - # self._connection._dm.objects.discard(self) - self._dirty = value - - def _get_dirty(self): - return self._dirty - - dirty = property(_get_dirty, _set_dirty) - - def get(self, id, connection=None, selectResults=None): - # While interacting with zope, we may end up having - # objects in the cache that have a __parent__ set. - # This may be confusing when expect to get a object - # which has no __parent__ and thats not what you get. - val = super(SQLOS, self).get(id, connection=connection, - selectResults=selectResults) - if getattr(val, '__parent__', None) is not None: - val.__parent__ = None - val.__name__ = None - return val - get = classmethod(get) - - def __repr__(self): - return '<%s at 0x%x>' % (self.__class__.__name__, id(self)) - - def setConnection(self, connection): - if connection is not None: - self._connection = connection - - setConnection = classmethod(setConnection) From jinty at codespeak.net Mon Apr 24 03:18:57 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Mon Apr 24 03:19:00 2006 Subject: [z3-checkins] r26206 - in z3/sqlos/trunk/src/sqlos: . ftests Message-ID: <20060424011857.D051D10084@code0.codespeak.net> Author: jinty Date: Mon Apr 24 03:18:48 2006 New Revision: 26206 Modified: z3/sqlos/trunk/src/sqlos/_transaction.py z3/sqlos/trunk/src/sqlos/adapter.py z3/sqlos/trunk/src/sqlos/ftests/test_transaction.py z3/sqlos/trunk/src/sqlos/zsqlobject.py Log: Implement a dirty object registry that keeps track of dirty SQLOS objects and registers a beforeCommitHook. This allows us to expose a syncUpdateAll function which can be used to send all outstanding SQL to the database in mid-transaction. Modified: z3/sqlos/trunk/src/sqlos/_transaction.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/_transaction.py (original) +++ z3/sqlos/trunk/src/sqlos/_transaction.py Mon Apr 24 03:18:48 2006 @@ -15,48 +15,25 @@ * Creates a thread local cache of SQLObjects so that cached objects do not leak into other threads as they would in pure SQLObject. * Clears the thread local cache at the start of each new transaction. - * When an object is modified, it registers itself with the data manager - which, in turn, registers a pre-commit hook. This hook sync's the object - sending all the SQL down the line before the two phase commit starts. - -XXX - There was a reason why we couldn't do this without a data manager, but I - cannot remember it now. -jinty + * When an object is modified, it registers itself with the dirty object + registry which, in turn, registers a pre-commit hook. This hook + syncUpdates's the object sending all the SQL down the line before the + commit starts. $Id$ """ __metaclass__ = type -import sets - import transaction -from transaction import get -from transaction.interfaces import IDataManager, ISynchronizer +from transaction.interfaces import ISynchronizer from zope.interface import implements -from zope.app.event.objectevent import modified -from sqlobject import SQLObjectNotFound from sqlobject.cache import CacheSet -from zope.security.proxy import removeSecurityProxy from zope.thread import local from sqlos.interfaces import ISQLObject -def beforeCommitHook(obj): - """Called before transactions are started. - - obj is a SQLObject - - This normally generates the database activity that pulls the zope.app.rdb - data manager into the transaction, thus must be called before the - transaction commits. - - Note that it is only called on commit. - """ - if not obj.sqlmeta._obsolete: - obj.sync() - - class CacheSynchronizer: """Synchronizer to expire the Global per thread cache at transaction start. @@ -126,144 +103,190 @@ # there must be a dead simple way. -class SQLObjectTransactionManager: - """ - This is a very simple Data Manager that just takes registrations - of ``ISQLObject`` objects and calls their ``sync()`` method when - needed. - - In addition to that, when the transaction is aborted, all modified - objects will be expired. +class DirtyObjectRegistry(local): + """A thread local registry of dirty SQLObjects. - Let's see how it works. + StubPeople: - First of all, setup the environment: - - >>> from zope.app.testing.placelesssetup import setUp, tearDown - >>> setUp() - - First, register the subscribers and make a test data base: - - >>> from sqlos import testing - >>> from sqlos.testing.sampleperson import SamplePerson - >>> testdb = testing.TestDB([SamplePerson]) + >>> synced = [] + >>> class StubPerson: + ... implements(ISQLObject) + ... class sqlmeta: + ... _obsolete = False + ... def __init__(self, name): + ... self.name = name + ... def syncUpdate(self): + ... synced.append(self.name) + ... synced.sort() + + Lets get some sample people: + + >>> jhon = StubPerson('jhon') + >>> jane = StubPerson('jane') + + Stub out some methods and make a registry: + + >>> oldhook = DirtyObjectRegistry._addBeforeCommitHook + >>> def hook(self): + ... print 'adding before commit hook' + ... assert transaction.get() is self._txn + ... oldhook(self) + >>> DirtyObjectRegistry._addBeforeCommitHook = hook + >>> reg = DirtyObjectRegistry() + + Objects not implementing ISQLObject fail to register: + + >>> reg.register(object()) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + ValueError: ... + + Register some people and check the internal state: + + >>> reg.register(jhon) + adding before commit hook + >>> len(reg._objects) + 1 + >>> reg._txn is transaction.get() + True - Now create some SamplePeople for testing: + >>> reg.register(jhon) + >>> len(reg._objects) + 1 + + >>> reg.register(jane) + >>> len(reg._objects) + 2 + + Test the thread localness of the registry: + + >>> log = [] + >>> import threading + >>> def logRegisterState(): + ... log.append(reg._txn) + ... log.append(reg._objects) + ... log.append(reg._registered) + >>> thread = threading.Thread(target=logRegisterState) + >>> thread.start() + >>> thread.join() + >>> log + [None, set([]), False] - >>> person = SamplePerson(fullname='Sidnei', username='sidnei', - ... password='123') - >>> person1 = SamplePerson(fullname='Brian', username='jinty', - ... password='456') - And commit everything: + After a commit we should be able to do it again: - >>> get().commit() + >>> transaction.get().commit() + >>> synced + ['jane', 'jhon'] - Monkeypatch some methods to ease testing: + Register some people and check the internal state: >>> synced = [] - - >>> oldsync = SamplePerson.sync - >>> def sync(self): - ... synced.append(self.username) - ... synced.sort() - ... oldsync(self) - >>> SamplePerson.sync = sync - - Now, we check the initial DataManager state: - - >>> person.dirty - False - >>> dm = SamplePerson._connection._dm - >>> dm._objects == sets.Set([]) + >>> reg.register(jhon) + adding before commit hook + >>> len(reg._objects) + 1 + >>> reg._txn is transaction.get() True - Change something on the people and make sure that they register: + >>> reg.register(jhon) + >>> len(reg._objects) + 1 - >>> person.set(fullname='Sidnei da Silva') - >>> person.dirty - True - >>> dm._objects == sets.Set([person]) - True - - >>> person1.set(fullname='Brian Sutherland') - >>> person1.dirty - True - >>> dm._objects == sets.Set([person, person1]) - True + >>> reg.register(jane) + >>> len(reg._objects) + 2 - Commit the transaction: + Test that after an abort everything works as expected: + >>> transaction.get().abort() >>> synced [] - >>> get().commit() - >>> synced - ['jinty', 'sidnei'] - - >>> synced[:] = [] - Check the state: + Register some people and check the internal state: - >>> person.dirty - False - >>> dm._objects == sets.Set([]) + >>> reg.register(jhon) + adding before commit hook + >>> len(reg._objects) + 1 + >>> reg._txn is transaction.get() True - Now, we change something again to test abort(): + >>> reg.register(jhon) + >>> len(reg._objects) + 1 - >>> person.set(fullname='Alan Runyan') - >>> person.dirty - True - >>> dm._objects == sets.Set([person]) - True + >>> reg.register(jane) + >>> len(reg._objects) + 2 - Lets abort the current transaction: + We can manually sync all the objects: + >>> reg.syncUpdateAll() >>> synced - [] - >>> get().abort() + ['jane', 'jhon'] + >>> len(reg._objects) + 0 + + We will not re-register after a manual sync, but new objects can be + registered. A committed transaction will sync them: + + >>> synced = [] + >>> reg.register(jhon) + >>> len(reg._objects) + 1 + >>> transaction.get().commit() >>> synced - [] + ['jhon'] - And then cleanup the monkeypatched method: + After an abort, nothing can be synced: - >>> SamplePerson.sync = oldsync + >>> synced = [] + >>> reg.register(jhon) + adding before commit hook + >>> len(reg._objects) + 1 + >>> transaction.get().abort() + >>> reg.syncUpdateAll() + >>> synced + [] - And finally call tearDown and cleanup: + TearDown: - >>> testdb.tearDown() - >>> tearDown() + >>> DirtyObjectRegistry._addBeforeCommitHook = oldhook """ - implements(IDataManager) - def __init__(self): - self._objects = sets.Set() - self._joined_txn = False - - def prepare(self, txn): - return True + self._txn = None + self._objects = set([]) + self._registered = False + + def syncUpdateAll(self): + self._ensureCurrentTxn() + while self._objects: + obj = self._objects.pop() + if not obj.sqlmeta._obsolete: + obj.syncUpdate() - def abort(self, txn): - self._objects.clear() - self._joined_txn = False - - def commit(self, txn): - self._objects.clear() - self._joined_txn = False + def _addBeforeCommitHook(self): + self._txn.addBeforeCommitHook(self.syncUpdateAll, ()) def register(self, obj): if not ISQLObject.providedBy(obj): raise ValueError, ("Only objects that implement ISQLObject " - "can be registered with this transaction " - "manager") - if obj not in self._objects: - self._objects.add(obj) - txn = get() - txn.addBeforeCommitHook(beforeCommitHook, (obj, )) - if not self._joined_txn: - txn.join(self) - self._joined_txn = True + "can be registered with this registry.") + self._ensureCurrentTxn() + if not self._registered: + self._addBeforeCommitHook() + self._registered = True + self._objects.add(obj) + + def _ensureCurrentTxn(self): + txn = transaction.get() + if self._txn is not txn: + # clean up after the last transaction + self._objects.clear() + self._txn = txn + self._registered = False - def sortKey(self): - return str(id(self)) +dirty_object_registry = DirtyObjectRegistry() Modified: z3/sqlos/trunk/src/sqlos/adapter.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/adapter.py (original) +++ z3/sqlos/trunk/src/sqlos/adapter.py Mon Apr 24 03:18:48 2006 @@ -26,7 +26,6 @@ from zope.interface import implements from sqlos.interfaces import ISQLObject -from sqlos._transaction import SQLObjectTransactionManager from sqlos._transaction import cache_manager # TODO: it is probably possible to optimize this by not creating a @@ -43,7 +42,6 @@ self.autoCommit = None self.debug = 0 self.supportTransactions = False - self._dm = SQLObjectTransactionManager() def _get_cache(self): return cache_manager.cache Modified: z3/sqlos/trunk/src/sqlos/ftests/test_transaction.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/ftests/test_transaction.py (original) +++ z3/sqlos/trunk/src/sqlos/ftests/test_transaction.py Mon Apr 24 03:18:48 2006 @@ -78,7 +78,8 @@ person.fullname = 'Sidnei Silva' person.username = 'dreamcatcher' person.password = 'pass' - person.sync() # Sunc to make sure that the DB is sent the statements + assert person.dirty is True + person.sync() # Sync to ensure that the DB is sent the SQL statements get().abort() begin() person = SamplePerson.get(self.personid) @@ -86,12 +87,62 @@ self.assertEqual(person.fullname, 'Sidnei da Silva') self.assertEqual(person.username, 'sidnei') self.assertEqual(person.password, 'test') + # commit the next transaction so we can paranoically check + get().commit() + begin() + person = SamplePerson.get(self.personid) + self.assertEqual(person.fullname, 'Sidnei da Silva') else: # ya well no fine + import warnings + warnings.warn('SQLObject connections for this database do not ' + 'support transactions. Not testing if transaction ' + 'abort works.') self.assertEqual(person.fullname, 'Sidnei Silva') self.assertEqual(person.username, 'dreamcatcher') self.assertEqual(person.password, 'pass') + def testAbortAndCommitDirty(self): + """Test the commit after an abort in the presence of dirty SQLObjects. + + Here we commit the next transaction with another dirty object + just to make sure that remnants from the previous transaction are + not committed. + Yeah, this is paranoid, but sometimes it pays to be paranoid. + """ + if self.supportTransactions(): + # make a dirty object + person = SamplePerson.get(self.personid) + self.assertEqual(person.fullname, 'Sidnei da Silva') + person.fullname = 'Sidnei Silva' + assert person.dirty is True + person.sync() # Sync to ensure that the DB is sent the SQL + # abort transaction and start a new one + get().abort() + begin() + # make another dirty object + person = SamplePerson.get(self.personid) + self.assertEqual(person.fullname, 'Sidnei da Silva') + brian = SamplePerson(fullname='Brian Sutherland', + username='brian', + password='test') + brian.fullname = "B. Sutherland" # make the object dirty + assert brian.dirty is True + brianid = brian.id + # commit the second transaction + get().commit() + begin() + person = SamplePerson.get(self.personid) + brian = SamplePerson.get(brianid) + self.assertEqual(person.fullname, 'Sidnei da Silva') + self.assertEqual(brian.fullname, 'B. Sutherland') + else: + # ya well no fine + import warnings + warnings.warn('SQLObject connections for this database do not ' + 'support transactions. Not testing if transaction ' + 'abort works.') + def testCacheThreadIsolation(self): """Tests that the changes we make in one thread don't appear in another. Modified: z3/sqlos/trunk/src/sqlos/zsqlobject.py ============================================================================== --- z3/sqlos/trunk/src/sqlos/zsqlobject.py (original) +++ z3/sqlos/trunk/src/sqlos/zsqlobject.py Mon Apr 24 03:18:48 2006 @@ -16,6 +16,15 @@ from sqlos.connection import ConnectionDescriptor from sqlos.interfaces import ISQLObject +from sqlos import _transaction + +def syncUpdateAll(): + """Calls syncUpdate on all dirty SQLOS objects, sending all SQL to the DB. + + >>> syncUpdateAll() + """ + _transaction.dirty_object_registry.syncUpdateAll() + class SQLOS(SQLObject): """Subclass SQLObject to enable ``lazy updates`` by default, @@ -47,14 +56,7 @@ def _set_dirty(self, value): if value: - self._connection._dm.register(self) - # This breaks the transaction functional tests and seems to be an - # optimization only. So I've commented it out. - jinty 2005-10-5 - #else: - # # XXX: 'objects' shouldn't really be fiddled directly like this. - # # Probably there should be an unregister function. - # # - Andrew Bennetts, 2005-01-05 - # self._connection._dm.objects.discard(self) + _transaction.dirty_object_registry.register(self) self._dirty = value def _get_dirty(self): From jwashin at codespeak.net Thu Apr 27 15:06:51 2006 From: jwashin at codespeak.net (jwashin@codespeak.net) Date: Thu Apr 27 15:06:51 2006 Subject: [z3-checkins] r26445 - in z3/jsonserver/trunk: . tests Message-ID: <20060427130651.56863100B7@code0.codespeak.net> Author: jwashin Date: Thu Apr 27 15:06:47 2006 New Revision: 26445 Modified: z3/jsonserver/trunk/jsonrpc.py z3/jsonserver/trunk/metaconfigure.py z3/jsonserver/trunk/tests/test_directives.py z3/jsonserver/trunk/tests/test_httpfactory.py Log: update for z3 trunk changes Modified: z3/jsonserver/trunk/jsonrpc.py ============================================================================== --- z3/jsonserver/trunk/jsonrpc.py (original) +++ z3/jsonserver/trunk/jsonrpc.py Thu Apr 27 15:06:47 2006 @@ -20,6 +20,7 @@ #2005-09-08 updated to work with the new IResult idea (wsgi) #2005-10-09 unicode handling update #2006-03-09 enabled gzip compression for large responses +#2006-04-27 updated to sync with z3 trunk changes jmw __docformat__ = 'restructuredtext' @@ -28,7 +29,11 @@ IJSONRPCRequest, IJSONReader, IJSONWriter from zope.interface import implements #from zope.publisher.http import IResult -from zope.app.location.location import Location +try: + from zope.location.location import Location +except ImportError: + #deprecate this for 3.5 + from zope.app.location.location import Location from zope.publisher.http import HTTPRequest, HTTPResponse, \ getCharsetUsingRequest, DirectResult from zope.publisher.browser import BrowserRequest Modified: z3/jsonserver/trunk/metaconfigure.py ============================================================================== --- z3/jsonserver/trunk/metaconfigure.py (original) +++ z3/jsonserver/trunk/metaconfigure.py Thu Apr 27 15:06:47 2006 @@ -1,7 +1,7 @@ ############################################################################ ## # -# Copyright (c) 2001 - 2005 Zope Corporation and Contributors. +# Copyright (c) 2001 - 2005 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, @@ -17,6 +17,7 @@ like zope.app.publisher.xmlrpc.metaconfigure +Updated 2006-04-27 to sync with zope3 trunk jmw updated 2005-12-03 Roger Ineichen jwashin 2005-06-06 """ @@ -26,8 +27,8 @@ from zope.configuration.exceptions import ConfigurationError from interfaces import IJSONRPCRequest -from zope.app.component.interface import provideInterface -from zope.app.component.metaconfigure import handler +from zope.component.interface import provideInterface +from zope.component.zcml import handler from jsonrpc import MethodPublisher def view(_context, for_=None, interface=None, methods=None, @@ -57,8 +58,7 @@ # Make sure that the class inherits MethodPublisher, so that the views # have a location if class_ is None: - class_ = MethodPublisher - original_class = class_ + class_ = original_class = MethodPublisher else: original_class = class_ class_ = type(class_.__name__, (class_, MethodPublisher), {}) @@ -83,8 +83,8 @@ _context.action( discriminator = ('view', for_, name, IJSONRPCRequest), callable = handler, - args = ('provideAdapter', - (for_, IJSONRPCRequest), Interface, name, class_, + args = ('registerAdapter', + class_, (for_, IJSONRPCRequest), Interface, name, _context.info) ) else: @@ -101,8 +101,8 @@ _context.action( discriminator = ('view', for_, name, IJSONRPCRequest), callable = handler, - args = ('provideAdapter', - (for_, IJSONRPCRequest), Interface, name, new_class, + args = ('registerAdapter', + new_class, (for_, IJSONRPCRequest), Interface, name, _context.info) ) Modified: z3/jsonserver/trunk/tests/test_directives.py ============================================================================== --- z3/jsonserver/trunk/tests/test_directives.py (original) +++ z3/jsonserver/trunk/tests/test_directives.py Thu Apr 27 15:06:47 2006 @@ -1,6 +1,6 @@ ############################################################################## # -# Copyright (c) 2001 - 2005 Zope Corporation and Contributors. +# Copyright (c) 2001 - 2005 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, @@ -19,11 +19,11 @@ from zope.configuration import xmlconfig from zope.configuration.exceptions import ConfigurationError -from zope.app.component.tests.views import IC, V1 +from zope.app.component.tests.views import IC, V1, Request from zope.app.testing.placelesssetup import PlacelessSetup from zope.security.proxy import ProxyFactory -from zope.component.tests.request import Request +#from zope.component.tests.request import Request from jsonserver.interfaces import IJSONRPCRequest Modified: z3/jsonserver/trunk/tests/test_httpfactory.py ============================================================================== --- z3/jsonserver/trunk/tests/test_httpfactory.py (original) +++ z3/jsonserver/trunk/tests/test_httpfactory.py Thu Apr 27 15:06:47 2006 @@ -1,6 +1,6 @@ ############################################################################## # -# Copyright (c) 2003 - 2005 Zope Corporation and Contributors. +# Copyright (c) 2003 - 2005 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, @@ -23,7 +23,7 @@ from zope.publisher.browser import BrowserRequest from zope.publisher.http import HTTPRequest from jsonserver.jsonrpc import JSONRPCRequest -from zope.component.tests.placelesssetup import PlacelessSetup +from zope.component.testing import PlacelessSetup from jsonserver.interfaces import IJSONRPCRequestFactory from zope.app.publication.httpfactory import HTTPPublicationRequestFactory from zope.app.publication.browser import BrowserPublication From faassen at codespeak.net Mon May 1 18:29:55 2006 From: faassen at codespeak.net (faassen@codespeak.net) Date: Mon May 1 18:29:57 2006 Subject: [z3-checkins] r26637 - z3/hurry/trunk Message-ID: <20060501162955.47EA8100AD@code0.codespeak.net> Author: faassen Date: Mon May 1 18:29:54 2006 New Revision: 26637 Added: z3/hurry/trunk/CHANGES.txt Log: Add changelog. Added: z3/hurry/trunk/CHANGES.txt ============================================================================== --- (empty file) +++ z3/hurry/trunk/CHANGES.txt Mon May 1 18:29:54 2006 @@ -0,0 +1,7 @@ +hurry changes +============= + +0.8 (2006-05-01) +---------------- + +Initial public release. From faassen at codespeak.net Mon May 1 18:50:29 2006 From: faassen at codespeak.net (faassen@codespeak.net) Date: Mon May 1 18:50:31 2006 Subject: [z3-checkins] r26638 - z3/hurry/trunk Message-ID: <20060501165029.DCFFF100AD@code0.codespeak.net> Author: faassen Date: Mon May 1 18:50:29 2006 New Revision: 26638 Modified: z3/hurry/trunk/INSTALL.txt Log: Intermediate checkin, needs more information. Modified: z3/hurry/trunk/INSTALL.txt ============================================================================== --- z3/hurry/trunk/INSTALL.txt (original) +++ z3/hurry/trunk/INSTALL.txt Mon May 1 18:50:29 2006 @@ -1,9 +1,13 @@ Installation ------------ -Hurry needs Zope 3.1. Install it in a Zope install's lib/python +Hurry needs Zope 3.1. It can work with Zope 3.2 too. Make sure hurry's +src directory is on the Python path somehow, and then copy +hurry-configure.zcml into your Zope's `etc/package-includes` directory. hurry.query also has support for zc.catalog SetIndexes in -hurry.query.set. zc.catalog can be found here in the Zope 3 -SVN repository, in Sandbox/zc/catalog/ +hurry.query.set. zc.catalog can be found here in the Zope 3 SVN +repository, in Sandbox/zc/catalog/. You also need to copy +`zc.catalog-configure.zcml` into your Zope's `etc/package-includes` +directory. From reebalazs at codespeak.net Tue May 2 15:55:07 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Tue May 2 15:55:08 2006 Subject: [z3-checkins] r26670 - z3/jsonserver/branch/zope2_test Message-ID: <20060502135507.7049C100A0@code0.codespeak.net> Author: reebalazs Date: Tue May 2 15:55:06 2006 New Revision: 26670 Modified: z3/jsonserver/branch/zope2_test/jsonrpc.py Log: Fix IJsonRequest interface providing problem earlier addressed in r26026 The problem is triggered from the traverse hook set up by Five on traversable objects. This calls setDefaultSkin in zope and this in effect sets the IBrowserLayer on the request but also purges all other interfaces. Which may not be a bug from a zope3 point of view, but it screws things in this combination XXX Workaround. We call setDefaultSkin ourselves, so later it does not touch the interface any more. Modified: z3/jsonserver/branch/zope2_test/jsonrpc.py ============================================================================== --- z3/jsonserver/branch/zope2_test/jsonrpc.py (original) +++ z3/jsonserver/branch/zope2_test/jsonrpc.py Tue May 2 15:55:06 2006 @@ -21,10 +21,10 @@ from zLOG import LOG, INFO, DEBUG, WARNING, ERROR from cgi import FieldStorage import ZPublisher.HTTPResponse -##from zope.interface import directlyProvides, directlyProvidedBy -from zope.interface import implements +from zope.interface import directlyProvides, directlyProvidedBy from interfaces import IJsonRequest from ZPublisher.HTTPRequest import HTTPRequest +from zope.app.publication.browser import setDefaultSkin # this is used to identify incoming requests request_content_type = 'application/json-rpc' @@ -200,11 +200,6 @@ # Patching processInputs of ZPublisher.HTTPRequest # -- -class JsonRpcRequest(HTTPRequest): - 'JSON-RPC HTTP request' - # this is just used to force the interface on the object - implements(IJsonRequest) - re_content_type= re.compile(r'charset\s*=\s*([^;]+)') def processInputs(self, **kw): @@ -255,10 +250,18 @@ # XXX this would be good but for some reason gets "swallowed" # by the time we get there, so we override the class instead. # This error first manifested in Zope2.9, it was ok. till 2.8. - ##interfaces = directlyProvidedBy(self) - ##interfaces += IJsonRequest - ##directlyProvides(self, interfaces) - self.__class__ = JsonRpcRequest + # The problem is triggered from the traverse hook set up by Five + # on traversable objects. This calls setDefaultSkin in zope and this + # in effect sets the IBrowserLayer on the request but also purges + # all other interfaces. Which may not be a bug from a zope3 point + # of view, but it screws things in this combination + # XXX Workaround. We call setDefaultSkin ourselves, so later it + # does not touch the interface any more. + setDefaultSkin(self) + # + interfaces = directlyProvidedBy(self) + interfaces += IJsonRequest + directlyProvides(self, interfaces) # response = Response(response, jsonID) other['RESPONSE'] = self.response = response From regebro at codespeak.net Tue May 2 17:46:44 2006 From: regebro at codespeak.net (regebro@codespeak.net) Date: Tue May 2 17:46:45 2006 Subject: [z3-checkins] r26677 - in z3/CMFonFive/trunk: . tests/products/CMFonFiveTest tests/products/CMFonFiveTest/tests Message-ID: <20060502154644.8E2BA100BB@code0.codespeak.net> Author: regebro Date: Tue May 2 17:46:44 2006 New Revision: 26677 Modified: z3/CMFonFive/trunk/CHANGES.txt z3/CMFonFive/trunk/configure.zcml z3/CMFonFive/trunk/tests/products/CMFonFiveTest/configure.zcml z3/CMFonFive/trunk/tests/products/CMFonFiveTest/tests/test_actionstool.py Log: - Got rid of some i18n warnings. - Fixed an incorrect import so it works in Zope 2.10 as well. Modified: z3/CMFonFive/trunk/CHANGES.txt ============================================================================== --- z3/CMFonFive/trunk/CHANGES.txt (original) +++ z3/CMFonFive/trunk/CHANGES.txt Tue May 2 17:46:44 2006 @@ -1,6 +1,9 @@ CMFonFive Product Changelog CMFonFive 1.3.3 (unreleased) + - Got rid of some i18n warnings. + + - Fixed an incorrect import so it works in Zope 2.10 as well. - The id of the action is now generated from the last part of the interface the menu item is defined for, and the last part of the action. This should Modified: z3/CMFonFive/trunk/configure.zcml ============================================================================== --- z3/CMFonFive/trunk/configure.zcml (original) +++ z3/CMFonFive/trunk/configure.zcml Tue May 2 17:46:44 2006 @@ -1,5 +1,6 @@ Modified: z3/CMFonFive/trunk/tests/products/CMFonFiveTest/configure.zcml ============================================================================== --- z3/CMFonFive/trunk/tests/products/CMFonFiveTest/configure.zcml (original) +++ z3/CMFonFive/trunk/tests/products/CMFonFiveTest/configure.zcml Tue May 2 17:46:44 2006 @@ -1,6 +1,7 @@ + xmlns:five="http://namespaces.zope.org/five" + i18n_domain="CMF"> Modified: z3/CMFonFive/trunk/tests/products/CMFonFiveTest/tests/test_actionstool.py ============================================================================== --- z3/CMFonFive/trunk/tests/products/CMFonFiveTest/tests/test_actionstool.py (original) +++ z3/CMFonFive/trunk/tests/products/CMFonFiveTest/tests/test_actionstool.py Tue May 2 17:46:44 2006 @@ -7,7 +7,8 @@ from Testing import ZopeTestCase from Testing.ZopeTestCase.functional import Functional from Products.CMFCore.utils import getToolByName -from Products.Five.traversable import newInteraction + +from Products.Five.security import newInteraction # we need to install test products *before* Five as Five # looks up zcml files in the products it can find. @@ -31,10 +32,10 @@ newInteraction() actions = tool.listActions(object=self.folder.content) action_names = [action.id for action in actions] - self.failUnless('action_content_public.html' in action_names, + self.failUnless('icmfcontent_public.html' in action_names, 'Expected menu item was not found in action list') # But not the protected action: - self.failIf('action_content_protected.html' in action_names, + self.failIf('icmfcontent_protected.html' in action_names, 'Protected menu item was found in action list') # And there should be no actions anywhere else: self.failUnlessEqual(list(tool.listActions(object=self.folder)), []) From regebro at codespeak.net Tue May 2 17:57:56 2006 From: regebro at codespeak.net (regebro@codespeak.net) Date: Tue May 2 17:57:57 2006 Subject: [z3-checkins] r26679 - z3/CMFonFive/trunk Message-ID: <20060502155756.871FE100BF@code0.codespeak.net> Author: regebro Date: Tue May 2 17:57:56 2006 New Revision: 26679 Modified: z3/CMFonFive/trunk/CHANGES.txt z3/CMFonFive/trunk/README.txt Log: Updated teh readmes to refelct the fact that GenericSetup has been required for quite some time. Modified: z3/CMFonFive/trunk/CHANGES.txt ============================================================================== --- z3/CMFonFive/trunk/CHANGES.txt (original) +++ z3/CMFonFive/trunk/CHANGES.txt Tue May 2 17:57:56 2006 @@ -13,12 +13,13 @@ The reason for this change is that it enables you to add icons with the CMF ActionIconsTool. - CMFonFive 1.3.2 (2005-02-22) + CMFonFive 1.3.2 (2006-02-22) - GenericSetup calls all action providers with both object and info as None, which resulted in an attribute error. - - Added a GenericSetup profile. + - Added a GenericSetup profile. This means you need to use CMF 1.6.0 or + later, or download and install GenericSetup. - Got rid of a deprecation warning for product_name. Modified: z3/CMFonFive/trunk/README.txt ============================================================================== --- z3/CMFonFive/trunk/README.txt (original) +++ z3/CMFonFive/trunk/README.txt Tue May 2 17:57:56 2006 @@ -41,7 +41,8 @@ * CMFonFive 1.3.2 (2006-02-22) - For CMF 1.5.2 and later, with Zope 2.9. + For CMF 1.5.2 and later, with Zope 2.9. + Requires GenericSetup or CMF 1.6 (Where GenericSetup is included). http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.3.2.tgz From jinty at codespeak.net Wed May 3 09:21:24 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Wed May 3 09:21:26 2006 Subject: [z3-checkins] r26704 - z3/sqlos/branch/0.2/Zope2/FiveSQLOS Message-ID: <20060503072124.4BA96100BB@code0.codespeak.net> Author: jinty Date: Wed May 3 09:21:21 2006 New Revision: 26704 Modified: z3/sqlos/branch/0.2/Zope2/FiveSQLOS/configure.zcml Log: oops, that was the wrong place to get ISQLObject. Modified: z3/sqlos/branch/0.2/Zope2/FiveSQLOS/configure.zcml ============================================================================== --- z3/sqlos/branch/0.2/Zope2/FiveSQLOS/configure.zcml (original) +++ z3/sqlos/branch/0.2/Zope2/FiveSQLOS/configure.zcml Wed May 3 09:21:21 2006 @@ -7,7 +7,7 @@ From jinty at codespeak.net Wed May 3 09:23:04 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Wed May 3 09:23:06 2006 Subject: [z3-checkins] r26706 - z3/sqlos/trunk/Zope2/FiveSQLOS Message-ID: <20060503072304.7EBF9100C2@code0.codespeak.net> Author: jinty Date: Wed May 3 09:23:02 2006 New Revision: 26706 Modified: z3/sqlos/trunk/Zope2/FiveSQLOS/configure.zcml Log: oops, that was the wrong place to get ISQLObject. Modified: z3/sqlos/trunk/Zope2/FiveSQLOS/configure.zcml ============================================================================== --- z3/sqlos/trunk/Zope2/FiveSQLOS/configure.zcml (original) +++ z3/sqlos/trunk/Zope2/FiveSQLOS/configure.zcml Wed May 3 09:23:02 2006 @@ -7,7 +7,7 @@ From faassen at codespeak.net Wed May 3 11:42:23 2006 From: faassen at codespeak.net (faassen@codespeak.net) Date: Wed May 3 11:42:24 2006 Subject: [z3-checkins] r26715 - z3/hurry/trunk Message-ID: <20060503094223.774B5100AB@code0.codespeak.net> Author: faassen Date: Wed May 3 11:42:22 2006 New Revision: 26715 Modified: z3/hurry/trunk/INSTALL.txt Log: Update a bit. Modified: z3/hurry/trunk/INSTALL.txt ============================================================================== --- z3/hurry/trunk/INSTALL.txt (original) +++ z3/hurry/trunk/INSTALL.txt Wed May 3 11:42:22 2006 @@ -1,13 +1,14 @@ Installation ------------ -Hurry needs Zope 3.1. It can work with Zope 3.2 too. Make sure hurry's -src directory is on the Python path somehow, and then copy -hurry-configure.zcml into your Zope's `etc/package-includes` +Hurry needs Zope 3.1 or Zope 3.2. + +Make sure hurry's src directory is on the Python path somehow, and +then copy hurry-configure.zcml into your Zope's `etc/package-includes` directory. hurry.query also has support for zc.catalog SetIndexes in -hurry.query.set. zc.catalog can be found here in the Zope 3 SVN -repository, in Sandbox/zc/catalog/. You also need to copy -`zc.catalog-configure.zcml` into your Zope's `etc/package-includes` -directory. +hurry.query.set. If you want to use this extension, you need to +install zc.catalog. It can be found in Zope's SVN repository. You +then also need to copy `zc.catalog-configure.zcml` into your Zope's +`etc/package-includes` directory. From faassen at codespeak.net Wed May 3 11:51:49 2006 From: faassen at codespeak.net (faassen@codespeak.net) Date: Wed May 3 11:51:50 2006 Subject: [z3-checkins] r26716 - z3/hurry/tag Message-ID: <20060503095149.6F143100AB@code0.codespeak.net> Author: faassen Date: Wed May 3 11:51:48 2006 New Revision: 26716 Added: z3/hurry/tag/ Log: Directory to make releases in. From faassen at codespeak.net Wed May 3 11:51:57 2006 From: faassen at codespeak.net (faassen@codespeak.net) Date: Wed May 3 11:51:58 2006 Subject: [z3-checkins] r26717 - z3/hurry/tag/hurry-0.8 Message-ID: <20060503095157.4CA2C100AB@code0.codespeak.net> Author: faassen Date: Wed May 3 11:51:56 2006 New Revision: 26717 Added: z3/hurry/tag/hurry-0.8/ - copied from r26716, z3/hurry/trunk/ Log: Create hurry 0.8 release tag. From srichter at codespeak.net Thu May 4 00:13:02 2006 From: srichter at codespeak.net (srichter@codespeak.net) Date: Thu May 4 00:13:11 2006 Subject: [z3-checkins] r26742 - z3/hurry/trunk/src/hurry/query Message-ID: <20060503221302.2507910092@code0.codespeak.net> Author: srichter Date: Thu May 4 00:12:11 2006 New Revision: 26742 Modified: z3/hurry/trunk/src/hurry/query/set.py Log: ICatalogSetIndex is an overly strict requirement; ISetIndex is really what you wanted in the first place. Modified: z3/hurry/trunk/src/hurry/query/set.py ============================================================================== --- z3/hurry/trunk/src/hurry/query/set.py (original) +++ z3/hurry/trunk/src/hurry/query/set.py Thu May 4 00:12:11 2006 @@ -1,10 +1,10 @@ -from zc.catalog.interfaces import ICatalogSetIndex +from zc.catalog.interfaces import ISetIndex from hurry.query import query class SetTerm(query.IndexTerm): def getIndex(self): index = super(SetTerm, self).getIndex() - assert ICatalogSetIndex.providedBy(index) + assert ISetIndex.providedBy(index) return index class AnyOf(SetTerm): From philikon at codespeak.net Thu May 4 01:29:46 2006 From: philikon at codespeak.net (philikon@codespeak.net) Date: Thu May 4 01:29:58 2006 Subject: [z3-checkins] r26743 - z3/www/trunk Message-ID: <20060503232946.C78FF10090@code0.codespeak.net> Author: philikon Date: Thu May 4 01:29:36 2006 New Revision: 26743 Modified: z3/www/trunk/mkwebsite.py Log: new releases Modified: z3/www/trunk/mkwebsite.py ============================================================================== --- z3/www/trunk/mkwebsite.py (original) +++ z3/www/trunk/mkwebsite.py Thu May 4 01:29:36 2006 @@ -152,24 +152,24 @@ site.registerReleases([ Z3ReleaseResource( - 'Five', 'svn://svn.zope.org/repos/main/Products.Five/tags/1.1'), + 'Five', 'svn://svn.zope.org/repos/main/Products.Five/tags/1.2.4'), Z3ReleaseResource( - 'Five', 'svn://svn.zope.org/repos/main/Products.Five/tags/1.2.2'), + 'Five', 'svn://svn.zope.org/repos/main/Products.Five/tags/1.3.5'), Z3ReleaseResource( - 'Five', 'svn://svn.zope.org/repos/main/Products.Five/tags/1.3.3'), + 'Five', 'svn://svn.zope.org/repos/main/Products.Five/tags/1.4c'), ], project.getName()) from z3publish import Z3TestPage site.registerPages([ - ZopeOrgPage('Products.Five/trunk', 'doc/main.txt', 'index'), - ZopeOrgPage('Products.Five/tags/1.3.3', 'doc/features.txt'), - ZopeOrgPage('Products.Five/tags/1.3.3', 'doc/directives.txt'), - ZopeOrgPage('Products.Five/tags/1.3.3', 'doc/manual.txt'), - ZopeOrgPage('Products.Five/tags/1.3.3', 'doc/i18n.txt'), - ZopeOrgPage('Products.Five/tags/1.3.3', 'doc/localsite.txt'), - ZopeOrgPage('Products.Five/tags/1.3.3', 'doc/event.txt'), - ZopeOrgPage('Products.Five/tags/1.3.3', 'CHANGES.txt'), - ZopeOrgPage('Products.Five/tags/1.3.3', 'INSTALL.txt'),], + ZopeOrgPage('Products.Five/tags/1.5b', 'doc/main.txt', 'index'), + ZopeOrgPage('Products.Five/tags/1.5b', 'doc/features.txt'), + ZopeOrgPage('Products.Five/tags/1.5b', 'doc/directives.txt'), + ZopeOrgPage('Products.Five/tags/1.5b', 'doc/manual.txt'), + ZopeOrgPage('Products.Five/tags/1.5b', 'doc/i18n.txt'), + ZopeOrgPage('Products.Five/tags/1.5b', 'doc/localsite.txt'), + ZopeOrgPage('Products.Five/tags/1.5b', 'doc/event.txt'), + ZopeOrgPage('Products.Five/tags/1.5b', 'CHANGES.txt'), + ZopeOrgPage('Products.Five/tags/1.5b', 'INSTALL.txt'),], site.getProjectLayouter(project), project.getName(), nav_links=nav_links, From philikon at codespeak.net Thu May 4 01:30:28 2006 From: philikon at codespeak.net (philikon@codespeak.net) Date: Thu May 4 01:30:30 2006 Subject: [z3-checkins] r26744 - z3/www/trunk/text Message-ID: <20060503233028.DB1C010090@code0.codespeak.net> Author: philikon Date: Thu May 4 01:30:22 2006 New Revision: 26744 Modified: z3/www/trunk/text/index.txt Log: news Modified: z3/www/trunk/text/index.txt ============================================================================== --- z3/www/trunk/text/index.txt (original) +++ z3/www/trunk/text/index.txt Thu May 4 01:30:22 2006 @@ -21,6 +21,8 @@ News ---- +* 2005-05-04 `Five`_ 1.2.4, 1.3.5, 1.4c and 1.5b released! + * 2005-02-25 `Five`_ 1.2.1 and 1.3.2 released! Download `Five 1.2.1`_ and `Five 1.3.2`_ From philikon at codespeak.net Thu May 4 01:39:17 2006 From: philikon at codespeak.net (philikon@codespeak.net) Date: Thu May 4 01:39:20 2006 Subject: [z3-checkins] r26745 - z3/www/trunk/text Message-ID: <20060503233917.7841510090@code0.codespeak.net> Author: philikon Date: Thu May 4 01:39:11 2006 New Revision: 26745 Added: z3/www/trunk/text/five_releasefest.txt - copied, changed from r26742, z3/www/trunk/text/five_1_2_1_3_release.txt Log: release notes for release fest Copied: z3/www/trunk/text/five_releasefest.txt (from r26742, z3/www/trunk/text/five_1_2_1_3_release.txt) ============================================================================== --- z3/www/trunk/text/five_1_2_1_3_release.txt (original) +++ z3/www/trunk/text/five_releasefest.txt Thu May 4 01:39:11 2006 @@ -1,8 +1,9 @@ -Five 1.2 and 1.3 released! -========================== +Five 1.2.4, 1.3.5, 1.4c and 1.5b released! +========================================== -The Five team is happy to announce the release of two Five versions -today, Five 1.2 and 1.3! +The Five team is happy to announce the release of two Five bugfix +releases, 1.2.4 and 1.3.5, as well as two Five betas, 1.4c and 1.5b +today. What is Five @@ -23,88 +24,47 @@ http://codespeak.net/z3/five/. -Five 1.2 --------- +About Five 1.4 and 1.5 +---------------------- -Five 1.2 is the last release line of Five to work with Zope 2.8 and -its included Zope X3 3.0. It does not work on Zope 2.7 anymore (use -Five 1.1 if you're bound to Zope 2.7) - -Compared to 1.1, it introduces the following compelling list of new -features: - -* Local site support - - Five now supports local sites in Zope 2. Sites are a concept known - from Zope 3 and similar to CMF's sites (only that they can be - nested). Thanks to Sidnei da Silva for the initial development back - in March, Lennart Regebro and Philipp von Weitershausen for bringing - it up to date for inclusion into Five 1.2. - -* Improved event support - - Five can now make standard Zope 2 containers (aka object managers) - send Zope 3-style events for adding, moving, copying and deleting - contained objects, instead of calling their manage_afterAdd, - manage_beforeDelete, etc. methods. Thanks to Florent Guillaume for - thinking through this non-trivial matter and implementing it. - -* Marker interfaces utility - - Five now includes a feature known from Zope X3 3.0's introspector, - the ability to set marker interfaces on objects to influence their - behaviour (such as view or adapter look-up). This also includes a - browser page with a page template macro for doing so - through-the-web. This feature is based on Sidnei da Silva's - Plone-based product Flon. Thanks to him for the original - implementation as well as Godefroid Chapelle, Whit Morriss and Yvo - Schubbe for bringing it to Five 1.2. - -* Class registration through ZCML - - It is now possible to register Zope 2 classes through ZCML so that - they show up in the ZMI as addable meta types. This basically - obsolete's the boiler-plate ``initialize()`` function in products' - ``__init__.py`` files, as well as equipping classes with a - ``meta_type`` in the first place. Thanks to Yvo Schubbe for - suggesting and implementing this great helper for cleaning out Zope - 2 boiler plate code out of products. - -* New test runner - - Five 1.2 (and only 1.2) includes a forked copy of Zope 3.2's - improved test runner which brings, among others, better doctest - debugging and support for running tests on different levels and - layers. Thanks to Tres Seaver for integrating this into Five 1.2. - -For more information please consult the `changes document`_. - -.. _changes document: http://codespeak.net/z3/five/CHANGES.html - -Five 1.2 can be downloaded at -http://codespeak.net/z3/five/release/Five-1.2.tgz. - - -Five 1.3 --------- - -Five 1.3 is a straight port of Five 1.2 to Zope 3.2 which will be -included in this December's Zope 2.9 release. Five 1.3 itself will -also be part of Zope 2.9. It does not introduce any new features -compared to Five 1.2, however, some restructuring has been made: - -* Most of the event work has been folded into Zope 2. That means that - Zope 2.9 will ship with event-enabled object managers out of the - box! - -* Several legacy packages were removed from Five as they are now - included in Zope 2, such as Zope 3-style interfaces for OFS - et.al. as well as the new test runner - -We are not providing a downloadable tarball of Five 1.3. Instead it -has been integrated into Zope 2.9 with which it will ship. To try out -Zope 2.9, you have to currently check out the Zope 2 trunk from the -subversion repository. +Five 1.4 and 1.5 are feature releases. They are basically equivalent +except that Five 1.4 works with Zope 2.9/3.2 (only) and 1.5 works with +Zope 2.10/3.3 (only). Five 1.5 will be included in Zope 2.10. + +Most important features are: + +* Added viewlet and content provider support. A big thanks to Alec + Mitchell and his helpers at the Archipelago sprint for making this + possible. + +* Add zope.formlib support. Please see ``doc/formlib.txt`` for more + information. A big thanks to Jan-Wijbrand Kolman for this. + +* Port zope.testbrowser to Zope 2. You can now use + Products.Five.testbrowser.Browser in functional tests. Much thanks + to Brian Sutherland. + +* Add python-packages-as-zope-products support which basically allows + for using any python package as a zope product without it having to + live in Products/. Much thanks to Rocky Burt for this. + +Zope 2.10 and Five 1.5 are also a big milestone in the convergence of +Zope 2 and Zope 3, for it is no longer necessary to mark classes with +five:traversable and five:defaultViewable to enable Zope 3 view lookup +functionality. A big thanks goes to Lennart Regebro and Michael +Kerrin for making this possible! + + +Changes in Five 1.2.4/1.3.5 and 1.4c (compared to 1.4b) +------------------------------------------------------- + +* Made sure that events are fired as expected in add and edit forms. + +* Made sure LocalizerLanguages class normalized language codes to + xx-yy, instead of xx_YY or xx-YY. + +* Fixed a problem with the new traversal look-up order and the root + object (OFS.Application.Application). About the Zope 3 Base From jinty at codespeak.net Fri May 5 05:31:41 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Fri May 5 05:31:42 2006 Subject: [z3-checkins] r26781 - z3/sqlos/trunk Message-ID: <20060505033141.443B110088@code0.codespeak.net> Author: jinty Date: Fri May 5 05:26:18 2006 New Revision: 26781 Modified: z3/sqlos/trunk/setup.cfg z3/sqlos/trunk/setup.py Log: Bump version number to the next release and fix setup.cfg Modified: z3/sqlos/trunk/setup.cfg ============================================================================== --- z3/sqlos/trunk/setup.cfg (original) +++ z3/sqlos/trunk/setup.cfg Fri May 5 05:26:18 2006 @@ -1,2 +1,3 @@ -[egg-info] +[egg_info] +tag_build = .svn tag_svn_revision = 1 Modified: z3/sqlos/trunk/setup.py ============================================================================== --- z3/sqlos/trunk/setup.py (original) +++ z3/sqlos/trunk/setup.py Fri May 5 05:26:18 2006 @@ -9,7 +9,7 @@ fiddly details that always seem to take a lot of time. """, url='http://codespeak.net/z3/sqlos/', - version="0.1", + version="0.3", license="ZPL", maintainer="SQLOS development team", maintainer_email="z3-sqlos@codespeak.net", From jinty at codespeak.net Fri May 5 05:53:02 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Fri May 5 05:53:03 2006 Subject: [z3-checkins] r26782 - z3/sqlos/trunk/src/sqlos Message-ID: <20060505035302.1B37A10088@code0.codespeak.net> Author: jinty Date: Fri May 5 05:53:00 2006 New Revision: 26782 Modified: z3/sqlos/trunk/src/sqlos/README.txt Log: Add an installation section to the README. Modified: z3/sqlos/trunk/src/sqlos/README.txt ============================================================================== --- z3/sqlos/trunk/src/sqlos/README.txt (original) +++ z3/sqlos/trunk/src/sqlos/README.txt Fri May 5 05:53:00 2006 @@ -50,7 +50,7 @@ ------------ -------- . Zope 3.2 ============ ======== -sqlos 0.2 X +sqlos 0.2.x X ============ ======== .. _FiveSQLOS: http://codespeak.net/svn/z3/sqlos/trunk/Zope2/FiveSQLOS/ @@ -121,6 +121,37 @@ connection and any registered class you wish. +Installation +------------ + +Zope3 +_____ + +You can easily install sqlos from the python cheeseshop using easy_install. +To do this, you will have to first install setuptools_. + +For example, this command will install sqlos and it's dependencies in +~/lib/python2.4/site-packages. Note that ~/lib/python2.4/site-packages should +be on the python path. + + $ easy_install --install-dir=~/lib/python2.4/site-packages 'sqlos == 0.2' + +After that, you should install the Zope Database Adapter you wish to use and +copy the sqlos-*.zcml package includes (in the includes directory in the +tarball) to the package-includes directory of your Zope instance. + +NOTE: the sqlos.ftesting-configure.zcml shouldn't be copied unless you want + to test the sample application. + + +Zope2 +_____ + +Same as for Zope3 above, except you do not have to setup the zcml package +includes. However, you do need to install the FiveSQLOS Zope2 product. This can +be found in the Zope2 directory in the tarball. + + A Sample Application -------------------- @@ -147,6 +178,7 @@ NOTE: changing debug=1 in src/sqlos/adapter.py will cause the SQL executed to be printed on the terminal + Setting up a connection for SQLObject ------------------------------------- From jinty at codespeak.net Fri May 5 05:56:02 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Fri May 5 05:56:04 2006 Subject: [z3-checkins] r26783 - z3/sqlos/trunk Message-ID: <20060505035602.CADB010088@code0.codespeak.net> Author: jinty Date: Fri May 5 05:55:55 2006 New Revision: 26783 Modified: z3/sqlos/trunk/makefile Log: Cut un-necssary cruft not needed by the latest setuptools. Modified: z3/sqlos/trunk/makefile ============================================================================== --- z3/sqlos/trunk/makefile (original) +++ z3/sqlos/trunk/makefile Fri May 5 05:55:55 2006 @@ -53,8 +53,7 @@ .PHONY: develop develop: Zope3-build sqlos-meta - touch Zope3/src/easy-install.pth - PYTHONPATH=Zope3/src $(PYTHON) setup.py develop -S Zope3/src --install-dir Zope3/src + PYTHONPATH=Zope3/src $(PYTHON) setup.py develop --install-dir Zope3/src .PHONY: testall test: develop From jinty at codespeak.net Fri May 5 06:00:01 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Fri May 5 06:00:03 2006 Subject: [z3-checkins] r26784 - z3/sqlos/tag/0.2.1 Message-ID: <20060505040001.D43A310088@code0.codespeak.net> Author: jinty Date: Fri May 5 05:59:57 2006 New Revision: 26784 Added: z3/sqlos/tag/0.2.1/ - copied from r26783, z3/sqlos/branch/0.2/ Log: Tag 0.2.1 release From jinty at codespeak.net Fri May 5 06:08:53 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Fri May 5 06:08:54 2006 Subject: [z3-checkins] r26785 - z3/sqlos/tag/0.2.1 Message-ID: <20060505040853.BA15210088@code0.codespeak.net> Author: jinty Date: Fri May 5 06:08:43 2006 New Revision: 26785 Modified: z3/sqlos/tag/0.2.1/setup.py Log: Bump version number. Modified: z3/sqlos/tag/0.2.1/setup.py ============================================================================== --- z3/sqlos/tag/0.2.1/setup.py (original) +++ z3/sqlos/tag/0.2.1/setup.py Fri May 5 06:08:43 2006 @@ -9,7 +9,7 @@ fiddly details that always seem to take a lot of time. """, url='http://codespeak.net/z3/sqlos/', - version="0.2.0", + version="0.2.1", license="ZPL", maintainer="SQLOS development team", maintainer_email="z3-sqlos@codespeak.net", From jinty at codespeak.net Fri May 5 06:41:35 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Fri May 5 06:41:37 2006 Subject: [z3-checkins] r26786 - z3/www/trunk Message-ID: <20060505044135.4246310088@code0.codespeak.net> Author: jinty Date: Fri May 5 06:41:15 2006 New Revision: 26786 Modified: z3/www/trunk/mkwebsite.py Log: Fix up sqlos links. Modified: z3/www/trunk/mkwebsite.py ============================================================================== --- z3/www/trunk/mkwebsite.py (original) +++ z3/www/trunk/mkwebsite.py Fri May 5 06:41:15 2006 @@ -223,11 +223,10 @@ def sqlos_site(site, project): nav_links = [ ('sqlos main', 'index.html'), - ('mailing list', '/mailman/listinfo/z3-sqlos'), ] quick_links = [ - ('sqlos 0.2.0 release (compatible with SQLObject 0.7)', - 'http://cheeseshop.python.org/pypi/sqlos/0.2.0'), + ('Mailing List', '/mailman/listinfo/z3-sqlos'), + ('Latest Releases', 'http://cheeseshop.python.org/pypi/sqlos/'), ('sqlos 0.1 release (compatible with SQLObject 0.6)', 'release/sqlos-0.1.tgz'), ('svn (the code)', From jinty at codespeak.net Fri May 5 06:55:19 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Fri May 5 06:55:20 2006 Subject: [z3-checkins] r26787 - z3/sqlos/trunk/doc Message-ID: <20060505045519.BC83B10088@code0.codespeak.net> Author: jinty Date: Fri May 5 06:55:11 2006 New Revision: 26787 Modified: z3/sqlos/trunk/doc/HowToMakeARealease.rst Log: Add a release message template. Modified: z3/sqlos/trunk/doc/HowToMakeARealease.rst ============================================================================== --- z3/sqlos/trunk/doc/HowToMakeARealease.rst (original) +++ z3/sqlos/trunk/doc/HowToMakeARealease.rst Fri May 5 06:55:11 2006 @@ -54,7 +54,37 @@ To: z3-sqlos@codespeak.net + zope-announce@zope.org TODO: More? Template: - TODO + +XXXMESSAGE + +What is sqlos: + + sqlos is a toolkit for using SQLObject (http://sqlobject.org) + inside Zope 3 or Zope 2. It tries to take care of many of the fiddly + details that always seem to take a lot of time. The major ways it + helps are: + + - Integrates the Zope transaction system and SQLObject, allowing + SQLObject to be used in lazyUpdate mode. + + - Uses Zope Database adapters in SQLObject. + + - Provide zcml configuration directives. + + - Provide ZODB persistent objects that can act as a "window" into + the database. + + - A testing infrastructure for testing SQLObject based applications. + + - Caches SQLObjects and database connections to improve + performance. + +More info: + http://codespeak.net/z3/sqlos/index.html + +Releases: + http://cheeseshop.python.org/pypi/sqlos From philikon at codespeak.net Fri May 5 20:53:57 2006 From: philikon at codespeak.net (philikon@codespeak.net) Date: Fri May 5 20:54:01 2006 Subject: [z3-checkins] r26830 - z3/www/trunk Message-ID: <20060505185357.E979910092@code0.codespeak.net> Author: philikon Date: Fri May 5 20:53:55 2006 New Revision: 26830 Modified: z3/www/trunk/mkwebsite.py Log: update releases in quicklinks Modified: z3/www/trunk/mkwebsite.py ============================================================================== --- z3/www/trunk/mkwebsite.py (original) +++ z3/www/trunk/mkwebsite.py Fri May 5 20:53:55 2006 @@ -142,12 +142,12 @@ 'http://codespeak.net/mailman/listinfo/z3-five'), ('z3-checkins mailing list', 'http://codespeak.net/mailman/listinfo/z3-checkins'), - ('Five 1.0.3 release', - 'release/Five-1.0.3.tgz'), - ('Five 1.2.2 release', - 'release/Five-1.2.2.tgz'), - ('Five 1.3.3 release', - 'release/Five-1.3.3.tgz'), + ('Five 1.2.4 release', + 'release/Five-1.2.4.tgz'), + ('Five 1.3.5 release', + 'release/Five-1.3.5.tgz'), + ('Five 1.4c release', + 'release/Five-1.4c.tgz'), ] site.registerReleases([ From srichter at codespeak.net Sat May 6 14:53:03 2006 From: srichter at codespeak.net (srichter@codespeak.net) Date: Sat May 6 14:53:04 2006 Subject: [z3-checkins] r26869 - z3/hurry/trunk/src/hurry/query Message-ID: <20060506125303.B22641007E@code0.codespeak.net> Author: srichter Date: Sat May 6 14:53:01 2006 New Revision: 26869 Added: z3/hurry/trunk/src/hurry/query/value.py (contents, props changed) Modified: z3/hurry/trunk/src/hurry/query/query.py z3/hurry/trunk/src/hurry/query/query.txt z3/hurry/trunk/src/hurry/query/set.py Log: - Implemented queries for the ``zc.catalog`` module's ``ValueIndex``. It pretty much does the same as the ``FieldIndex`` queries, except that it supports the additional features of the value index, such as extents, exclude_min and exclude_max. - Soem whitespace cleanup. Martijn, I hope you are okay with those changes. I think that we eventually want to merge the ``set`` and ``value`` module queries into the main ones as to not duplicate so much of the API. Modified: z3/hurry/trunk/src/hurry/query/query.py ============================================================================== --- z3/hurry/trunk/src/hurry/query/query.py (original) +++ z3/hurry/trunk/src/hurry/query/query.py Sat May 6 14:53:01 2006 @@ -15,7 +15,7 @@ class Query(object): implements(interfaces.IQuery) - + def searchResults(self, query): results = query.apply() if results is not None: @@ -29,7 +29,7 @@ def __rand__(self, other): return And(other, self) - + def __or__(self, other): return Or(self, other) @@ -38,7 +38,7 @@ def __invert__(self): return Not(self) - + class And(Term): def __init__(self, *terms): self.terms = terms @@ -63,13 +63,13 @@ for _, r in results: _, result = weightedIntersection(result, r) return result - + class Or(Term): def __init__(self, *terms): self.terms = terms def apply(self): - results = [] + results = [] for term in self.terms: r = term.apply() # empty results @@ -91,7 +91,7 @@ def __init__(self, term): self.term = term - def apply(self): + def apply(self): return difference(self._all(), self.term.apply()) def _all(self): @@ -123,17 +123,17 @@ index = super(Text, self).getIndex() assert ITextIndex.providedBy(index) return index - + def apply(self): index = self.getIndex() return index.apply(self.text) - + class FieldTerm(IndexTerm): def getIndex(self): index = super(FieldTerm, self).getIndex() assert IFieldIndex.providedBy(index) return index - + class Eq(FieldTerm): def __init__(self, index_id, value): assert value is not None @@ -176,7 +176,7 @@ assert None not in values super(In, self).__init__(index_id) self.values = values - + def apply(self): results = [] index = self.getIndex() Modified: z3/hurry/trunk/src/hurry/query/query.txt ============================================================================== --- z3/hurry/trunk/src/hurry/query/query.txt (original) +++ z3/hurry/trunk/src/hurry/query/query.txt Sat May 6 14:53:01 2006 @@ -40,7 +40,7 @@ easily. By including the __cmp__ method we make sure search results can be stably sorted. -We use a fake int id utility here so we can test independent of +We use a fake int id utility here so we can test independent of the full-blown zope environment:: >>> from zope.interface import verify @@ -98,7 +98,7 @@ ... Content(6, 'Y', 'Z')] And catalog them now:: - + >>> for entry in content: ... catalog.index_doc(intid.register(entry), entry) @@ -168,7 +168,7 @@ Using and (&):: - >>> f2 = ('catalog1', 'f2') + >>> f2 = ('catalog1', 'f2') >>> displayQuery(Eq(f1, 'a') & Eq(f2, 'b')) [1, 4] @@ -209,6 +209,7 @@ >>> displayQuery(In(f1, ['a', 'X', 'Y', 'Z']) & In(f1, ['Z'])) [] + SetIndex queries ---------------- @@ -267,3 +268,127 @@ >>> displayQuery(AnyOf(f1, ['a']) & Eq(f2, 1)) [1, 2] + + +ValueIndex queries +------------------ + +The ``ValueIndex`` is defined in ``zc.catalog`` and provides a generalization +of the standard field index. + + >>> from hurry.query import value + +Let's set up a catalog that uses this index. The ``ValueIndex`` is defined in +``zc.catalog``. Let's make a catalog which uses it: + + >>> intid = DummyIntId() + >>> ztapi.provideUtility(zope.app.intid.interfaces.IIntIds, intid) + + >>> from zope.app.catalog.interfaces import ICatalog + >>> from zope.app.catalog.catalog import Catalog + >>> catalog = Catalog() + >>> ztapi.provideUtility(ICatalog, catalog, 'catalog1') + + >>> from zc.catalog.catalogindex import ValueIndex + >>> catalog['f1'] = ValueIndex('f1', IContent) + +Next we set up some content data to fill the indices: + + >>> content = [ + ... Content(1, 'a'), + ... Content(2, 'b'), + ... Content(3, 'c'), + ... Content(4, 'd'), + ... Content(5, 'c'), + ... Content(6, 'a')] + +And catalog them now: + + >>> for entry in content: + ... catalog.index_doc(intid.register(entry), entry) + + +Let's now query for all objects where ``f1`` equals 'a': + + >>> f1 = ('catalog1', 'f1') + >>> displayQuery(value.Eq(f1, 'a')) + [1, 6] + +Next, let's find all objects where ``f1`` does not equal 'a'; this is more +efficient than the generic ``~`` operator: + + >>> displayQuery(value.NotEq(f1, 'a')) + [2, 3, 4, 5] + +You can also query for all objects where the value of ``f1`` is in a set of +values: + + >>> displayQuery(value.In(f1, ['a', 'd'])) + [1, 4, 6] + +The next interesting set of queries allows you to make evaluations of the +values. For example, you can ask for all objects between a certain set of +values: + + >>> displayQuery(value.Between(f1, 'a', 'c')) + [1, 2, 3, 5, 6] + + >>> displayQuery(value.Between(f1, 'a', 'c', exclude_min=True)) + [2, 3, 5] + + >>> displayQuery(value.Between(f1, 'a', 'c', exclude_max=True)) + [1, 2, 6] + + >>> displayQuery(value.Between(f1, 'a', 'c', + ... exclude_min=True, exclude_max=True)) + [2] + +You can also leave out one end of the range: + + >>> displayQuery(value.Between(f1, 'c', None)) + [3, 4, 5] + >>> displayQuery(value.Between(f1, None, 'c')) + [1, 2, 3, 5, 6] + +You can also use greater-equals and lesser-equals for the same purpose: + + >>> displayQuery(value.Ge(f1, 'c')) + [3, 4, 5] + >>> displayQuery(value.Le(f1, 'c')) + [1, 2, 3, 5, 6] + +Of course, you can chain those queries with the others as demonstrated before. + +The ``value`` module also supports ``zc.catalog`` extents. The first query is +``ExtentAny``, which returns all douments matching the extent. If the the +extent is ``None``, all document ids are returned: + + >>> displayQuery(value.ExtentAny(f1, None)) + [1, 2, 3, 4, 5, 6] + +If we now create an extent that is only in the scope of the first four +documents, + + >>> from zc.catalog.extentcatalog import FilterExtent + >>> extent = FilterExtent(lambda extent, uid, obj: True) + >>> for i in range(4): + ... extent.add(i, i) + +then only the first four are returned: + + >>> displayQuery(value.ExtentAny(f1, extent)) + [1, 2, 3, 4] + +The opposite query is the ``ExtentNone`` query, which returns all ids in the +extent that are *not* in the index: + + >>> id = intid.register(Content(7, 'b')) + >>> id = intid.register(Content(8, 'c')) + >>> id = intid.register(Content(9, 'a')) + + >>> extent = FilterExtent(lambda extent, uid, obj: True) + >>> for i in range(9): + ... extent.add(i, i) + + >>> displayQuery(value.ExtentNone(f1, extent)) + [7, 8, 9] Modified: z3/hurry/trunk/src/hurry/query/set.py ============================================================================== --- z3/hurry/trunk/src/hurry/query/set.py (original) +++ z3/hurry/trunk/src/hurry/query/set.py Sat May 6 14:53:01 2006 @@ -6,12 +6,12 @@ index = super(SetTerm, self).getIndex() assert ISetIndex.providedBy(index) return index - + class AnyOf(SetTerm): def __init__(self, index_id, values): super(AnyOf, self).__init__(index_id) self.values = values - + def apply(self): return self.getIndex().apply({'any_of': self.values}) Added: z3/hurry/trunk/src/hurry/query/value.py ============================================================================== --- (empty file) +++ z3/hurry/trunk/src/hurry/query/value.py Sat May 6 14:53:01 2006 @@ -0,0 +1,79 @@ +from zc.catalog.interfaces import IValueIndex +from hurry.query import query + +class ValueTerm(query.IndexTerm): + def getIndex(self): + index = super(ValueTerm, self).getIndex() + assert IValueIndex.providedBy(index) + return index + +class Eq(ValueTerm): + def __init__(self, index_id, value): + assert value is not None + super(Eq, self).__init__(index_id) + self.value = value + + def apply(self): + return self.getIndex().apply({'any_of': (self.value,)}) + +class NotEq(ValueTerm): + def __init__(self, index_id, not_value): + super(NotEq, self).__init__(index_id) + self.not_value = not_value + + def apply(self): + index = self.getIndex() + values = list(index.values()) + values.remove(self.not_value) + return index.apply({'any_of': values}) + +class Between(ValueTerm): + def __init__(self, index_id, min_value=None, max_value=None, + exclude_min=False, exclude_max=False): + super(Between, self).__init__(index_id) + self.min_value = min_value + self.max_value = max_value + self.exclude_min = exclude_min + self.exclude_max = exclude_max + + def apply(self): + return self.getIndex().apply( + {'between': (self.min_value, self.max_value, + self.exclude_min, self.exclude_max)}) + +class Ge(Between): + def __init__(self, index_id, min_value): + super(Ge, self).__init__(index_id, min_value=min_value) + +class Le(Between): + def __init__(self, index_id, max_value): + super(Le, self).__init__(index_id, max_value=max_value) + +class In(ValueTerm): + def __init__(self, index_id, values): + assert None not in values + super(In, self).__init__(index_id) + self.values = values + + def apply(self): + return self.getIndex().apply({'any_of': self.values}) + +class ExtentAny(ValueTerm): + """Any ids in the extent that are indexed by this index. + """ + def __init__(self, index_id, extent): + super(ExtentAny, self).__init__(index_id) + self.extent = extent + + def apply(self): + return self.getIndex().apply({'any': self.extent}) + +class ExtentNone(ValueTerm): + """Any ids in the extent that are not indexed by this index. + """ + def __init__(self, index_id, extent): + super(ExtentNone, self).__init__(index_id) + self.extent = extent + + def apply(self): + return self.getIndex().apply({'none': self.extent}) From jinty at codespeak.net Mon May 8 14:21:38 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Mon May 8 14:21:41 2006 Subject: [z3-checkins] r26962 - z3/sqlos/trunk Message-ID: <20060508122138.C604310070@code0.codespeak.net> Author: jinty Date: Mon May 8 14:21:37 2006 New Revision: 26962 Modified: z3/sqlos/trunk/makefile Log: add src to the pythonpath so that we dont have to patch test.py. Modified: z3/sqlos/trunk/makefile ============================================================================== --- z3/sqlos/trunk/makefile (original) +++ z3/sqlos/trunk/makefile Mon May 8 14:21:37 2006 @@ -57,7 +57,7 @@ .PHONY: testall test: develop - cd Zope3 && $(PYTHON) test.py --test-path=../src -s sqlos + cd Zope3 && PYTHONPATH=src $(PYTHON) test.py --test-path=../src -s sqlos Zope3/principals.zcml: Zope3 Zope3/sample_principals.zcml cp Zope3/sample_principals.zcml $@ From jinty at codespeak.net Wed May 10 12:35:16 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Wed May 10 12:35:17 2006 Subject: [z3-checkins] r27039 - z3/sqlos/branch/jinty-sqlobject2 Message-ID: <20060510103516.E8DD2100A4@code0.codespeak.net> Author: jinty Date: Wed May 10 12:35:15 2006 New Revision: 27039 Added: z3/sqlos/branch/jinty-sqlobject2/ - copied from r27038, z3/sqlos/trunk/ Log: Make a branch for playing with SQLObject2 From jinty at codespeak.net Wed May 10 12:48:33 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Wed May 10 12:48:35 2006 Subject: [z3-checkins] r27040 - in z3/sqlos/branch/jinty-sqlobject2/src/sqlos: . interfaces Message-ID: <20060510104833.610B1100B3@code0.codespeak.net> Author: jinty Date: Wed May 10 12:48:30 2006 New Revision: 27040 Added: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces.py (contents, props changed) Removed: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/adapter.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces/ Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/__init__.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/connection.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/zsqlobject.py Log: Armageddon - Rip out stuff thats not going to be useful with SQLObject2. Of course that leaves this branch completely broken. Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/__init__.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/__init__.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/__init__.py Wed May 10 12:48:30 2006 @@ -9,25 +9,3 @@ """ $Id$ """ - -from datetime import datetime, date -from sqlobject.sqlbuilder import registerConverter - -# sqlos.SQLOS is softly deprecated, will go away sometime -# (after at least one major release with deprecation warnings) -# import directly from sqlos.zsqlobject -from sqlos.zsqlobject import SQLOS - - -## XXX: What are these?? I am sure there are no tests for them. - jinty -def DateTimeConverter(value, db=None): - return repr(value.isoformat()) - -registerConverter(datetime, DateTimeConverter) - -def DateConverter(value, db=None): - if isinstance(value, datetime): - return repr(value.date().isoformat()) - return repr(value.isoformat()) - -registerConverter(date, DateConverter) Deleted: /z3/sqlos/branch/jinty-sqlobject2/src/sqlos/adapter.py ============================================================================== --- /z3/sqlos/branch/jinty-sqlobject2/src/sqlos/adapter.py Wed May 10 12:48:30 2006 +++ (empty file) @@ -1,162 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004 Enfold Systems LLC. All rights reserved. -# Copyright (c) 2005-2006 Brian Sutherland. All rights reserved. -# -# This software is distributed under the terms of the Zope Public -# License (ZPL) v2.1. See COPYING.txt for more information. -# -############################################################################## -"""Connection adapters for sqlos. - -These adapters adapt Zope RDB Connections to SQLObject connections by -sub-classing the SQLObject connection classes. - -$Id$ -""" - -__metaclass__ = type - -from sqlobject.dbconnection import DBAPI -from sqlobject import _mysql, _postgres, _sqlite -from sqlobject.converters import registerConverter -from sqlobject.mysql import mysqlconnection -from zope.app.rdb.interfaces import DatabaseException -from zope.app.container.interfaces import INameChooser -from zope.interface import implements - -from sqlos.interfaces import ISQLObject -from sqlos._transaction import cache_manager - -# TODO: it is probably possible to optimize this by not creating a -# ConnectionAdapter every adapter lookup, but rather caching one per thread, -# and stuffing the connection into it using a factory function. Probably there -# would be one factory function per adapter type and we could get rid of the -# cache property on the ConnectionAdapter. - -class ConnectionAdapter: - - def __init__(self, connection): - DBAPI.__init__(self) - self._connection = connection - self.autoCommit = None - self.debug = 0 - self.supportTransactions = False - - def _get_cache(self): - return cache_manager.cache - def _set_cache(self, val): - pass # don't let ourselves be overridden - cache = property(_get_cache, _set_cache) - - def makeConnection(self): - return self._connection - - def getConnection(self): - # we override this because we really don't care about sqlobjects idea - # of threadsafe pool of db connections. zope.app.rdb takes care of - # that for us - return self.makeConnection() - - def releaseConnection(self, conn, explicit=False): - # we simply lobotomize this method because zope.app.rdb - # takes care of all commits/rollbacks as well as all threading issues - # with connections - pass - - def close(self): - # there is no sane way of doing this I can see. It would be nice to - # raise an error here, but sqlobject.dbconnection registers this method - # to be called when python exits. - pass - - def _executeRetry(self, conn, cursor, query): - try: - return cursor.execute(query) - except Exception, exc: - raise DatabaseException(str(exc.args)) - - def _runWithConnection(self, meth, *args): - conn = self.getConnection() - try: - try: - val = meth(conn, *args) - except DatabaseException: - raise # We may have already raised Database exception in - # _executeRetry, so we re-raise it - except Exception, exc: - raise DatabaseException, tuple(exc.args) - finally: - self.releaseConnection(conn) - return val - - def printDebug(self, conn, s, name, type='query'): - # XXX this is a quick hack to get it to work - jinty - if name == 'Pool' and self.debug != 'Pool': - return - if type == 'query': - sep = ': ' - else: - sep = '->' - s = repr(s) - spaces = ' '*(8-len(name)) - if self.debugThreading: - threadName = threading.currentThread().getName() - threadName = (':' + threadName + ' '*(8-len(threadName))) - else: - threadName = '' - print '%(threadName)s/%(name)s%(spaces)s%(sep)s %(s)s' % locals() - - -class MySQLAdapter(ConnectionAdapter, _mysql.builder()): - - def __init__(self, connection): - if getattr(self, 'module', None) == None: - import MySQLdb - self.module = MySQLdb - mysqlconnection.MySQLdb = MySQLdb - super(MySQLAdapter, self).__init__(connection) - - def _executeRetry(*args, **kw): - try: - return mysqlconnection.MySQLConnection._executeRetry(*args, **kw) - except Exception, exc: - raise DatabaseException(str(exc.args)) - - -class PostgresAdapter(ConnectionAdapter, _postgres.builder()): - - def __init__(self, connection): - #The import is needed, as sqlobject uses self.module.Binary uppon - #startup. But until now we dont define .module. There is definitely - #need for a better solution. Propably the other adapters need this as - #well, but i cant test them, as i dont have them. - #Andres Freund - 2005-10-17 - if getattr(self, 'module', None) == None: - import psycopg - self.module = psycopg - #This is needed, because psycopg provides a optimized - #Binary() function which sqlobject dont get along with. This is - #normally done in sqlobject.postgres.pgconnection __init__ but we - #dont call that. - from sqlobject.postgres import pgconnection - registerConverter(type(psycopg.Binary('')), - pgconnection.PsycoBinaryConverter) - - - super(PostgresAdapter, self).__init__(connection) - self.supportTransactions = True - - -class SQLiteAdapter(ConnectionAdapter, _sqlite.builder()): - - def __init__(self, connection): - #see above - if getattr(self, 'module', None) == None: - try: - from pysqlite2 import dbapi2 as sqlite - except ImportError: - import sqlite - self.module = sqlite - super(SQLiteAdapter, self).__init__(connection) - self.supportTransactions = True Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/connection.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/connection.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/connection.py Wed May 10 12:48:30 2006 @@ -10,26 +10,12 @@ """ Connection management. -This module defines the connection descriptor used as the connection in a -a sqlos SQLObject. This is responsible for getting the Zope connection and -adapting it to look like a SQLObject connection. - -Connections are cached as experience has shown that all the utility and -adapter utilities have a significant effect on speed. - $Id: factory.py 5216 2004-06-21 18:33:07Z dreamcatcher $ """ __metaclass__ = type -import warnings - -from zope.component import ComponentLookupError -import zope.component -from zope.app.rdb.interfaces import IZopeDatabaseAdapter from zope.thread import local -from sqlos.interfaces import IZopeSQLConnection, IConnectionName - class ConnectionCache(local): """A per thread cache for adapted connections.""" @@ -72,43 +58,3 @@ True """ conn_cache.clear() - - -class SQLObjectWarning(UserWarning): - pass - - -class ConnectionDescriptor: - - def __init__(self, name=None): - self.name = name - - def __get__(self, inst, cls=None): - # get and cache the connection name - name = self.name - if name is None: - try: - ut = zope.component.getUtility(IConnectionName) - except ComponentLookupError: - return self - if ut is None: - warnings.warn("Couldn't find ISQLConnectionName utility. " - "Please verify your setup.", - SQLObjectWarning, 2) - return - name = ut.name - # try get the connection from the cache, or make a new one - conn = conn_cache.queryConnection(name) - if conn is None: - zda = zope.component.getUtility(IZopeDatabaseAdapter, name) - try: - conn = IZopeSQLConnection(zda()) - except ComponentLookupError: - return self - conn_cache.setConnection(name, conn) - return conn - - def __set__(self, inst, value): - # Ignore, so we don't get overriden. - # We always use the connections from the IZopeDatabaseAdapter utility. - pass Added: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces.py ============================================================================== --- (empty file) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces.py Wed May 10 12:48:30 2006 @@ -0,0 +1,80 @@ +############################################################################## +# +# Copyright (c) 2004 Enfold Systems LLC. All rights reserved. +# +# This software is distributed under the terms of the Zope Public +# License (ZPL) v2.1. See COPYING.txt for more information. +# +############################################################################## +""" +$Id: adapter.py 5212 2004-06-21 18:09:05Z philikon $ +""" + +from zope.schema import TextLine +from zope.interface import Interface, Attribute +from zope.interface import Attribute +from zope.app.container.constraints import ItemTypePrecondition +from zope.app.annotation.interfaces import IAttributeAnnotatable +from zope.app.container.interfaces import IContainerNamesContainer +from zope.app.container.interfaces import IReadContainer, IContainer + +class ISQLObjectReadContainer(IReadContainer, IAttributeAnnotatable): + """ An SQLObject Container """ + + +class ISQLObjectContainer(IContainer, IContainerNamesContainer, + IAttributeAnnotatable): + """ An SQLObject Container """ + + def __setitem__(name, obj): + """Add a new object""" + + __setitem__.precondition = ItemTypePrecondition() + + +class IIsolatedSQLContainer(ISQLObjectContainer): + # TODO Attribute -> zope.schema.* - jinty + container_id = Attribute("The id of the containers, this is a filter on the" + "database table.") + + +class IConnectionName(Interface): + """A marker interface for providing a connection name""" + + name = TextLine( + title=u"Connection Name", + required=True + ) + + +class IISQLObject(IReadSQLObjectClass, IWriteSQLObjectClass): + """Class methods for SQLObject classes.""" + + +class IISQLObjectIsolated(IISQLObject): + """Support for using this class in isolated containers. + + This interface is necessary to move the SQL query logic to the SQLOS class + as it can be implemented in various ways in the class. + """ + + def countByDomain(domain): + """Return the number of objects which are in the domain.""" + + def selectByDomain(domain): + """Returns an iterator of objects in the domain. + + similar to select() + """ + + +class ISQLObject(Interface): + """Marker interface for SQLObjects. + + Hopefully one day this will be a real interface in SQLObject. + """ + + +class ISQLObjectIsolated(ISQLObject): + + domains = Attribute("A _tuple_ of containers_ids which contain this object") Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/zsqlobject.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/zsqlobject.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/zsqlobject.py Wed May 10 12:48:30 2006 @@ -24,64 +24,3 @@ >>> syncUpdateAll() """ _transaction.dirty_object_registry.syncUpdateAll() - - -class SQLOS(SQLObject): - """Subclass SQLObject to enable ``lazy updates`` by default, - as well as adding knowledge to register ``dirty`` objects - with SQLObjectTransactionManager so they get sync'd on transaction - boundaries. - - First, make a test data base: - - >>> from sqlos import testing - >>> testdb = testing.TestDB([SQLOS]) - - Test the interface: - - >>> s = SQLOS() - >>> from zope.interface.verify import verifyObject - >>> verifyObject(ISQLObject, s) - True - - And finally call tearDown and cleanup: - - >>> testdb.tearDown() - """ - implements(ISQLObject) - _connection = ConnectionDescriptor() - - class sqlmeta: - lazyUpdate = True - - def _set_dirty(self, value): - if value: - _transaction.dirty_object_registry.register(self) - self._dirty = value - - def _get_dirty(self): - return self._dirty - - dirty = property(_get_dirty, _set_dirty) - - def get(self, id, connection=None, selectResults=None): - # While interacting with zope, we may end up having - # objects in the cache that have a __parent__ set. - # This may be confusing when expect to get a object - # which has no __parent__ and thats not what you get. - val = super(SQLOS, self).get(id, connection=connection, - selectResults=selectResults) - if getattr(val, '__parent__', None) is not None: - val.__parent__ = None - val.__name__ = None - return val - get = classmethod(get) - - def __repr__(self): - return '<%s at 0x%x>' % (self.__class__.__name__, id(self)) - - def setConnection(self, connection): - if connection is not None: - self._connection = connection - - setConnection = classmethod(setConnection) From jinty at codespeak.net Wed May 10 12:57:16 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Wed May 10 12:57:17 2006 Subject: [z3-checkins] r27041 - z3/sqlos/branch/jinty-sqlobject2 Message-ID: <20060510105716.CE171100BB@code0.codespeak.net> Author: jinty Date: Wed May 10 12:57:15 2006 New Revision: 27041 Modified: z3/sqlos/branch/jinty-sqlobject2/setup.py Log: Update dependencies. Modified: z3/sqlos/branch/jinty-sqlobject2/setup.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/setup.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/setup.py Wed May 10 12:57:15 2006 @@ -19,6 +19,6 @@ zip_safe=False, include_package_data=True, install_requires = [ - 'SQLObject>=0.7', + 'SQLObject2', ] # XXX - what else? at least zope, let the users find out;) ) From jinty at codespeak.net Wed May 10 12:58:14 2006 From: jinty at codespeak.net (jinty@codespeak.net) Date: Wed May 10 12:58:16 2006 Subject: [z3-checkins] r27042 - z3/sqlos/branch/jinty-sqlobject2/src/sqlos Message-ID: <20060510105814.81A64100BD@code0.codespeak.net> Author: jinty Date: Wed May 10 12:58:12 2006 New Revision: 27042 Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces.py Log: Update dependencies. Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces.py Wed May 10 12:58:12 2006 @@ -47,7 +47,7 @@ ) -class IISQLObject(IReadSQLObjectClass, IWriteSQLObjectClass): +class IISQLObject(Interface): """Class methods for SQLObject classes.""" From reebalazs at codespeak.net Wed May 10 20:55:58 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Wed May 10 20:56:00 2006 Subject: [z3-checkins] r27052 - z3/jsonserver/branch/merge/concatresource/compression/thirdparty Message-ID: <20060510185558.CCB3A10087@code0.codespeak.net> Author: reebalazs Date: Wed May 10 20:55:57 2006 New Revision: 27052 Modified: z3/jsonserver/branch/merge/concatresource/compression/thirdparty/LICENSE z3/jsonserver/branch/merge/concatresource/compression/thirdparty/packer.py Log: Change license of packer.py Modified: z3/jsonserver/branch/merge/concatresource/compression/thirdparty/LICENSE ============================================================================== --- z3/jsonserver/branch/merge/concatresource/compression/thirdparty/LICENSE (original) +++ z3/jsonserver/branch/merge/concatresource/compression/thirdparty/LICENSE Wed May 10 20:55:57 2006 @@ -1,8 +1,25 @@ -packer.py is originally licensed under GNU GPL +packer.py is released under the MIT license. + +# packer.py +# +# Copyright (c) 2006 Florian Schulze +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. -# ------------------------------------------------------------------------------ -# used with permission by Florian Schulze, -# originally from -# https://svn.plone.org/svn/plone/ResourceRegistries/trunk/tools/packer.py -# ------------------------------------------------------------------------------ Modified: z3/jsonserver/branch/merge/concatresource/compression/thirdparty/packer.py ============================================================================== --- z3/jsonserver/branch/merge/concatresource/compression/thirdparty/packer.py (original) +++ z3/jsonserver/branch/merge/concatresource/compression/thirdparty/packer.py Wed May 10 20:55:57 2006 @@ -1,12 +1,29 @@ - -# ------------------------------------------------------------------------------ -# used with permission by Florian Schulze, -# originally from -# https://svn.plone.org/svn/plone/ResourceRegistries/trunk/tools/packer.py -# ------------------------------------------------------------------------------ +# +# packer.py +# +# Copyright (c) 2006 Florian Schulze +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. import re + class KeywordMapper: def __init__(self, regexp, encoder): if isinstance(regexp, (str, unicode)): From jwashin at codespeak.net Thu May 11 13:48:10 2006 From: jwashin at codespeak.net (jwashin@codespeak.net) Date: Thu May 11 13:48:12 2006 Subject: [z3-checkins] r27069 - in z3/jsonserver/trunk: . tests Message-ID: <20060511114810.649131007B@code0.codespeak.net> Author: jwashin Date: Thu May 11 13:48:07 2006 New Revision: 27069 Modified: z3/jsonserver/trunk/CHANGES.txt z3/jsonserver/trunk/VERSION.txt z3/jsonserver/trunk/jsoncomponent.py z3/jsonserver/trunk/jsonrpc.py z3/jsonserver/trunk/metaconfigure.py z3/jsonserver/trunk/tests/test_jsonrpcrequest.py Log: adjusted a few deprecated imports. preliminary support for json-rpc 1.1 Modified: z3/jsonserver/trunk/CHANGES.txt ============================================================================== --- z3/jsonserver/trunk/CHANGES.txt (original) +++ z3/jsonserver/trunk/CHANGES.txt Thu May 11 13:48:07 2006 @@ -1,17 +1,20 @@ #CHANGES.txt -20051202 a bit of backward-compatibility with five: - ++resource++ notation for the javascript. updated to the available +20051202 a bit of backward-compatibility with five: + ++resource++ notation for the javascript. updated to the available jsolait (2005-11-15.small) -20051125 some work toward making json requests better zope citizens. +20051125 some work toward making json requests better zope citizens. Some work toward keyword parameter support. -Some work toward making more information available in request: now -provides IBrowserApplicationRequest. This is experimental. Let me +Some work toward making more information available in request: now +provides IBrowserApplicationRequest. This is experimental. Let me know what you think. 20050921 Using the next beta of jsolait (20050914). The init file is now - jsolait.js instead of init.js. jsolait installer adds init.js as a copy of jsolait.js - for backwards compatibility. We are now using the 3.1 ResourceDirectory, - so the jsolait file structure does not need to be flattened. Upgrade to this - version using the installer is optional. + jsolait.js instead of init.js. jsolait installer adds init.js as a copy of + jsolait.js for backwards compatibility. We are now using the 3.1 + ResourceDirectory, so the jsolait file structure does not need to be flattened. + Upgrade to this version of jsolait using the installer is optional. + +20060511 Removed gzip support, since that can be done more elegantly by other + means. Preliminary support for json-rpc 1.1. \ No newline at end of file Modified: z3/jsonserver/trunk/VERSION.txt ============================================================================== --- z3/jsonserver/trunk/VERSION.txt (original) +++ z3/jsonserver/trunk/VERSION.txt Thu May 11 13:48:07 2006 @@ -1 +1 @@ -jsonserver 3.2.2 svn +jsonserver 3.3.0 svn Modified: z3/jsonserver/trunk/jsoncomponent.py ============================================================================== --- z3/jsonserver/trunk/jsoncomponent.py (original) +++ z3/jsonserver/trunk/jsoncomponent.py Thu May 11 13:48:07 2006 @@ -17,6 +17,7 @@ # jwashin 2005-07-27 # 2005-10-09 updated to properly? handle unicode on the boundary # 2005-09-08 updated for modularity and IResult +# 2006-05-11 allowed encoding param for reader import minjson as json from interfaces import IJSONReader, IJSONWriter @@ -26,14 +27,14 @@ class JSONReader(object): """component implementing JSON reading""" implements(IJSONReader) - - def read(self,aString, encoding='utf-8'): + + def read(self,aString,encoding=None): return json.read(aString,encoding) class JSONWriter(object): """component implementing JSON writing""" implements(IJSONWriter) - + def write(self,anObject): return json.write(anObject) Modified: z3/jsonserver/trunk/jsonrpc.py ============================================================================== --- z3/jsonserver/trunk/jsonrpc.py (original) +++ z3/jsonserver/trunk/jsonrpc.py Thu May 11 13:48:07 2006 @@ -20,7 +20,7 @@ #2005-09-08 updated to work with the new IResult idea (wsgi) #2005-10-09 unicode handling update #2006-03-09 enabled gzip compression for large responses -#2006-04-27 updated to sync with z3 trunk changes jmw +#2006-05-10 removed gzip compression and (prematurely) enabled json-rpc 1.1 jmw __docformat__ = 'restructuredtext' @@ -29,23 +29,18 @@ IJSONRPCRequest, IJSONReader, IJSONWriter from zope.interface import implements #from zope.publisher.http import IResult -try: - from zope.location.location import Location -except ImportError: - #deprecate this for 3.5 - from zope.app.location.location import Location +from zope.location.location import Location from zope.publisher.http import HTTPRequest, HTTPResponse, \ getCharsetUsingRequest, DirectResult from zope.publisher.browser import BrowserRequest from zope.security.proxy import isinstance +from zope.publisher.interfaces.browser import IBrowserRequest +from zope.publisher.interfaces.browser import IBrowserApplicationRequest +from zope.component import getUtility try: from cStringIO import StringIO except ImportError: from StringIO import StringIO -from zope.publisher.interfaces.browser import IBrowserRequest -from zope.publisher.interfaces.browser import IBrowserApplicationRequest -from zope.component import getUtility -import gzip import traceback import logging @@ -74,6 +69,9 @@ def __call__(self): return self.__pub +def intsort(item): + return int(item[0]) + class JSONRPCRequest(BrowserRequest): """a JSON-RPC Request modeled after zope.publisher.xmlrpc.XMLRPCRequest @@ -106,9 +104,6 @@ input = ''.join(input) #make it unicode; we are at the boundary input = self._decode(input) - #encoding = getCharsetUsingRequest(self) - #if not isinstance(input,unicode): - # input = input.decode(encoding) data = json.read(input) if writeProfileData: infile = 'profiledata.js' @@ -121,69 +116,57 @@ # failure unless we split on '.' Why? function = functionstr.split('.') self.jsonID = data['id'] - args = list(data['params']) - # now, look for keyword parameters - kwargs = None - notPositional = [] - for k in args: - if isinstance(k,dict): - if k.has_key(keyword_key): - if isinstance(k[keyword_key],dict): - j = k[keyword_key] - kwargs= j - notPositional.append(k) - if notPositional: - for k in notPositional: - args.remove(k) - if kwargs: - for m in kwargs.keys(): - self.form[str(m)] = kwargs[m] + params = data['params'] + if isinstance(params,list): + args = params + # now, look for keyword parameters, the old way + kwargs = None + notPositional = [] + for k in args: + if isinstance(k,dict): + if k.has_key(keyword_key): + if isinstance(k[keyword_key],dict): + j = k[keyword_key] + kwargs= j + notPositional.append(k) + if notPositional: + for k in notPositional: + args.remove(k) + if kwargs: + for m in kwargs.keys(): + self.form[str(m)] = kwargs[m] + elif isinstance(params,dict): + #json-rpc 1.1 (to be proposed) + #get the numeric params for positional params + temp_positional = [] + for key in params: + if key.isdigit(): + temp_positional.append((key,params[key])) + temp_positional.sort(key=intsort) + args = [] + #make args from positional args and remove them from params + for item in temp_positional: + args.append(item[1]) + del params[item[0]] + #drop remaining named params into request.form + for named_param in params: + #named_param is unicode; python needs string for param names + self.form[str(named_param)] = params[named_param] + else: + raise TypeError, 'Unsupported type for JSON-RPC "params" (%s)' \ + % type(params) self._args = tuple(args) #make environment,cookies, etc., available to request.get() super(JSONRPCRequest,self).processInputs() self._environ['JSONRPC_MODE'] = True if function: self.setPathSuffix(function) - def traverse(self,object): return super(BrowserRequest,self).traverse(object) def __getitem__(self,key): return self.get(key) -# IResult has gone PRIVATE; for we now will send a bytestring and set -# charset. - -##class JSONResult(object): -## implements(IResult) -## def __init__(self,aString, encoding='utf-8'): -## #statements to help figure out Opera -## #encoding='utf-8' #yields oriental charset, unparseable -## #encoding='utf-16' #yields something that looks like the right code, -## # no trouble in gecko, but opera refuses to parse it -## #encoding = None is troublesome for gecko; only get '{' -## #encoding = 'iso-8859-1' -## try: -## s= aString.encode(encoding) -## except UnicodeEncodeError: -## s = aString -## self.body = [s] -## if encoding == 'utf-8': -## # don't need charset for utf-8; charset handling seems buggy on -## # some browsers, so best not to use unnecessarily -## self.headers = [('content-type', -## 'application/x-javascript'), -## ('content-length',str(len(s)))] -## else: -## self.headers = [('content-type', -## 'application/x-javascript;charset=%s' % encoding), -## ('content-length',str(len(s)))] -#### else: -#### self.body = [aString] -#### self.headers = [('content-type','application/x-javascript'), -#### ('content-length',str(len(aString)))] -## - class JSONRPCResponse(HTTPResponse): """JSON-RPC Response modeled after zope.publisher.xmlrpc.XMLRPCResponse @@ -222,31 +205,16 @@ super(JSONRPCResponse,self).setResult('') def _prepareResult(self,result): - #we've asked json to return unicode. result should be unicode - + #we've asked json to return unicode; result should be unicode encoding = getCharsetUsingRequest(self._request) or 'utf-8' + #at outgoing boundary; encode it. if isinstance(result,unicode): body = result.encode(encoding) charset = encoding else: #something's wrong. json did not return unicode. - raise AttributeError - - #let's gzip compress it if it's big. - #thanks to Alan Kennedy http://www.xhaus.com/alan/python/httpcomp.html - compress_type = self._request.getHeader('Accept-Encoding', []) - bodyLength = len(body) - if 'gzip' in compress_type and bodyLength > compressionTrigger: - #using cStringIO, but OK, because we have a byte string here - zbuf = StringIO() - zfile = gzip.GzipFile(mode='wb', fileobj=zbuf, - compresslevel=compressionLevel) - zfile.write(body) - zfile.close() - body = zbuf.getvalue() - #a = len(body) - #print "before %s after %s" % (bodyLength,a) - self.setHeader('content-encoding','gzip') + raise TypeError, "JSON did not return unicode (%s)" % type(result) + #we used to gzip compress here, but that should be decided elsewhere self.setHeader('content-type',"application/x-javascript;charset=%s" \ % charset) return body @@ -355,4 +323,3 @@ super(TestRequest, self).__init__( body_instream, _testEnv, response) - Modified: z3/jsonserver/trunk/metaconfigure.py ============================================================================== --- z3/jsonserver/trunk/metaconfigure.py (original) +++ z3/jsonserver/trunk/metaconfigure.py Thu May 11 13:48:07 2006 @@ -17,7 +17,6 @@ like zope.app.publisher.xmlrpc.metaconfigure -Updated 2006-04-27 to sync with zope3 trunk jmw updated 2005-12-03 Roger Ineichen jwashin 2005-06-06 """ @@ -28,7 +27,7 @@ from interfaces import IJSONRPCRequest from zope.component.interface import provideInterface -from zope.component.zcml import handler +from zope.app.component.metaconfigure import handler from jsonrpc import MethodPublisher def view(_context, for_=None, interface=None, methods=None, @@ -58,7 +57,8 @@ # Make sure that the class inherits MethodPublisher, so that the views # have a location if class_ is None: - class_ = original_class = MethodPublisher + class_ = MethodPublisher + original_class = class_ else: original_class = class_ class_ = type(class_.__name__, (class_, MethodPublisher), {}) @@ -83,8 +83,8 @@ _context.action( discriminator = ('view', for_, name, IJSONRPCRequest), callable = handler, - args = ('registerAdapter', - class_, (for_, IJSONRPCRequest), Interface, name, + args = ('provideAdapter', + (for_, IJSONRPCRequest), Interface, name, class_, _context.info) ) else: @@ -101,8 +101,8 @@ _context.action( discriminator = ('view', for_, name, IJSONRPCRequest), callable = handler, - args = ('registerAdapter', - new_class, (for_, IJSONRPCRequest), Interface, name, + args = ('provideAdapter', + (for_, IJSONRPCRequest), Interface, name, new_class, _context.info) ) Modified: z3/jsonserver/trunk/tests/test_jsonrpcrequest.py ============================================================================== --- z3/jsonserver/trunk/tests/test_jsonrpcrequest.py (original) +++ z3/jsonserver/trunk/tests/test_jsonrpcrequest.py Thu May 11 13:48:07 2006 @@ -1,6 +1,6 @@ ############################################################################## # -# Copyright (c) 2001 - 2005 Zope Corporation and Contributors. +# Copyright (c) 2001 - 2005 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, @@ -14,6 +14,8 @@ """JSON-RPC Request Tests modified from zope/publisher/tests/test_xmlrpcrequest.py jwashin 2005-06-06 """ +#2006-05-10 updated to test json-rpc1.1 jmw + import unittest from StringIO import StringIO @@ -55,6 +57,17 @@ self.body = '{"id":"httpReq","method":"keyworded","params":[1,{"pythonKwMaRkEr":{"kw1":"aaa"}}]}' self.headers = [] +class Param1_1SpecTestCall1: + def __init__(self): + self.body = '{"id":"httpReq","method":"keyworded","params":{"1":1,"kw1":"aaa"}}' + self.headers = [] + +class Param1_1SpecTestCall2: + def __init__(self): + self.body = '{"id":"httpReq","method":"action1_1","params":{"1":1,"kw1":"aaa"}}' + self.headers = [] + + class JSONRPCTests(unittest.TestCase): """The only thing different to HTTP is the input processing; so there is no need to redo all the HTTP tests again. @@ -92,14 +105,18 @@ class View(object): - def action(self, a): + def action(self, a, kw1=None): return "Parameter[type: %s; value: %s" %( type(a).__name__, `a`) - + def keyworded(self, a, kw1="spam"): return "kw1: [type: %s; value: %s]" %( type(kw1).__name__, `kw1`) - + + def action1_1(self, a, kw1=None): + return "Parameter[type: %s; value: %s" %( + type(a).__name__, `a`) + class Item2(object): view = View() @@ -135,14 +152,28 @@ action = req.traverse(self.app) self.failUnlessEqual(action(*req._args), "Parameter[type: int; value: 1") - + def testKeyword(self): req = self._createRequest({}, ParamTestCall()) req.processInputs() action = req.traverse(self.app) self.failUnlessEqual(action(*req._args, **req.form), "kw1: [type: unicode; value: u'aaa']") - + + def test1_1spec_kw(self): + req = self._createRequest({}, Param1_1SpecTestCall1()) + req.processInputs() + action = req.traverse(self.app) + self.failUnlessEqual(action(*req._args, **req.form), + "kw1: [type: unicode; value: u'aaa']") + + def test1_1spec2_p(self): + req = self._createRequest({}, Param1_1SpecTestCall2()) + req.processInputs() + action = req.traverse(self.app) + self.failUnlessEqual(action(*req._args, **req.form), + "Parameter[type: int; value: 1") + def testJSONRPCMode(self): req = self._createRequest({}, jsonrpc_call) req.processInputs() From jwashin at codespeak.net Thu May 11 14:12:12 2006 From: jwashin at codespeak.net (jwashin@codespeak.net) Date: Thu May 11 14:12:14 2006 Subject: [z3-checkins] r27071 - in z3/jsonserver/trunk: . tests Message-ID: <20060511121212.EA49710082@code0.codespeak.net> Author: jwashin Date: Thu May 11 14:12:10 2006 New Revision: 27071 Modified: z3/jsonserver/trunk/configure.zcml z3/jsonserver/trunk/tests/test_directives.py Log: resolved svn oops Modified: z3/jsonserver/trunk/configure.zcml ============================================================================== --- z3/jsonserver/trunk/configure.zcml (original) +++ z3/jsonserver/trunk/configure.zcml Thu May 11 14:12:10 2006 @@ -12,17 +12,17 @@ mimetypes="application/json-rpc" priority="25" /> - + - + - + - + - + - + - + - + /> + - + Modified: z3/jsonserver/trunk/tests/test_directives.py ============================================================================== --- z3/jsonserver/trunk/tests/test_directives.py (original) +++ z3/jsonserver/trunk/tests/test_directives.py Thu May 11 14:12:10 2006 @@ -23,8 +23,6 @@ from zope.app.testing.placelesssetup import PlacelessSetup from zope.security.proxy import ProxyFactory -#from zope.component.tests.request import Request - from jsonserver.interfaces import IJSONRPCRequest import jsonserver From reebalazs at codespeak.net Thu May 11 17:12:58 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Thu May 11 17:12:59 2006 Subject: [z3-checkins] r27082 - z3/jsonserver/branch/zope2_test Message-ID: <20060511151258.168F61007F@code0.codespeak.net> Author: reebalazs Date: Thu May 11 17:12:56 2006 New Revision: 27082 Modified: z3/jsonserver/branch/zope2_test/jsonrpc.py Log: Fix the last fix to work with Z 2.8 Modified: z3/jsonserver/branch/zope2_test/jsonrpc.py ============================================================================== --- z3/jsonserver/branch/zope2_test/jsonrpc.py (original) +++ z3/jsonserver/branch/zope2_test/jsonrpc.py Thu May 11 17:12:56 2006 @@ -24,7 +24,12 @@ from zope.interface import directlyProvides, directlyProvidedBy from interfaces import IJsonRequest from ZPublisher.HTTPRequest import HTTPRequest -from zope.app.publication.browser import setDefaultSkin + +try: + from zope.app.publication.browser import setDefaultSkin +except ImportError: + # 2.8. We don't need this hack. + setDefaultSkin = lambda self: None # this is used to identify incoming requests request_content_type = 'application/json-rpc' From jwashin at codespeak.net Thu May 11 17:30:43 2006 From: jwashin at codespeak.net (jwashin@codespeak.net) Date: Thu May 11 17:30:45 2006 Subject: [z3-checkins] r27083 - in z3/jsonserver/branch/merge: . tests Message-ID: <20060511153043.027E61007F@code0.codespeak.net> Author: jwashin Date: Thu May 11 17:30:39 2006 New Revision: 27083 Modified: z3/jsonserver/branch/merge/CHANGES.txt z3/jsonserver/branch/merge/VERSION.txt z3/jsonserver/branch/merge/configure.zcml z3/jsonserver/branch/merge/jsoncomponent.py z3/jsonserver/branch/merge/jsonrpc.py z3/jsonserver/branch/merge/metaconfigure.py z3/jsonserver/branch/merge/tests/test_directives.py z3/jsonserver/branch/merge/tests/test_httpfactory.py z3/jsonserver/branch/merge/tests/test_jsonrpcrequest.py Log: removed gzip. updated some deprecated imports. preliminary support for json-rpc 1.1 Modified: z3/jsonserver/branch/merge/CHANGES.txt ============================================================================== --- z3/jsonserver/branch/merge/CHANGES.txt (original) +++ z3/jsonserver/branch/merge/CHANGES.txt Thu May 11 17:30:39 2006 @@ -1,17 +1,20 @@ #CHANGES.txt -20051202 a bit of backward-compatibility with five: - ++resource++ notation for the javascript. updated to the available +20051202 a bit of backward-compatibility with five: + ++resource++ notation for the javascript. updated to the available jsolait (2005-11-15.small) -20051125 some work toward making json requests better zope citizens. +20051125 some work toward making json requests better zope citizens. Some work toward keyword parameter support. -Some work toward making more information available in request: now -provides IBrowserApplicationRequest. This is experimental. Let me +Some work toward making more information available in request: now +provides IBrowserApplicationRequest. This is experimental. Let me know what you think. 20050921 Using the next beta of jsolait (20050914). The init file is now - jsolait.js instead of init.js. jsolait installer adds init.js as a copy of jsolait.js - for backwards compatibility. We are now using the 3.1 ResourceDirectory, - so the jsolait file structure does not need to be flattened. Upgrade to this - version using the installer is optional. + jsolait.js instead of init.js. jsolait installer adds init.js as a copy of + jsolait.js for backwards compatibility. We are now using the 3.1 + ResourceDirectory, so the jsolait file structure does not need to be flattened. + Upgrade to this version of jsolait using the installer is optional. + +20060511 Removed gzip support, since that can be done more elegantly by other + means. Preliminary support for json-rpc 1.1. \ No newline at end of file Modified: z3/jsonserver/branch/merge/VERSION.txt ============================================================================== --- z3/jsonserver/branch/merge/VERSION.txt (original) +++ z3/jsonserver/branch/merge/VERSION.txt Thu May 11 17:30:39 2006 @@ -1 +1 @@ -jsonserver 3.2.2 svn +jsonserver 3.3.0 svn Modified: z3/jsonserver/branch/merge/configure.zcml ============================================================================== --- z3/jsonserver/branch/merge/configure.zcml (original) +++ z3/jsonserver/branch/merge/configure.zcml Thu May 11 17:30:39 2006 @@ -66,15 +66,15 @@ - + - + + /> - - - - - - - - Modified: z3/jsonserver/branch/merge/jsoncomponent.py ============================================================================== --- z3/jsonserver/branch/merge/jsoncomponent.py (original) +++ z3/jsonserver/branch/merge/jsoncomponent.py Thu May 11 17:30:39 2006 @@ -17,6 +17,7 @@ # jwashin 2005-07-27 # 2005-10-09 updated to properly? handle unicode on the boundary # 2005-09-08 updated for modularity and IResult +# 2006-05-11 allowed encoding param for reader import minjson as json from interfaces import IJSONReader, IJSONWriter @@ -26,14 +27,14 @@ class JSONReader(object): """component implementing JSON reading""" implements(IJSONReader) - - def read(self,aString, encoding='utf-8'): + + def read(self,aString,encoding=None): return json.read(aString,encoding) class JSONWriter(object): """component implementing JSON writing""" implements(IJSONWriter) - + def write(self,anObject): return json.write(anObject) Modified: z3/jsonserver/branch/merge/jsonrpc.py ============================================================================== --- z3/jsonserver/branch/merge/jsonrpc.py (original) +++ z3/jsonserver/branch/merge/jsonrpc.py Thu May 11 17:30:39 2006 @@ -20,6 +20,7 @@ #2005-09-08 updated to work with the new IResult idea (wsgi) #2005-10-09 unicode handling update #2006-03-09 enabled gzip compression for large responses +#2006-05-10 removed gzip compression and (prematurely) enabled json-rpc 1.1 jmw __docformat__ = 'restructuredtext' @@ -28,16 +29,18 @@ IJSONRPCRequest, IJSONReader, IJSONWriter from zope.interface import implements #from zope.publisher.http import IResult -from zope.app.location.location import Location +from zope.location.location import Location from zope.publisher.http import HTTPRequest, HTTPResponse, \ getCharsetUsingRequest, DirectResult from zope.publisher.browser import BrowserRequest from zope.security.proxy import isinstance -from cStringIO import StringIO from zope.publisher.interfaces.browser import IBrowserRequest from zope.publisher.interfaces.browser import IBrowserApplicationRequest from zope.component import getUtility -import gzip +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO import traceback import logging @@ -66,6 +69,9 @@ def __call__(self): return self.__pub +def intsort(item): + return int(item[0]) + class JSONRPCRequest(BrowserRequest): """a JSON-RPC Request modeled after zope.publisher.xmlrpc.XMLRPCRequest @@ -98,9 +104,6 @@ input = ''.join(input) #make it unicode; we are at the boundary input = self._decode(input) - #encoding = getCharsetUsingRequest(self) - #if not isinstance(input,unicode): - # input = input.decode(encoding) data = json.read(input) if writeProfileData: infile = 'profiledata.js' @@ -113,69 +116,57 @@ # failure unless we split on '.' Why? function = functionstr.split('.') self.jsonID = data['id'] - args = list(data['params']) - # now, look for keyword parameters - kwargs = None - notPositional = [] - for k in args: - if isinstance(k,dict): - if k.has_key(keyword_key): - if isinstance(k[keyword_key],dict): - j = k[keyword_key] - kwargs= j - notPositional.append(k) - if notPositional: - for k in notPositional: - args.remove(k) - if kwargs: - for m in kwargs.keys(): - self.form[str(m)] = kwargs[m] + params = data['params'] + if isinstance(params,list): + args = params + # now, look for keyword parameters, the old way + kwargs = None + notPositional = [] + for k in args: + if isinstance(k,dict): + if k.has_key(keyword_key): + if isinstance(k[keyword_key],dict): + j = k[keyword_key] + kwargs= j + notPositional.append(k) + if notPositional: + for k in notPositional: + args.remove(k) + if kwargs: + for m in kwargs.keys(): + self.form[str(m)] = kwargs[m] + elif isinstance(params,dict): + #json-rpc 1.1 (to be proposed) + #get the numeric params for positional params + temp_positional = [] + for key in params: + if key.isdigit(): + temp_positional.append((key,params[key])) + temp_positional.sort(key=intsort) + args = [] + #make args from positional args and remove them from params + for item in temp_positional: + args.append(item[1]) + del params[item[0]] + #drop remaining named params into request.form + for named_param in params: + #named_param is unicode; python needs string for param names + self.form[str(named_param)] = params[named_param] + else: + raise TypeError, 'Unsupported type for JSON-RPC "params" (%s)' \ + % type(params) self._args = tuple(args) #make environment,cookies, etc., available to request.get() super(JSONRPCRequest,self).processInputs() self._environ['JSONRPC_MODE'] = True if function: self.setPathSuffix(function) - def traverse(self,object): return super(BrowserRequest,self).traverse(object) def __getitem__(self,key): return self.get(key) -# IResult has gone PRIVATE; for we now will send a bytestring and set -# charset. - -##class JSONResult(object): -## implements(IResult) -## def __init__(self,aString, encoding='utf-8'): -## #statements to help figure out Opera -## #encoding='utf-8' #yields oriental charset, unparseable -## #encoding='utf-16' #yields something that looks like the right code, -## # no trouble in gecko, but opera refuses to parse it -## #encoding = None is troublesome for gecko; only get '{' -## #encoding = 'iso-8859-1' -## try: -## s= aString.encode(encoding) -## except UnicodeEncodeError: -## s = aString -## self.body = [s] -## if encoding == 'utf-8': -## # don't need charset for utf-8; charset handling seems buggy on -## # some browsers, so best not to use unnecessarily -## self.headers = [('content-type', -## 'application/x-javascript'), -## ('content-length',str(len(s)))] -## else: -## self.headers = [('content-type', -## 'application/x-javascript;charset=%s' % encoding), -## ('content-length',str(len(s)))] -#### else: -#### self.body = [aString] -#### self.headers = [('content-type','application/x-javascript'), -#### ('content-length',str(len(aString)))] -## - class JSONRPCResponse(HTTPResponse): """JSON-RPC Response modeled after zope.publisher.xmlrpc.XMLRPCResponse @@ -214,31 +205,16 @@ super(JSONRPCResponse,self).setResult('') def _prepareResult(self,result): - #we've asked json to return unicode. result should be unicode - + #we've asked json to return unicode; result should be unicode encoding = getCharsetUsingRequest(self._request) or 'utf-8' + #at outgoing boundary; encode it. if isinstance(result,unicode): body = result.encode(encoding) charset = encoding else: #something's wrong. json did not return unicode. - raise AttributeError - - #let's gzip compress it if it's big. - #thanks to Alan Kennedy http://www.xhaus.com/alan/python/httpcomp.html - compress_type = self._request.getHeader('Accept-Encoding',[]) - bodyLength = len(body) - if 'gzip' in compress_type and bodyLength > compressionTrigger: - #using cStringIO, but OK, because we have a byte string here - zbuf = StringIO() - zfile = gzip.GzipFile(mode='wb', fileobj=zbuf, - compresslevel=compressionLevel) - zfile.write(body) - zfile.close() - body = zbuf.getvalue() - #a = len(body) - #print "before %s after %s" % (bodyLength,a) - self.setHeader('content-encoding','gzip') + raise TypeError, "JSON did not return unicode (%s)" % type(result) + #we used to gzip compress here, but that should be decided elsewhere self.setHeader('content-type',"application/x-javascript;charset=%s" \ % charset) return body @@ -347,4 +323,3 @@ super(TestRequest, self).__init__( body_instream, _testEnv, response) - Modified: z3/jsonserver/branch/merge/metaconfigure.py ============================================================================== --- z3/jsonserver/branch/merge/metaconfigure.py (original) +++ z3/jsonserver/branch/merge/metaconfigure.py Thu May 11 17:30:39 2006 @@ -1,7 +1,7 @@ ############################################################################ ## # -# Copyright (c) 2001 - 2005 Zope Corporation and Contributors. +# Copyright (c) 2001 - 2005 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, @@ -26,7 +26,7 @@ from zope.configuration.exceptions import ConfigurationError from interfaces import IJSONRPCRequest -from zope.app.component.interface import provideInterface +from zope.component.interface import provideInterface from zope.app.component.metaconfigure import handler from jsonrpc import MethodPublisher Modified: z3/jsonserver/branch/merge/tests/test_directives.py ============================================================================== --- z3/jsonserver/branch/merge/tests/test_directives.py (original) +++ z3/jsonserver/branch/merge/tests/test_directives.py Thu May 11 17:30:39 2006 @@ -1,6 +1,6 @@ ############################################################################## # -# Copyright (c) 2001 - 2005 Zope Corporation and Contributors. +# Copyright (c) 2001 - 2005 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, @@ -19,12 +19,10 @@ from zope.configuration import xmlconfig from zope.configuration.exceptions import ConfigurationError -from zope.app.component.tests.views import IC, V1 +from zope.app.component.tests.views import IC, V1, Request from zope.app.testing.placelesssetup import PlacelessSetup from zope.security.proxy import ProxyFactory -from zope.component.tests.request import Request - from jsonserver.interfaces import IJSONRPCRequest import jsonserver Modified: z3/jsonserver/branch/merge/tests/test_httpfactory.py ============================================================================== --- z3/jsonserver/branch/merge/tests/test_httpfactory.py (original) +++ z3/jsonserver/branch/merge/tests/test_httpfactory.py Thu May 11 17:30:39 2006 @@ -1,6 +1,6 @@ ############################################################################## # -# Copyright (c) 2003 - 2005 Zope Corporation and Contributors. +# Copyright (c) 2003 - 2005 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, @@ -23,7 +23,7 @@ from zope.publisher.browser import BrowserRequest from zope.publisher.http import HTTPRequest from jsonserver.jsonrpc import JSONRPCRequest -from zope.component.tests.placelesssetup import PlacelessSetup +from zope.component.testing import PlacelessSetup from jsonserver.interfaces import IJSONRPCRequestFactory from zope.app.publication.httpfactory import HTTPPublicationRequestFactory from zope.app.publication.browser import BrowserPublication Modified: z3/jsonserver/branch/merge/tests/test_jsonrpcrequest.py ============================================================================== --- z3/jsonserver/branch/merge/tests/test_jsonrpcrequest.py (original) +++ z3/jsonserver/branch/merge/tests/test_jsonrpcrequest.py Thu May 11 17:30:39 2006 @@ -1,6 +1,6 @@ ############################################################################## # -# Copyright (c) 2001 - 2005 Zope Corporation and Contributors. +# Copyright (c) 2001 - 2005 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, @@ -14,6 +14,8 @@ """JSON-RPC Request Tests modified from zope/publisher/tests/test_xmlrpcrequest.py jwashin 2005-06-06 """ +#2006-05-10 updated to test json-rpc1.1 jmw + import unittest from StringIO import StringIO @@ -55,6 +57,17 @@ self.body = '{"id":"httpReq","method":"keyworded","params":[1,{"pythonKwMaRkEr":{"kw1":"aaa"}}]}' self.headers = [] +class Param1_1SpecTestCall1: + def __init__(self): + self.body = '{"id":"httpReq","method":"keyworded","params":{"1":1,"kw1":"aaa"}}' + self.headers = [] + +class Param1_1SpecTestCall2: + def __init__(self): + self.body = '{"id":"httpReq","method":"action1_1","params":{"1":1,"kw1":"aaa"}}' + self.headers = [] + + class JSONRPCTests(unittest.TestCase): """The only thing different to HTTP is the input processing; so there is no need to redo all the HTTP tests again. @@ -92,14 +105,18 @@ class View(object): - def action(self, a): + def action(self, a, kw1=None): return "Parameter[type: %s; value: %s" %( type(a).__name__, `a`) - + def keyworded(self, a, kw1="spam"): return "kw1: [type: %s; value: %s]" %( type(kw1).__name__, `kw1`) - + + def action1_1(self, a, kw1=None): + return "Parameter[type: %s; value: %s" %( + type(a).__name__, `a`) + class Item2(object): view = View() @@ -135,14 +152,28 @@ action = req.traverse(self.app) self.failUnlessEqual(action(*req._args), "Parameter[type: int; value: 1") - + def testKeyword(self): req = self._createRequest({}, ParamTestCall()) req.processInputs() action = req.traverse(self.app) self.failUnlessEqual(action(*req._args, **req.form), "kw1: [type: unicode; value: u'aaa']") - + + def test1_1spec_kw(self): + req = self._createRequest({}, Param1_1SpecTestCall1()) + req.processInputs() + action = req.traverse(self.app) + self.failUnlessEqual(action(*req._args, **req.form), + "kw1: [type: unicode; value: u'aaa']") + + def test1_1spec2_p(self): + req = self._createRequest({}, Param1_1SpecTestCall2()) + req.processInputs() + action = req.traverse(self.app) + self.failUnlessEqual(action(*req._args, **req.form), + "Parameter[type: int; value: 1") + def testJSONRPCMode(self): req = self._createRequest({}, jsonrpc_call) req.processInputs() From reebalazs at codespeak.net Thu May 11 17:35:39 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Thu May 11 17:35:40 2006 Subject: [z3-checkins] r27084 - z3/jsonserver/branch/merge/browser Message-ID: <20060511153539.B56BF10082@code0.codespeak.net> Author: reebalazs Date: Thu May 11 17:35:38 2006 New Revision: 27084 Modified: z3/jsonserver/branch/merge/browser/json.js Log: Implement JSON-RPC 1.1 Modified: z3/jsonserver/branch/merge/browser/json.js ============================================================================== --- z3/jsonserver/branch/merge/browser/json.js (original) +++ z3/jsonserver/branch/merge/browser/json.js Thu May 11 17:35:38 2006 @@ -123,6 +123,46 @@ var _dummyRequestManager = new _DummyRequestManager(); +function JSONSig(params, allowSupplement) { + // Params are those submitted to the rpc method + // Params can contain _JsonNamedWrapper and _JsonSupplement items + // they must be sorted out + // and finally the result is converted to the 1.1 marshall format + // that only needs to be jsonized after + this.supplementWrapper = null; + var args = new Array(); + for(var i=0;i= 1 && typeof(args[args.length-1]) == 'object' && ! args[args.length-1].toJSON) { + // we have named parms! + this.args = {}; + var kw = args[args.length-1]; + for (var key in kw) { + this.args[key] = kw[key]; + } + for (var i=0; i Author: reebalazs Date: Thu May 11 17:36:03 2006 New Revision: 27085 Modified: z3/jsonserver/branch/zope2_test/jsonrpc.py Log: Implement JSON-RPC 1.1 Modified: z3/jsonserver/branch/zope2_test/jsonrpc.py ============================================================================== --- z3/jsonserver/branch/zope2_test/jsonrpc.py (original) +++ z3/jsonserver/branch/zope2_test/jsonrpc.py Thu May 11 17:36:03 2006 @@ -78,19 +78,37 @@ # Separare positional keywords from args # this works if client emits {'jsonclass': ['zope.kw', kw]} args, kw = [], {} - for arg in params: - success = False - if isinstance(arg, dict) and 'jsonclass' in arg: - # json class hints - # TODO handle Date - pass - elif isinstance(arg, dict) and pythonkwmarker in arg: - # a keyword parm - kw.update(arg[pythonkwmarker]) - success = True - if not success: - # a normal positional parm - args.append(arg) + if isinstance(params, dict): + argcounter = [] + for key, value in params.iteritems(): + try: + index = int(key) + except ValueError: + # a key + kw[key] = value + else: + # an arg + argcounter.append((index, value)) + # now put together the args + argcounter.sort() + for i, (index, value) in enumerate(argcounter): + if i != index: + raise IndexError, "Bad order or arguments in JSON payload" + args.append(value) + else: + for arg in params: + success = False + if isinstance(arg, dict) and 'jsonclass' in arg: + # json class hints + # TODO handle Date + pass + elif isinstance(arg, dict) and pythonkwmarker in arg: + # a keyword parm + kw.update(arg[pythonkwmarker]) + success = True + if not success: + # a normal positional parm + args.append(arg) return jsonID, method, args, kw From jwashin at codespeak.net Thu May 11 18:31:06 2006 From: jwashin at codespeak.net (jwashin@codespeak.net) Date: Thu May 11 18:31:07 2006 Subject: [z3-checkins] r27088 - z3/jsonserver/branch/merge/concatresource Message-ID: <20060511163106.CDF2810082@code0.codespeak.net> Author: jwashin Date: Thu May 11 18:31:04 2006 New Revision: 27088 Added: z3/jsonserver/branch/merge/concatresource/concatresource-configure.zcml z3/jsonserver/branch/merge/concatresource/concatresource-meta.zcml Modified: z3/jsonserver/branch/merge/concatresource/__init__.py z3/jsonserver/branch/merge/concatresource/concatfileresource.py Log: conditional imports for z3 compatibility. files for etc/package-includes Modified: z3/jsonserver/branch/merge/concatresource/__init__.py ============================================================================== --- z3/jsonserver/branch/merge/concatresource/__init__.py (original) +++ z3/jsonserver/branch/merge/concatresource/__init__.py Thu May 11 18:31:04 2006 @@ -1,9 +1,11 @@ '''\ Product init ''' - # alias myself to Products, directly -import sys, Products -if not hasattr(Products, 'concatresource'): +try: + import sys, Products + if not hasattr(Products, 'concatresource'): # only 1st import is aliased. - Products.concatresource = sys.modules['Products.concatresource'] = sys.modules[globals()['__name__']] + Products.concatresource = sys.modules['Products.concatresource'] = sys.modules[globals()['__name__']] +except ImportError: + pass Modified: z3/jsonserver/branch/merge/concatresource/concatfileresource.py ============================================================================== --- z3/jsonserver/branch/merge/concatresource/concatfileresource.py (original) +++ z3/jsonserver/branch/merge/concatresource/concatfileresource.py Thu May 11 18:31:04 2006 @@ -9,7 +9,10 @@ from zope.interface import implements from interfaces import IContextFile # we are aliased to Products, hence the following absolute import -from Products.concatresource.interfaces import IConcatResourceAddon +try: + from Products.concatresource.interfaces import IConcatResourceAddon +except ImportError: + from interfaces import IConcatResourceAddon from fileresource import File from compression import compress import time @@ -18,7 +21,7 @@ class ConcatFiles(object): '''A resource that concatenates files and compresses the result - + It is also possible to extend the statically given list via a utility. ''' @@ -50,7 +53,7 @@ extend = registry.getAddonFiles() pathlist = self.pathlist_base + extend return pathlist - + def getFilesList(self): 'Gets the list of files' ## # XXX We have two choices: @@ -70,13 +73,13 @@ else: fileslist = self.fileslist return fileslist - + def getLastMod(self): # We take in consideration that the pathlist # itself could have changed too. - return max([f.getLastMod() for f in self.getFilesList()] + + return max([f.getLastMod() for f in self.getFilesList()] + [self.fileslist_changed]) - + def getContents(self): fileslist = self.getFilesList() assert fileslist, 'Must contain at least one resource.' Added: z3/jsonserver/branch/merge/concatresource/concatresource-configure.zcml ============================================================================== --- (empty file) +++ z3/jsonserver/branch/merge/concatresource/concatresource-configure.zcml Thu May 11 18:31:04 2006 @@ -0,0 +1 @@ + Added: z3/jsonserver/branch/merge/concatresource/concatresource-meta.zcml ============================================================================== --- (empty file) +++ z3/jsonserver/branch/merge/concatresource/concatresource-meta.zcml Thu May 11 18:31:04 2006 @@ -0,0 +1,2 @@ + + \ No newline at end of file From reebalazs at codespeak.net Fri May 12 09:36:13 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Fri May 12 09:36:15 2006 Subject: [z3-checkins] r27106 - z3/jsonserver/branch/merge/concatresource Message-ID: <20060512073613.B704F1009D@code0.codespeak.net> Author: reebalazs Date: Fri May 12 09:36:12 2006 New Revision: 27106 Modified: z3/jsonserver/branch/merge/concatresource/README Log: Release notes about brokenness with Zope 2.9.2 Modified: z3/jsonserver/branch/merge/concatresource/README ============================================================================== --- z3/jsonserver/branch/merge/concatresource/README (original) +++ z3/jsonserver/branch/merge/concatresource/README Fri May 12 09:36:12 2006 @@ -69,4 +69,14 @@ - Specifying "none" will leave your resource uncompressed. This can be useful for debugging. +Release notes +------------- + +In Zope 2.9.2 there is Five 1.3.3 included. This contains a but that +the resources will never be looked up from the +application root. + +To fix this, you need to update Five to version 1.3.5, or update Zope +to version 2.9.3 (not available of the time of writing this). + From reebalazs at codespeak.net Fri May 12 09:36:22 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Fri May 12 09:36:24 2006 Subject: [z3-checkins] r27107 - z3/jsonserver/branch/zope2_test Message-ID: <20060512073622.DE937100A5@code0.codespeak.net> Author: reebalazs Date: Fri May 12 09:36:21 2006 New Revision: 27107 Modified: z3/jsonserver/branch/zope2_test/README.txt Log: Release notes about brokenness with Zope 2.9.2 Modified: z3/jsonserver/branch/zope2_test/README.txt ============================================================================== --- z3/jsonserver/branch/zope2_test/README.txt (original) +++ z3/jsonserver/branch/zope2_test/README.txt Fri May 12 09:36:21 2006 @@ -163,7 +163,14 @@ **json:page** declarations will be callable from code and their macros will be visible from other templates. -TODO: ------ -gzip? +Release notes +------------- + +In Zope 2.9.2 there is Five 1.3.3 included. This contains a but that +the resources will never be looked up from the +application root. + +To fix this, you need to update Five to version 1.3.5, or update Zope +to version 2.9.3 (not available of the time of writing this). + From reebalazs at codespeak.net Fri May 12 11:17:11 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Fri May 12 11:17:12 2006 Subject: [z3-checkins] r27114 - z3/jsonserver/branch/merge/browser Message-ID: <20060512091711.71D7110093@code0.codespeak.net> Author: reebalazs Date: Fri May 12 11:17:10 2006 New Revision: 27114 Modified: z3/jsonserver/branch/merge/browser/json.js Log: Clean up instantiation of JSONMethod Modified: z3/jsonserver/branch/merge/browser/json.js ============================================================================== --- z3/jsonserver/branch/merge/browser/json.js (original) +++ z3/jsonserver/branch/merge/browser/json.js Fri May 12 11:17:10 2006 @@ -52,21 +52,6 @@ return new json.SupplementWrapper(data, id); } -// Direct method creation, by creating an implicit proxy -// if methodName == '' then the url is taken as full url -function makeJSONRPCMethod(url, methodName, callback, error, timeout, supplementData, - requestId, requestManager, user, pass) { - if (typeof(methodName) == 'undefined' || methodName == null || methodName == '') { - var pieces = url.split('/'); - methodName = pieces.pop(); - url = pieces.join('/'); - } - var proxy = new JSONRPC(url); - proxy.addMethod(methodName, callback, error, timeout, supplementData, - requestId, requestManager, user, pass); - return proxy[methodName]; -} - function JSONRPC(url) { this._url = url; this._methods = new Array(); @@ -79,21 +64,6 @@ } JSONRPC.prototype.addMethod = function(name, callback, errHandler, timeout, supplementData, requestId, requestManager) { - if (typeof(errHandler) == 'undefined') { - errHandler = null; - } - if (typeof(timeout) == 'undefined') { - timeout = null; - } - if (typeof(supplementData) == 'undefined') { - supplementData = null; - } - if (typeof(requestId) == 'undefined' || requestId == null) { - requestId = "jsonRequest"; - } - if (typeof(requestManager) == 'undefined' || requestManager == null) { - requestManager = _dummyRequestManager; - } var self = this; if(!self[name]){ var method = new JSONRPCMethod(this._url, name, callback, errHandler, timeout, supplementData, requestId, @@ -165,6 +135,28 @@ function JSONRPCMethod(url, methodName, callback, errHandler, timeout, supplementData, requestId, requestManager, user, pass) { + // Make it possible to call it with no methodName, and just an url. + // if methodName == null, it will be figured out from the url. + if (typeof(methodName) == 'undefined' || methodName == null || methodName == '') { + var pieces = url.split('/'); + methodName = pieces.pop(); + url = pieces.join('/'); + } + if (typeof(errHandler) == 'undefined') { + errHandler = null; + } + if (typeof(timeout) == 'undefined') { + timeout = null; + } + if (typeof(supplementData) == 'undefined') { + supplementData = null; + } + if (typeof(requestId) == 'undefined' || requestId == null) { + requestId = "jsonRequest"; + } + if (typeof(requestManager) == 'undefined' || requestManager == null) { + requestManager = _dummyRequestManager; + } this.methodName = methodName; this.callback = callback; this.errHandler = errHandler; From reebalazs at codespeak.net Fri May 12 19:00:53 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Fri May 12 19:00:54 2006 Subject: [z3-checkins] r27146 - in z3/jsonserver/branch: merge/minjson zope2_test/minjson Message-ID: <20060512170053.A0567100BA@code0.codespeak.net> Author: reebalazs Date: Fri May 12 19:00:51 2006 New Revision: 27146 Added: z3/jsonserver/branch/merge/minjson/ - copied from r27145, z3/jsonserver/branch/zope2_test/minjson/ Removed: z3/jsonserver/branch/zope2_test/minjson/ Log: Relocate minjson to the merge branch From reebalazs at codespeak.net Fri May 12 19:02:03 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Fri May 12 19:02:04 2006 Subject: [z3-checkins] r27147 - z3/jsonserver/branch/zope2_test Message-ID: <20060512170203.1FAFF100BA@code0.codespeak.net> Author: reebalazs Date: Fri May 12 19:02:01 2006 New Revision: 27147 Modified: z3/jsonserver/branch/zope2_test/ (props changed) z3/jsonserver/branch/zope2_test/EXTERNALS.TXT Log: link to minjson Modified: z3/jsonserver/branch/zope2_test/EXTERNALS.TXT ============================================================================== --- z3/jsonserver/branch/zope2_test/EXTERNALS.TXT (original) +++ z3/jsonserver/branch/zope2_test/EXTERNALS.TXT Fri May 12 19:02:01 2006 @@ -8,4 +8,5 @@ browser http://codespeak.net/svn/z3/jsonserver/branch/merge/browser concatresource http://codespeak.net/svn/z3/jsonserver/branch/merge/concatresource utils http://codespeak.net/svn/z3/jsonserver/branch/merge/utils +minjson http://codespeak.net/svn/z3/jsonserver/branch/merge/minjson From reebalazs at codespeak.net Fri May 12 19:04:20 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Fri May 12 19:04:22 2006 Subject: [z3-checkins] r27148 - z3/jsonserver/branch/merge Message-ID: <20060512170420.B25CD100BA@code0.codespeak.net> Author: reebalazs Date: Fri May 12 19:04:19 2006 New Revision: 27148 Removed: z3/jsonserver/branch/merge/minjson.py Modified: z3/jsonserver/branch/merge/configure.zcml Log: Use new minjson Modified: z3/jsonserver/branch/merge/configure.zcml ============================================================================== --- z3/jsonserver/branch/merge/configure.zcml (original) +++ z3/jsonserver/branch/merge/configure.zcml Fri May 12 19:04:19 2006 @@ -5,6 +5,8 @@ i18n_domain="zope" > + + Author: reebalazs Date: Fri May 12 19:13:40 2006 New Revision: 27149 Added: z3/jsonserver/branch/merge/z2_compatibility/ Log: add dir From reebalazs at codespeak.net Fri May 12 19:14:56 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Fri May 12 19:14:57 2006 Subject: [z3-checkins] r27150 - z3/jsonserver/branch/merge/z2_compatibility Message-ID: <20060512171456.8CCE3100BA@code0.codespeak.net> Author: reebalazs Date: Fri May 12 19:14:54 2006 New Revision: 27150 Added: z3/jsonserver/branch/merge/z2_compatibility/jsonrpc.py - copied unchanged from r27149, z3/jsonserver/branch/zope2_test/jsonrpc.py Log: Copy this to the merge branch From reebalazs at codespeak.net Sat May 13 10:55:36 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Sat May 13 10:55:46 2006 Subject: [z3-checkins] r27159 - z3/jsonserver/branch/merge/z2_compatibility Message-ID: <20060513085536.8F338100AA@code0.codespeak.net> Author: reebalazs Date: Sat May 13 10:55:31 2006 New Revision: 27159 Added: z3/jsonserver/branch/merge/z2_compatibility/configure.zcml - copied unchanged from r27158, z3/jsonserver/branch/zope2_test/configure.zcml Log: Relocation From reebalazs at codespeak.net Sat May 13 10:55:50 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Sat May 13 10:55:52 2006 Subject: [z3-checkins] r27160 - z3/jsonserver/branch/merge/z2_compatibility Message-ID: <20060513085550.4323D100B6@code0.codespeak.net> Author: reebalazs Date: Sat May 13 10:55:47 2006 New Revision: 27160 Added: z3/jsonserver/branch/merge/z2_compatibility/meta.zcml - copied unchanged from r27159, z3/jsonserver/branch/zope2_test/meta.zcml Log: Relocation From reebalazs at codespeak.net Sat May 13 10:56:03 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Sat May 13 10:56:05 2006 Subject: [z3-checkins] r27161 - z3/jsonserver/branch/merge/z2_compatibility Message-ID: <20060513085603.E5488100B2@code0.codespeak.net> Author: reebalazs Date: Sat May 13 10:56:01 2006 New Revision: 27161 Added: z3/jsonserver/branch/merge/z2_compatibility/browserconfigure.py - copied unchanged from r27160, z3/jsonserver/branch/zope2_test/browserconfigure.py Log: Relocation From reebalazs at codespeak.net Sat May 13 10:57:55 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Sat May 13 10:57:56 2006 Subject: [z3-checkins] r27162 - z3/jsonserver/branch/merge/z2_compatibility Message-ID: <20060513085755.19F63100AA@code0.codespeak.net> Author: reebalazs Date: Sat May 13 10:57:53 2006 New Revision: 27162 Added: z3/jsonserver/branch/merge/z2_compatibility/interfaces.py - copied unchanged from r27161, z3/jsonserver/branch/zope2_test/interfaces.py Log: Relocation From reebalazs at codespeak.net Sat May 13 15:42:36 2006 From: reebalazs at codespeak.net (reebalazs@codespeak.net) Date: Sat May 13 15:42:37 2006 Subject: [z3-checkins] r27172 - in z3/jsonserver/branch/merge: . minjson z2_compatibility Message-ID: <20060513134236.33A8F100AA@code0.codespeak.net> Author: reebalazs Date: Sat May 13 15:42:32 2006 New Revision: 27172 Added: z3/jsonserver/branch/merge/__compat__.py z3/jsonserver/branch/merge/z2_compatibility/__init__.py Modified: z3/jsonserver/branch/merge/__init__.py z3/jsonserver/branch/merge/configure.zcml z3/jsonserver/branch/merge/jsonrpc.py z3/jsonserver/branch/merge/meta.zcml z3/jsonserver/branch/merge/metaconfigure.py z3/jsonserver/branch/merge/minjson/configure.zcml z3/jsonserver/branch/merge/z2_compatibility/configure.zcml z3/jsonserver/branch/merge/z2_compatibility/jsonrpc.py z3/jsonserver/branch/merge/z2_compatibility/meta.zcml Log: Merge progress. Not yet done. Added: z3/jsonserver/branch/merge/__compat__.py ============================================================================== --- (empty file) +++ z3/jsonserver/branch/merge/__compat__.py Sat May 13 15:42:32 2006 @@ -0,0 +1,74 @@ +'''\ +Compatibility configuration switches + +This is a transitional solution to attack the problem +of quickly changing Zope3 and Five apis. + +Import checks are done centrally from here. +The point is that compatibility imports should fail here, +if anything goes wrong. Components should only check +the switches set from here. + +Supported versions: +------------------- + +Zope 2.9, 2.10 +Zope 3.2, 3.3 + +Compatibility matrix +-------------------- + +The following table shows which Five version can and should be used +with which Zope 2 and Zope 3 versions. + +. Zope 2.8 Zope 2.9 Zope 2.10 +. Zope X3 3.0 Zope 3.2 Zope 3.3 +Five 1.0 included +Five 1.2 X +Five 1.3 included +Five 1.4 X +Five trunk included + +''' + +__all__ = ('__compat__', ) + +class DictLike(object): + pass + +__compat__ = DictLike() + +try: + import zope.component.interface + import zope.component.location + __compat__.zope_pre_3_3 = False +except ImportError: + # The only supported pre_3_3 version is 3.2 + import zope.app.component.interface + import zope.app.location + __compat__.zope_pre_3_3 = True + +try: + import Products.Five +except ImportError: + __compat__.five = False +else: + __compat__.five = True + try: + # Zope 2.8 / Five 1.0.2 + from Products.Five.resource import Resource + __compat__.five_pre_1_3 = True + except ImportError: + # Zope 2.9 / Five 1.3 + from Products.Five.browser.resource import Resource + __compat__.five_pre_1_3 = False + +# Unsupported versions. +if __compat__.five and __compat__.five_pre_1_3: + raise Exception, 'Zope 2.8 or prior versions (Five 1.2 or prior versions) are unsupported, please upgrade!' + +# If running on zope3, make a fake installed product. We need this because +# there is no negation of zcml:condition="installed Zope2". +import sys +if not __compat__.five: + sys.modules['not_Zope2'] = sys.modules[globals()['__name__']] Modified: z3/jsonserver/branch/merge/__init__.py ============================================================================== --- z3/jsonserver/branch/merge/__init__.py (original) +++ z3/jsonserver/branch/merge/__init__.py Sat May 13 15:42:32 2006 @@ -1 +1,14 @@ #python package + +import __compat__ + +# Debugging +#from AccessControl import allow_module +#allow_module('pdb') + +# This is only executed on Zope 2 and ignored of Z3. +def initialize(context): + from z2_compatibility import jsonrpc + + # patches the zpublisher to provide json-rpc + jsonrpc.patch_HTTPRequest() Modified: z3/jsonserver/branch/merge/configure.zcml ============================================================================== --- z3/jsonserver/branch/merge/configure.zcml (original) +++ z3/jsonserver/branch/merge/configure.zcml Sat May 13 15:42:32 2006 @@ -2,11 +2,22 @@ xmlns:jsonrpc="http://namespaces.zope.org/jsonrpc" xmlns:browser="http://namespaces.zope.org/browser" xmlns:help="http://namespaces.zope.org/help" + xmlns:zcml="http://namespaces.zope.org/zcml" i18n_domain="zope" > + + + + + + + + + + + + - + + Modified: z3/jsonserver/branch/merge/jsonrpc.py ============================================================================== --- z3/jsonserver/branch/merge/jsonrpc.py (original) +++ z3/jsonserver/branch/merge/jsonrpc.py Sat May 13 15:42:32 2006 @@ -24,12 +24,17 @@ __docformat__ = 'restructuredtext' +from __compat__ import __compat__ + from zope.app.publication.http import BaseHTTPPublication from interfaces import IMethodPublisher, IJSONRPCView, IJSONRPCPublisher,\ IJSONRPCRequest, IJSONReader, IJSONWriter from zope.interface import implements #from zope.publisher.http import IResult -from zope.location.location import Location +if __compat__.zope_pre_3_3: + from zope.app.location import Location +else: + from zope.location.location import Location from zope.publisher.http import HTTPRequest, HTTPResponse, \ getCharsetUsingRequest, DirectResult from zope.publisher.browser import BrowserRequest Modified: z3/jsonserver/branch/merge/meta.zcml ============================================================================== --- z3/jsonserver/branch/merge/meta.zcml (original) +++ z3/jsonserver/branch/merge/meta.zcml Sat May 13 15:42:32 2006 @@ -1,5 +1,6 @@ + + + - + + - + + + + + Modified: z3/jsonserver/branch/merge/metaconfigure.py ============================================================================== --- z3/jsonserver/branch/merge/metaconfigure.py (original) +++ z3/jsonserver/branch/merge/metaconfigure.py Sat May 13 15:42:32 2006 @@ -20,13 +20,19 @@ updated 2005-12-03 Roger Ineichen jwashin 2005-06-06 """ + +from __compat__ import __compat__ + import zope.interface from zope.interface import Interface from zope.security.checker import CheckerPublic, Checker from zope.configuration.exceptions import ConfigurationError from interfaces import IJSONRPCRequest -from zope.component.interface import provideInterface +if __compat__.zope_pre_3_3: + from zope.app.component.interface import provideInterface +else: + from zope.component.interface import provideInterface from zope.app.component.metaconfigure import handler from jsonrpc import MethodPublisher Modified: z3/jsonserver/branch/merge/minjson/configure.zcml ============================================================================== --- z3/jsonserver/branch/merge/minjson/configure.zcml (original) +++ z3/jsonserver/branch/merge/minjson/configure.zcml Sat May 13 15:42:32 2006 @@ -1,7 +1,7 @@ - + - - - - @@ -38,20 +34,4 @@ - - - - - - - Modified: z3/jsonserver/branch/merge/z2_compatibility/jsonrpc.py ============================================================================== --- z3/jsonserver/branch/merge/z2_compatibility/jsonrpc.py (original) +++ z3/jsonserver/branch/merge/z2_compatibility/jsonrpc.py Sat May 13 15:42:32 2006 @@ -14,7 +14,7 @@ __docformat__ = 'restructuredtext' -from minjson import read, write, ReadException, WriteException +from Products.jsonserver.minjson import read, write, ReadException, WriteException from zExceptions.ExceptionFormatter import format_exception from StringIO import StringIO import sys, traceback, re Modified: z3/jsonserver/branch/merge/z2_compatibility/meta.zcml ============================================================================== --- z3/jsonserver/branch/merge/z2_compatibility/meta.zcml (original) +++ z3/jsonserver/branch/merge/z2_compatibility/meta.zcml Sat May 13 15:42:32 2006 @@ -1,7 +1,7 @@ - + - - From regebro at codespeak.net Mon May 15 12:25:57 2006 From: regebro at codespeak.net (regebro@codespeak.net) Date: Mon May 15 12:25:59 2006 Subject: [z3-checkins] r27227 - z3/CMFonFive/trunk Message-ID: <20060515102557.3FC38100B6@code0.codespeak.net> Author: regebro Date: Mon May 15 12:25:56 2006 New Revision: 27227 Modified: z3/CMFonFive/trunk/README.txt Log: Noting that 2.9.0 dosn't work. Modified: z3/CMFonFive/trunk/README.txt ============================================================================== --- z3/CMFonFive/trunk/README.txt (original) +++ z3/CMFonFive/trunk/README.txt Mon May 15 12:25:56 2006 @@ -37,11 +37,12 @@ -------- Which version you should download depends on the version of Zope and CMF. Make sure you match these versions with your CMFonFive version! -Note that there is no CMFonFive for CMF versions before 1.5.2 on Zope 2.9. +Note that there is no CMFonFive for CMF versions before 1.5.2 on Zope 2.9 +and no support for Zope 2.9.0. * CMFonFive 1.3.2 (2006-02-22) - For CMF 1.5.2 and later, with Zope 2.9. + For CMF 1.5.2 and later, with Zope 2.9.1 or 2.9.2. Requires GenericSetup or CMF 1.6 (Where GenericSetup is included). http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.3.2.tgz From regebro at codespeak.net Mon May 15 18:26:06 2006 From: regebro at codespeak.net (regebro@codespeak.net) Date: Mon May 15 18:26:07 2006 Subject: [z3-checkins] r27242 - z3/CMFonFive/trunk Message-ID: <20060515162606.D386810093@code0.codespeak.net> Author: regebro Date: Mon May 15 18:26:06 2006 New Revision: 27242 Modified: z3/CMFonFive/trunk/__init__.py Log: Made GenericSetup optional (for 1.5.x support). Modified: z3/CMFonFive/trunk/__init__.py ============================================================================== --- z3/CMFonFive/trunk/__init__.py (original) +++ z3/CMFonFive/trunk/__init__.py Mon May 15 18:26:06 2006 @@ -10,9 +10,7 @@ $Id$ """ -from Products.GenericSetup import profile_registry, EXTENSION from Products.CMFCore.utils import ToolInit -from Products.CMFCore.interfaces import ISiteRoot import fiveactionstool def initialize(context): @@ -22,10 +20,15 @@ , icon='tool.gif' ).initialize( context ) - profile_registry.registerProfile('default', - 'CMFonFive', - "Profile for a CMFonFive installation", - 'profiles/default', - 'CMFonFive', - EXTENSION, - for_=ISiteRoot) + try: + from Products.GenericSetup import profile_registry, EXTENSION + from Products.CMFCore.interfaces import ISiteRoot + profile_registry.registerProfile('default', + 'CMFonFive', + "Profile for a CMFonFive installation", + 'profiles/default', + 'CMFonFive', + EXTENSION, + for_=ISiteRoot) + except ImportError: + pass From regebro at codespeak.net Mon May 15 18:27:11 2006 From: regebro at codespeak.net (regebro@codespeak.net) Date: Mon May 15 18:27:12 2006 Subject: [z3-checkins] r27243 - z3/CMFonFive/trunk Message-ID: <20060515162711.CECAE10093@code0.codespeak.net> Author: regebro Date: Mon May 15 18:27:11 2006 New Revision: 27243 Modified: z3/CMFonFive/trunk/CHANGES.txt z3/CMFonFive/trunk/README.txt z3/CMFonFive/trunk/version.txt Log: Preparing for release. Modified: z3/CMFonFive/trunk/CHANGES.txt ============================================================================== --- z3/CMFonFive/trunk/CHANGES.txt (original) +++ z3/CMFonFive/trunk/CHANGES.txt Mon May 15 18:27:11 2006 @@ -13,6 +13,8 @@ The reason for this change is that it enables you to add icons with the CMF ActionIconsTool. + - GenericSetup is now optional. + CMFonFive 1.3.2 (2006-02-22) - GenericSetup calls all action providers with both object and info Modified: z3/CMFonFive/trunk/README.txt ============================================================================== --- z3/CMFonFive/trunk/README.txt (original) +++ z3/CMFonFive/trunk/README.txt Mon May 15 18:27:11 2006 @@ -26,44 +26,34 @@ Requirements ------------ -* Zope 2.7 or later. +* Zope 2.9.1 or later. -* If you use Zope 2.7 you also need Five 1.0 or 1.1. - -* CMF 1.4 or 1.5. +* CMF 1.5.2 or later. + CMF 2.0 does not need CMFonFive. Download -------- -Which version you should download depends on the version of Zope and CMF. -Make sure you match these versions with your CMFonFive version! -Note that there is no CMFonFive for CMF versions before 1.5.2 on Zope 2.9 -and no support for Zope 2.9.0. - -* CMFonFive 1.3.2 (2006-02-22) - For CMF 1.5.2 and later, with Zope 2.9.1 or 2.9.2. - Requires GenericSetup or CMF 1.6 (Where GenericSetup is included). - - http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.3.2.tgz +* CMFonFive 1.3.3 (2006-05-15) -* CMFonFive 1.2.1 (2006-01-02) + For CMF 1.5.2 and later, with Zope 2.9.1, 2.9.2, 2.9.3 and 2.10.0. - For CMF 1.5.2 and later, with Zope 2.8. + http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.3.3.tgz - http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.2.1.tgz -* CMFonFive 1.1.1 (2006-01-02) +Earlier versions +---------------- - For CMF 1.4.0 to 1.5.1 with Zope 2.7 or 2.8. +These earlier versions are deprecated, but if you need CMFonFive for older +versions of CMF or Zope, you can still download them here: - http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.1.1.tgz +* CMFonFive 1.3.2 (2006-02-22) + For CMF 1.5.2 and later, with Zope 2.9. Requires GenericSetup or CMF 1.6 + (Where GenericSetup is included). -Earlier versions ----------------- - -These earlier versions are depracated, as later version have had bugs fixed. + http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.3.2.tgz * CMFonFive 1.3.1 (2006-02-10) @@ -77,12 +67,24 @@ http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.3.0.tgz +* CMFonFive 1.2.1 (2006-01-02) + + For CMF 1.5.2 and later, with Zope 2.8. + + http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.2.1.tgz + * CMFonFive 1.2.0 (2005-07-22) For CMF 1.5.2 and later, with Zope 2.9. http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.2.0.tgz +* CMFonFive 1.1.1 (2006-01-02) + + For CMF 1.4.0 to 1.5.1 with Zope 2.7 or 2.8. + + http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.1.1.tgz + * CMFonFive 1.1.0 (2005-06-19) For CMF 1.4.0 to 1.5.1 with Zope 2.7 or 2.8. Modified: z3/CMFonFive/trunk/version.txt ============================================================================== --- z3/CMFonFive/trunk/version.txt (original) +++ z3/CMFonFive/trunk/version.txt Mon May 15 18:27:11 2006 @@ -1 +1 @@ -CMFonFive-1.3.2+ +CMFonFive-1.3.3 From regebro at codespeak.net Mon May 15 18:28:44 2006 From: regebro at codespeak.net (regebro@codespeak.net) Date: Mon May 15 18:28:45 2006 Subject: [z3-checkins] r27244 - z3/CMFonFive/trunk Message-ID: <20060515162844.D605D10093@code0.codespeak.net> Author: regebro Date: Mon May 15 18:28:44 2006 New Revision: 27244 Modified: z3/CMFonFive/trunk/README.txt Log: Simplified. Modified: z3/CMFonFive/trunk/README.txt ============================================================================== --- z3/CMFonFive/trunk/README.txt (original) +++ z3/CMFonFive/trunk/README.txt Mon May 15 18:28:44 2006 @@ -37,7 +37,7 @@ * CMFonFive 1.3.3 (2006-05-15) - For CMF 1.5.2 and later, with Zope 2.9.1, 2.9.2, 2.9.3 and 2.10.0. + For CMF 1.5.2 and later, with Zope 2.9.1 or later. http://codespeak.net/z3/cmfonfive/release/CMFonFive-1.3.3.tgz From regebro at codespeak.net Mon May 15 18:31:37 2006 From: regebro at codespeak.net (regebro@codespeak.net) Date: Mon May 15 18:31:39 2006 Subject: [z3-checkins] r27246 - z3/CMFonFive/tag/CMFonFive-1.3.3 Message-ID: <20060515163137.5545A100BD@code0.codespeak.net> Author: regebro Date: Mon May 15 18:31:33 2006 New Revision: 27246 Added: z3/CMFonFive/tag/CMFonFive-1.3.3/ - copied from r27226, z3/CMFonFive/trunk/ z3/CMFonFive/tag/CMFonFive-1.3.3/CHANGES.txt - copied unchanged from r27243, z3/CMFonFive/trunk/CHANGES.txt z3/CMFonFive/tag/CMFonFive-1.3.3/README.txt - copied unchanged from r27244, z3/CMFonFive/trunk/README.txt z3/CMFonFive/tag/CMFonFive-1.3.3/__init__.py - copied unchanged from r27242, z3/CMFonFive/trunk/__init__.py z3/CMFonFive/tag/CMFonFive-1.3.3/version.txt - copied unchanged from r27243, z3/CMFonFive/trunk/version.txt Log: Releasing 1.3.3 From regebro at codespeak.net Mon May 15 18:53:14 2006 From: regebro at codespeak.net (regebro@codespeak.net) Date: Mon May 15 18:53:15 2006 Subject: [z3-checkins] r27247 - z3/www/trunk Message-ID: <20060515165314.5BB61100B6@code0.codespeak.net> Author: regebro Date: Mon May 15 18:53:13 2006 New Revision: 27247 Modified: z3/www/trunk/mkwebsite.py Log: Added the later CMFonFive releases. Modified: z3/www/trunk/mkwebsite.py ============================================================================== --- z3/www/trunk/mkwebsite.py (original) +++ z3/www/trunk/mkwebsite.py Mon May 15 18:53:13 2006 @@ -209,6 +209,8 @@ Z3ReleaseResource('CMFonFive', 'http://codespeak.net/svn/z3/CMFonFive/tag/CMFonFive-1.2.1'), Z3ReleaseResource('CMFonFive', 'http://codespeak.net/svn/z3/CMFonFive/tag/CMFonFive-1.3.0'), Z3ReleaseResource('CMFonFive', 'http://codespeak.net/svn/z3/CMFonFive/tag/CMFonFive-1.3.1'), + Z3ReleaseResource('CMFonFive', 'http://codespeak.net/svn/z3/CMFonFive/tag/CMFonFive-1.3.2'), + Z3ReleaseResource('CMFonFive', 'http://codespeak.net/svn/z3/CMFonFive/tag/CMFonFive-1.3.3'), ], project.getName()) From gintas at codespeak.net Mon May 15 22:49:39 2006 From: gintas at codespeak.net (gintas@codespeak.net) Date: Mon May 15 22:49:41 2006 Subject: [z3-checkins] r27253 - z3/z3reload Message-ID: <20060515204939.D6BC6100C5@code0.codespeak.net> Author: gintas Date: Mon May 15 22:49:38 2006 New Revision: 27253 Added: z3/z3reload/ Log: Importing z3reload (1/4). From gintas at codespeak.net Mon May 15 22:49:52 2006 From: gintas at codespeak.net (gintas@codespeak.net) Date: Mon May 15 22:49:53 2006 Subject: [z3-checkins] r27254 - z3/z3reload/trunk Message-ID: <20060515204952.A7B41100C5@code0.codespeak.net> Author: gintas Date: Mon May 15 22:49:52 2006 New Revision: 27254 Added: z3/z3reload/trunk/ Log: Importing z3reload (2/4). From gintas at codespeak.net Mon May 15 22:51:58 2006 From: gintas at codespeak.net (gintas@codespeak.net) Date: Mon May 15 22:51:59 2006 Subject: [z3-checkins] r27255 - in z3/z3reload/trunk: . ftests package-includes Message-ID: <20060515205158.647F6100C5@code0.codespeak.net> Author: gintas Date: Mon May 15 22:51:57 2006 New Revision: 27255 Added: z3/z3reload/trunk/README.txt (contents, props changed) z3/z3reload/trunk/__init__.py (contents, props changed) z3/z3reload/trunk/configure.zcml (contents, props changed) z3/z3reload/trunk/ftests/ z3/z3reload/trunk/ftests/__init__.py (contents, props changed) z3/z3reload/trunk/ftests/dynamic.pt (contents, props changed) z3/z3reload/trunk/ftests/dynamic.py (contents, props changed) z3/z3reload/trunk/ftests/dynamic_orig.py (contents, props changed) z3/z3reload/trunk/ftests/ftesting.zcml (contents, props changed) z3/z3reload/trunk/ftests/reload.txt (contents, props changed) z3/z3reload/trunk/ftests/tests.py (contents, props changed) z3/z3reload/trunk/meta.zcml (contents, props changed) z3/z3reload/trunk/metaconfigure.py (contents, props changed) z3/z3reload/trunk/metadirectives.py (contents, props changed) z3/z3reload/trunk/package-includes/ z3/z3reload/trunk/package-includes/z3reload-configure.zcml (contents, props changed) z3/z3reload/trunk/package-includes/z3reload-ftesting.zcml (contents, props changed) z3/z3reload/trunk/package-includes/z3reload-meta.zcml (contents, props changed) z3/z3reload/trunk/reload.py (contents, props changed) z3/z3reload/trunk/subscriber.py (contents, props changed) Log: Importing z3reload (3/4). Added: z3/z3reload/trunk/README.txt ============================================================================== --- (empty file) +++ z3/z3reload/trunk/README.txt Mon May 15 22:51:57 2006 @@ -0,0 +1,118 @@ +z3reload +======== + +Version 0.1 + +http://gintas.pov.lt/z3reload + + +z3reload is a Zope 3 product that enables automatic reloading of view code. + +Make sure to read the *pitfalls* section before you delve in. + +View instances are short-lived and references to them are stored very +infrequently, which makes them a good candidate for dynamic reloading. +In addition they are frequently the largest and most complex part of +the code in a typical web application. Even within the restrictions of +this implementation automatic code reloading is very handy to have as Zope 3 +requires a noticeable amount of time to restart. + + +Installation +------------ + +Copy the z3reload directory where Zope 3 can find it, copy all files in +the package-includes/ subdirectory to package-includes/ in Zope 3. + + +Configuration +------------- + +In package-includes/z3reload-configure.zcml (the global one which you created, +not the one inside the package), the namespace `reload` should be registered, +like this: + + + +In the same file you can specify individual classes, modules or packages which +contain views that should be made reloadable using the ZCML directive +`reload`. Here is an example: + + + +This configuration would make views SomeView and AnotherView reloadable. +All views directly in anotherpackage.views, for example, +anotherpackage.views.FooView (but not anotherpackage.views.admin.BarView), +would be included too. Finally, all views in all modules that reside +in thirdpackage.browser would be processed (thirdpackage.browser.XView, +thirdpackage.browser.admin.YView, etc.). + + +Usage +----- + +Use the views as you normally would. The view code will be automatically +reloaded before just before rendering the view each time. + + +Pitfalls +-------- + +Only the module that the view code resides in will be reloaded. E.g., if +you have a view mypackage.browser.admin.AdminView that inherits from +mypackage.browser.ViewBase, the mypackage.browser module will not be +reloaded, and therefore changes in ViewBase will not take effect. + +It is important to understand the implications of reloading a Python +module. Basically, all objects -- classes, functions and others -- +defined in the top level of the module "change". Old references +(frequently in the form of imports) from other modules, however, will +still point to the old objects. This way you can end up with two +different references to distinct versions of the same class, which may +cause unexpected behaviour with issubclass(). A similar problem can arise +if the module defines interfaces which other modules use. + +z3reload can deal with updated views, but it will not notice changes in +other components: adapters, utilities, subscribers. It will work with +code outside the components (top-level functions and classes other than +the registered one) though. This is because Zope 3 stores references to +the components at startup time. It should be possible to reload these +components automatically too, but that would probably require a different +approach, because we would not be able not use the mixin hack. + +In general it is a good idea to only use automatic reloading for +non-structural changes such as defining or modifying methods of views +and do an old-fashioned server restart when you make a more significant +change. + + +Implementation details +---------------------- + +z3reload waits for the DatabaseOpened event, when all view registration has +been completed, and then walks through the global adapter registry. For +each view to be processed according to the `reload` directive it installs +the mixin Reloader. + +Actually, Zope 3 ZCML directives that register views do not register the +plain view class as a multi-adapter. Instead, they dynamically construct +a new type which inherits from the given class and from a `simple view` class +(that would be zope.app.pagetemplate.simpleviewclass.simple for views that +have page templates defined in ZCML, and +zope.app.publisher.browser.viewmeta.simple for views that don't). We use +this fact and add Reloader as the first base class. + +Reloader overrides the __init__() method of the real view. In this method +the module of the class is reloaded and the attribute __bases__ of the class +is updated with a new reference to the reloaded class. Then __init__ of the +actual reloaded view is invoked. + + +Gintautas Miliauskas +2005-08-20 Added: z3/z3reload/trunk/__init__.py ============================================================================== --- (empty file) +++ z3/z3reload/trunk/__init__.py Mon May 15 22:51:57 2006 @@ -0,0 +1,2 @@ +# Set this to True to list processed view classes on stderr. +BLATHER = False Added: z3/z3reload/trunk/configure.zcml ============================================================================== --- (empty file) +++ z3/z3reload/trunk/configure.zcml Mon May 15 22:51:57 2006 @@ -0,0 +1,9 @@ + + + + + + Added: z3/z3reload/trunk/ftests/__init__.py ============================================================================== Added: z3/z3reload/trunk/ftests/dynamic.pt ============================================================================== --- (empty file) +++ z3/z3reload/trunk/ftests/dynamic.pt Mon May 15 22:51:57 2006 @@ -0,0 +1 @@ +

The number is

Added: z3/z3reload/trunk/ftests/dynamic.py ============================================================================== --- (empty file) +++ z3/z3reload/trunk/ftests/dynamic.py Mon May 15 22:51:57 2006 @@ -0,0 +1,19 @@ +from zope.app.publisher.browser import BrowserView + + +class SomeNumberView(BrowserView): + + def __init__(self, context, request): + BrowserView.__init__(self, context, request) + self.number = 1001 + + +class AnotherNumberView(BrowserView): + + number = 2001 + + +class ThirdNumberView(BrowserView): + + def __call__(self): + return '3001' Added: z3/z3reload/trunk/ftests/dynamic_orig.py ============================================================================== --- (empty file) +++ z3/z3reload/trunk/ftests/dynamic_orig.py Mon May 15 22:51:57 2006 @@ -0,0 +1,19 @@ +from zope.app.publisher.browser import BrowserView + + +class SomeNumberView(BrowserView): + + def __init__(self, context, request): + BrowserView.__init__(self, context, request) + self.number = 1001 + + +class AnotherNumberView(BrowserView): + + number = 2001 + + +class ThirdNumberView(BrowserView): + + def __call__(self): + return '3001' Added: z3/z3reload/trunk/ftests/ftesting.zcml ============================================================================== --- (empty file) +++ z3/z3reload/trunk/ftests/ftesting.zcml Mon May 15 22:51:57 2006 @@ -0,0 +1,23 @@ + + + + + + + + + + + Added: z3/z3reload/trunk/ftests/reload.txt ============================================================================== --- (empty file) +++ z3/z3reload/trunk/ftests/reload.txt Mon May 15 22:51:57 2006 @@ -0,0 +1,73 @@ +z3reload functional test +======================== + + +Quick look +---------- + +First, let's simply try looking at the views, to make sure that +the configuration is correct. + + >>> print http("GET /some.html HTTP/1.1\n", handle_errors=False) + HTTP/1.1 200 Ok + ... +

The number is 1001

+ + + >>> print http("GET /another.html HTTP/1.1\n", handle_errors=False) + HTTP/1.1 200 Ok + ... +

The number is 2001

+ + + >>> print http("GET /third.txt HTTP/1.1\n", handle_errors=False) + HTTP/1.1 200 Ok + ... + Content-Type: text/plain;charset=utf-8 + + 3001 + + +Modification +------------ + +Now we will modify the view code: + + >>> from z3reload.ftests.tests import openfile + >>> import time + >>> def replace(old, new): + ... time.sleep(0.5) # longish, but shorter delays don't seem to work + ... orig = openfile('dynamic_orig.py').read() + ... f = openfile('dynamic.py', 'w') + ... f.write(orig.replace(old, new)) + ... f.close() + ... time.sleep(0.5) # longish, but shorter delays don't seem to work + + >>> replace('1001', '1123') + >>> print http("GET /some.html HTTP/1.1\n", handle_errors=False) + HTTP/1.1 200 Ok + ... +

The number is 1123

+ + + >>> replace('2001', '2123') + >>> print http("GET /another.html HTTP/1.1\n", handle_errors=False) + HTTP/1.1 200 Ok + ... +

The number is 2123

+ + + >>> replace('3001', '3123') + + >>> print http("GET /third.txt HTTP/1.1\n", handle_errors=False) + HTTP/1.1 200 Ok + ... + Content-Type: text/plain;charset=utf-8 + + 3123 + + +Epilogue +-------- + + vim: ft=rest Added: z3/z3reload/trunk/ftests/tests.py ============================================================================== --- (empty file) +++ z3/z3reload/trunk/ftests/tests.py Mon May 15 22:51:57 2006 @@ -0,0 +1,27 @@ +import os +import unittest + +from zope.testing import doctest +from zope.app.testing.functional import FunctionalDocFileSuite + + +current_dir = os.path.dirname(__file__) + +def openfile(filename, mode='r'): + return file(os.path.join(current_dir, filename), mode) + +def resetFile(test): + dynamic_orig = openfile('dynamic_orig.py').read() + openfile('dynamic.py', 'w').write(dynamic_orig) + + +def test_suite(): + optionflags = (doctest.ELLIPSIS | doctest.REPORT_NDIFF | + doctest.NORMALIZE_WHITESPACE | + doctest.REPORT_ONLY_FIRST_FAILURE) + return FunctionalDocFileSuite('reload.txt', optionflags=optionflags, + setUp=resetFile, tearDown=resetFile) + + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') Added: z3/z3reload/trunk/meta.zcml ============================================================================== --- (empty file) +++ z3/z3reload/trunk/meta.zcml Mon May 15 22:51:57 2006 @@ -0,0 +1,11 @@ + + + + + + + Added: z3/z3reload/trunk/metaconfigure.py ============================================================================== --- (empty file) +++ z3/z3reload/trunk/metaconfigure.py Mon May 15 22:51:57 2006 @@ -0,0 +1,23 @@ +import sys +from zope.configuration.exceptions import ConfigurationError + + +enabled_classes = [] # list of class objects +enabled_modules = [] # list of module names +enabled_packages = [] # list of package names + + +def handle_reload(classes, modules, packages): + """Add provided objects to global registry of reloadable objects.""" + enabled_classes.extend(classes) + enabled_modules.extend([mod.__name__ for mod in modules]) + enabled_packages.extend([pkg.__name__ for pkg in packages]) + + +def reload(_context, classes=[], modules=[], packages=[]): + """Process the `reload` ZCML directive.""" + if not (classes or modules or packages): + raise ConfigurationError("You must specify at least one of" + " `classes`, `modules` or `packages`.") + _context.action(discriminator=None, callable=handle_reload, + args=(classes, modules, packages)) Added: z3/z3reload/trunk/metadirectives.py ============================================================================== --- (empty file) +++ z3/z3reload/trunk/metadirectives.py Mon May 15 22:51:57 2006 @@ -0,0 +1,40 @@ +from zope.interface import Interface +from zope.configuration.fields import Tokens, GlobalObject + + +class IReloadDirective(Interface): + + classes = Tokens( + title=u"View classes", + required=False, + value_type=GlobalObject( + title=u"View class", + description=u""" + A view class for which automatic reload should be enabled. + """)) + + modules = Tokens( + title=u"Modules", + required=False, + value_type=GlobalObject( + title=u"Module", + description=u""" + A module containing views for which automatic reload should be + enabled. + """)) + + packages = Tokens( + title=u"Packages", + required=False, + value_type=GlobalObject( + title=u"Package", + description=u""" + A package containing views for which automatic reload should be + enabled. + + `module` only works for a single module, whereas `package` also + applies for contained modules and packages. + """)) + + +# TODO: reload:omit, reload:all Added: z3/z3reload/trunk/package-includes/z3reload-configure.zcml ============================================================================== --- (empty file) +++ z3/z3reload/trunk/package-includes/z3reload-configure.zcml Mon May 15 22:51:57 2006 @@ -0,0 +1,14 @@ + + + + + + + + + Added: z3/z3reload/trunk/package-includes/z3reload-ftesting.zcml ============================================================================== --- (empty file) +++ z3/z3reload/trunk/package-includes/z3reload-ftesting.zcml Mon May 15 22:51:57 2006 @@ -0,0 +1 @@ + Added: z3/z3reload/trunk/package-includes/z3reload-meta.zcml ============================================================================== --- (empty file) +++ z3/z3reload/trunk/package-includes/z3reload-meta.zcml Mon May 15 22:51:57 2006 @@ -0,0 +1 @@ + Added: z3/z3reload/trunk/reload.py ============================================================================== --- (empty file) +++ z3/z3reload/trunk/reload.py Mon May 15 22:51:57 2006 @@ -0,0 +1,74 @@ +import sys +from zope.app.pagetemplate.simpleviewclass import simple as SimplePTPage +from zope.app.publisher.browser.viewmeta import simple as SimplePage + +from z3reload import BLATHER + +simple_view_classes = (SimplePTPage, SimplePage) + + +class Reloader(object): + """A mixin to be used on SimpleViewClass instances. + + These SimpleViewClass instances are in fact dynamically constructed types + with either zope.app.pagetemplate.simpleviewclass.simple or + zope.app.publisher,browser.viewmeta as one of the base classes. + + This mixin must be the first superclass, because its __init__ must be + called on instantiation. + """ + + def __init__(self, *args, **kw): + assert len(self.__class__.__bases__) == 3 + reloader2, real_view, simple2 = self.__class__.__bases__ + assert reloader2 is Reloader + assert simple2 in simple_view_classes + + clsname = real_view.__name__ + modname = real_view.__module__ + module = sys.modules[modname] + if hasattr(module, clsname): + reload(module) + new_view = getattr(module, clsname) + self.__class__.__bases__ = (Reloader, new_view, simple2) + else: + # If the module does not have such an attribute, chances are that + # the class was dynamically constructed. In this case reloading is + # likely to break so we don't do it. + new_view = real_view # just use the old view + + self.__sanitize_bases(new_view) + new_view.__init__(self, *args, **kw) + + def __sanitize_bases(self, cls): + """Make sure that the bases of a class are in the scope. + + This works around the problem when a class bases do not correspond + to the same-named classes in the scope, which could happen after a + reload. This causes errors when invoking base clases + """ + modname = cls.__module__ + module = sys.modules[modname] + + bases = cls.__bases__ + new_bases = [] + for b in bases: + if hasattr(module, b.__name__): + new_base = getattr(module, b.__name__) + self.__sanitize_bases(new_base) + new_bases.append(new_base) + else: + # Couldn't find class in local scope, abort. + break + else: + # All bases checked successfully. + cls.__bases__ = tuple(new_bases) + + + +def install_reloader(view_class): + """Install the Reloader mixin on view_class.""" + assert view_class.__bases__[-1] in simple_view_classes + if BLATHER: + print >> sys.stderr, 'Reloader installed for', view_class.__bases__[0] + view_class.__bases__ = (Reloader, ) + view_class.__bases__ Added: z3/z3reload/trunk/subscriber.py ============================================================================== --- (empty file) +++ z3/z3reload/trunk/subscriber.py Mon May 15 22:51:57 2006 @@ -0,0 +1,52 @@ +import sys + +from zope.component import getGlobalSiteManager +from zope.publisher.interfaces import IRequest +from zope.component.site import AdapterRegistration + +from z3reload.reload import install_reloader, simple_view_classes +from z3reload.metaconfigure import enabled_classes, enabled_modules +from z3reload.metaconfigure import enabled_packages + +request_type = IRequest + + +def is_simple_view(reg): + """Return True if reg is a registration for a `simple` view. + + A `simple` view is one that subclasses one of simple_view_classes. + """ + if not (isinstance(reg, AdapterRegistration) and + len(reg.required) > 0 and + reg.required[-1] is not None and + reg.required[-1].isOrExtends(IRequest)): + return False # this registration does not appear to be a view + + return (type(reg.value) == type and + issubclass(reg.value, simple_view_classes)) + + +def reload_enabled_for(view_class): + """Return True if view_class should be made reloadable.""" + assert view_class.__bases__[-1] in simple_view_classes + real_view = view_class.__bases__[0] + if real_view in enabled_classes: + return True + for module in enabled_modules: + if real_view.__module__ == module: + return True + for package in enabled_packages: + if real_view.__module__.startswith(package): + return True + return False + + +def database_opened(event): + """Scan adapter registrations and make specified views reloadable. + + Hooks on the DatabaseOpened event. + """ + gsm = getGlobalSiteManager() + for reg in gsm.registrations(): + if is_simple_view(reg) and reload_enabled_for(reg.value): + install_reloader(reg.value) From gintas at codespeak.net Mon May 15 22:58:46 2006 From: gintas at codespeak.net (gintas@codespeak.net) Date: Mon May 15 22:58:48 2006 Subject: [z3-checkins] r27256 - z3/z3reload/trunk Message-ID: <20060515205846.B90B6100C5@code0.codespeak.net> Author: gintas Date: Mon May 15 22:58:46 2006 New Revision: 27256 Modified: z3/z3reload/trunk/README.txt Log: Importing z3reload (4/4). Modified: z3/z3reload/trunk/README.txt ============================================================================== --- z3/z3reload/trunk/README.txt (original) +++ z3/z3reload/trunk/README.txt Mon May 15 22:58:46 2006 @@ -15,7 +15,12 @@ In addition they are frequently the largest and most complex part of the code in a typical web application. Even within the restrictions of this implementation automatic code reloading is very handy to have as Zope 3 -requires a noticeable amount of time to restart. +can take a while to restart. + +Code of z3reload now resides at the Zope 3 Base (codespeak.net). Use the +following command to grab the latest trunk from Subversion: + + svn co http://codespeak.net/svn/z3/z3reload/trunk z3reload Installation From gintas at codespeak.net Mon May 15 23:22:16 2006 From: gintas at codespeak.net (gintas@codespeak.net) Date: Mon May 15 23:22:17 2006 Subject: [z3-checkins] r27257 - z3/z3reload/trunk Message-ID: <20060515212216.1229E100A4@code0.codespeak.net> Author: gintas Date: Mon May 15 23:22:15 2006 New Revision: 27257 Modified: z3/z3reload/trunk/README.txt Log: Updated URL to the zope 3 base. Modified: z3/z3reload/trunk/README.txt ============================================================================== --- z3/z3reload/trunk/README.txt (original) +++ z3/z3reload/trunk/README.txt Mon May 15 23:22:15 2006 @@ -17,10 +17,10 @@ this implementation automatic code reloading is very handy to have as Zope 3 can take a while to restart. -Code of z3reload now resides at the Zope 3 Base (codespeak.net). Use the -following command to grab the latest trunk from Subversion: +Code of z3reload now resides at the Zope 3 Base (http://codespeak.net/z3). +Use the following command to grab the latest trunk using Subversion: - svn co http://codespeak.net/svn/z3/z3reload/trunk z3reload + svn checkout http://codespeak.net/svn/z3/z3reload/trunk z3reload Installation From tseaver at codespeak.net Tue May 16 14:38:55 2006 From: tseaver at codespeak.net (tseaver at codespeak.net) Date: Tue, 16 May 2006 14:38:55 +0200 (CEST) Subject: [z3-checkins] r27274 - in z3/xicken/trunk: . src/xicken Message-ID: <20060516123855.E87D110070@code0.codespeak.net> Author: tseaver Date: Tue May 16 14:38:54 2006 New Revision: 27274 Modified: z3/xicken/trunk/CHANGES.txt z3/xicken/trunk/src/xicken/browser.py z3/xicken/trunk/src/xicken/interfaces.py Log: Update for compatibility with Zope 3.2+. Fixed bug blocking page removal. Modified: z3/xicken/trunk/CHANGES.txt ============================================================================== --- z3/xicken/trunk/CHANGES.txt (original) +++ z3/xicken/trunk/CHANGES.txt Tue May 16 14:38:54 2006 @@ -1,7 +1,12 @@ -Xickens Package Changelog -========================= +Xicken Package Changelog +======================== -After xickens-0.1.1 +xicken-0.2 (2006/05/16) +---------------------- + + - Update for compatibility with Zope 3.2+. + + - Fixed bug blocking page removal. - Derive from IContained, rathar than ILocation, to get our __parent__ set majykally. @@ -15,10 +20,12 @@ - Add "index.xml" views for fetching simple XML serialization of a XickenPage or a XickenSite. -xickens-0.1.1 (2004/10/19) +xicken-0.1.1 (2004/10/19) +------------------------- - Allow Mom to edit site title. -xickens-0.1.0 (2004/09/27) +xicken-0.1.0 (2004/09/27) +------------------------- - Simplest-possible Zope3 content management application (not a framework!) Modified: z3/xicken/trunk/src/xicken/browser.py ============================================================================== --- z3/xicken/trunk/src/xicken/browser.py (original) +++ z3/xicken/trunk/src/xicken/browser.py Tue May 16 14:38:54 2006 @@ -2,11 +2,10 @@ $Id$ """ -from transaction import get_transaction +import transaction from zope.event import notify -from zope.i18nmessageid import MessageIDFactory -from zope.app import zapi +from zope.component import getMultiAdapter from zope.app.event.objectevent import ObjectCreatedEvent from zope.app.event.objectevent import ObjectModifiedEvent @@ -14,7 +13,11 @@ from xicken.interfaces import IXickenPage from xicken.content import XickenPage -_ = MessageIDFactory('xicken') +try: + from zope.i18nmessageid import MessageFactory +except ImportError: + from zope.i18nmessageid import MessageIDFactory as MessageFactory +_ = MessageFactory('xicken') class XickenBaseView: @@ -37,7 +40,8 @@ def _getURL(self, page): - return zapi.getView(page, 'absolute_url', self.request) + view = getMultiAdapter((page, self.request), name='absolute_url') + return view() def _getContextUrl(self): @@ -73,7 +77,7 @@ if self.errors: status = _("Could not save configuration.") - get_transaction().abort() + transaction.get().abort() else: self.context.title = title notify(ObjectModifiedEvent(self.context)) @@ -106,7 +110,7 @@ if self.errors: status = _("Could not add page.") - get_transaction().abort() + transaction.get().abort() else: page = XickenPage(name) page.title = title @@ -134,10 +138,10 @@ if error: self.request.response.redirect('%s/FrontPage?error=%s' - % (self.site_url(), error)) + % (self.site_url, error)) else: self.request.response.redirect('%s/FrontPage?message=%s' - % (self.site_url(), message)) + % (self.site_url, message)) return error or message class XickenPageView(XickenBaseView): @@ -176,7 +180,7 @@ if self.errors: status = _("Could not save page.") - get_transaction().abort() + transaction.get().abort() else: self.savePage(title, body) notify(ObjectModifiedEvent(self.context)) Modified: z3/xicken/trunk/src/xicken/interfaces.py ============================================================================== --- z3/xicken/trunk/src/xicken/interfaces.py (original) +++ z3/xicken/trunk/src/xicken/interfaces.py Tue May 16 14:38:54 2006 @@ -5,12 +5,15 @@ from zope.schema import Text from zope.schema import TextLine -from zope.i18nmessageid import MessageIDFactory from zope.app.folder.interfaces import IFolder from zope.app.file.interfaces import IFile -_ = MessageIDFactory('xicken') +try: + from zope.i18nmessageid import MessageFactory +except ImportError: + from zope.i18nmessageid import MessageIDFactory as MessageFactory +_ = MessageFactory('xicken') class IXickenSite(IFolder): """A Xicken Site is a simple CM appliction for creating pages. From tseaver at codespeak.net Tue May 16 14:39:48 2006 From: tseaver at codespeak.net (tseaver at codespeak.net) Date: Tue, 16 May 2006 14:39:48 +0200 (CEST) Subject: [z3-checkins] r27275 - z3/xicken/tag/0.2 Message-ID: <20060516123948.D110B10070@code0.codespeak.net> Author: tseaver Date: Tue May 16 14:39:48 2006 New Revision: 27275 Added: z3/xicken/tag/0.2/ - copied from r27274, z3/xicken/trunk/ Log: Tag xicken-0.2 release. From faassen at codespeak.net Tue May 16 18:41:43 2006 From: faassen at codespeak.net (faassen at codespeak.net) Date: Tue, 16 May 2006 18:41:43 +0200 (CEST) Subject: [z3-checkins] r27278 - z3/hurry.query Message-ID: <20060516164143.140D110080@code0.codespeak.net> Author: faassen Date: Tue May 16 18:41:42 2006 New Revision: 27278 Added: z3/hurry.query/ Log: Create new hurry.query package, containing just hurry.query functionality. From faassen at codespeak.net Tue May 16 18:41:52 2006 From: faassen at codespeak.net (faassen at codespeak.net) Date: Tue, 16 May 2006 18:41:52 +0200 (CEST) Subject: [z3-checkins] r27279 - z3/hurry.query/trunk Message-ID: <20060516164152.3042910080@code0.codespeak.net> Author: faassen Date: Tue May 16 18:41:51 2006 New Revision: 27279 Added: z3/hurry.query/trunk/ Log: Create trunk. From faassen at codespeak.net Tue May 16 18:42:18 2006 From: faassen at codespeak.net (faassen at codespeak.net) Date: Tue, 16 May 2006 18:42:18 +0200 (CEST) Subject: [z3-checkins] r27280 - z3/hurry.query/trunk Message-ID: <20060516164218.6A84B10080@code0.codespeak.net> Author: faassen Date: Tue May 16 18:42:17 2006 New Revision: 27280 Removed: z3/hurry.query/trunk/ Log: Going to create trunk as copy from hurry instead. From faassen at codespeak.net Tue May 16 18:42:51 2006 From: faassen at codespeak.net (faassen at codespeak.net) Date: Tue, 16 May 2006 18:42:51 +0200 (CEST) Subject: [z3-checkins] r27281 - z3/hurry.query/trunk Message-ID: <20060516164251.3BC3D10080@code0.codespeak.net> Author: faassen Date: Tue May 16 18:42:49 2006 New Revision: 27281 Added: z3/hurry.query/trunk/ - copied from r27280, z3/hurry/trunk/ Log: Create new trunk. Will prune it so it only contains hurry.query code. From faassen at codespeak.net Tue May 16 18:46:04 2006 From: faassen at codespeak.net (faassen at codespeak.net) Date: Tue, 16 May 2006 18:46:04 +0200 (CEST) Subject: [z3-checkins] r27282 - in z3/hurry.query/trunk: . src/hurry src/hurry/file src/hurry/workflow Message-ID: <20060516164604.ED23410069@code0.codespeak.net> Author: faassen Date: Tue May 16 18:46:03 2006 New Revision: 27282 Added: z3/hurry.query/trunk/hurry.query-configure.zcml - copied, changed from r27281, z3/hurry.query/trunk/hurry-configure.zcml Removed: z3/hurry.query/trunk/hurry-configure.zcml z3/hurry.query/trunk/src/hurry/configure.zcml z3/hurry.query/trunk/src/hurry/file/ z3/hurry.query/trunk/src/hurry/workflow/ Modified: z3/hurry.query/trunk/CHANGES.txt z3/hurry.query/trunk/CREDITS.txt z3/hurry.query/trunk/INSTALL.txt z3/hurry.query/trunk/LICENSE.txt z3/hurry.query/trunk/README.txt Log: First pruning away of everything non-hurry.query. Modified: z3/hurry.query/trunk/CHANGES.txt ============================================================================== --- z3/hurry.query/trunk/CHANGES.txt (original) +++ z3/hurry.query/trunk/CHANGES.txt Tue May 16 18:46:03 2006 @@ -1,6 +1,11 @@ hurry changes ============= +0.8.1 (under development) +------------------------- + +Separate hurry.query from the rest. + 0.8 (2006-05-01) ---------------- Modified: z3/hurry.query/trunk/CREDITS.txt ============================================================================== --- z3/hurry.query/trunk/CREDITS.txt (original) +++ z3/hurry.query/trunk/CREDITS.txt Tue May 16 18:46:03 2006 @@ -2,7 +2,8 @@ ------- Martijn Faassen - initial and main developer +Stephan Richter - additional hurry.query index support Jan-Wijbrand Kolman - suggestions and feedback -The hurry library for Zope 3 was originally developed at Infrae +The hurry.query library for Zope 3 was originally developed at Infrae (http://www.infrae.com). Modified: z3/hurry.query/trunk/INSTALL.txt ============================================================================== --- z3/hurry.query/trunk/INSTALL.txt (original) +++ z3/hurry.query/trunk/INSTALL.txt Tue May 16 18:46:03 2006 @@ -1,11 +1,11 @@ Installation ------------ -Hurry needs Zope 3.1 or Zope 3.2. +hurry.query needs Zope 3.1 or Zope 3.2. -Make sure hurry's src directory is on the Python path somehow, and -then copy hurry-configure.zcml into your Zope's `etc/package-includes` -directory. +Make sure hurry.query's src directory is on the Python path somehow, +and then copy hurry.query-configure.zcml into your Zope's +`etc/package-includes` directory. hurry.query also has support for zc.catalog SetIndexes in hurry.query.set. If you want to use this extension, you need to Modified: z3/hurry.query/trunk/LICENSE.txt ============================================================================== --- z3/hurry.query/trunk/LICENSE.txt (original) +++ z3/hurry.query/trunk/LICENSE.txt Tue May 16 18:46:03 2006 @@ -1,4 +1,4 @@ -Copyright (c) 2005 Infrae. All rights reserved. +Copyright (c) 2005-2006 Infrae. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are Modified: z3/hurry.query/trunk/README.txt ============================================================================== --- z3/hurry.query/trunk/README.txt (original) +++ z3/hurry.query/trunk/README.txt Tue May 16 18:46:03 2006 @@ -1,17 +1,4 @@ -Packages that could be generic and eventually might, in changed form, -end up in the Zope 3 core or Zope 3 ECM, but that we (at Infrae) built -in isolation for now, as we're in a hurry to use them. - -It includes: - hurry.query - higher level query system built on top of the Zope 3 catalog. Some inspiration came from Dieter Maurer's AdvancedQuery. See src/hurry/query/query.txt for documentation. - -hurry.workflow - a simple but quite nifty workflow system. See - src/hurry/workflow/workflow.txt for documentation. - -hurry.file - advanced file widget which tries its best to behave like - other widgets. See the doctest in - src/hurry/file/browser/file.txt for some documentation. Deleted: /z3/hurry.query/trunk/hurry-configure.zcml ============================================================================== --- /z3/hurry.query/trunk/hurry-configure.zcml Tue May 16 18:46:03 2006 +++ (empty file) @@ -1,3 +0,0 @@ - - Copied: z3/hurry.query/trunk/hurry.query-configure.zcml (from r27281, z3/hurry.query/trunk/hurry-configure.zcml) ============================================================================== --- z3/hurry.query/trunk/hurry-configure.zcml (original) +++ z3/hurry.query/trunk/hurry.query-configure.zcml Tue May 16 18:46:03 2006 @@ -1,3 +1,3 @@ - + Deleted: /z3/hurry.query/trunk/src/hurry/configure.zcml ============================================================================== --- /z3/hurry.query/trunk/src/hurry/configure.zcml Tue May 16 18:46:03 2006 +++ (empty file) @@ -1,11 +0,0 @@ - - - - - - - - - From faassen at codespeak.net Tue May 16 18:46:39 2006 From: faassen at codespeak.net (faassen at codespeak.net) Date: Tue, 16 May 2006 18:46:39 +0200 (CEST) Subject: [z3-checkins] r27283 - z3/hurry.query/trunk Message-ID: <20060516164639.4FEE310069@code0.codespeak.net> Author: faassen Date: Tue May 16 18:46:38 2006 New Revision: 27283 Removed: z3/hurry.query/trunk/VERSION.txt Log: Will maintain version information in setup.py. Deleted: /z3/hurry.query/trunk/VERSION.txt ============================================================================== --- /z3/hurry.query/trunk/VERSION.txt Tue May 16 18:46:38 2006 +++ (empty file) @@ -1 +0,0 @@ -0.8 From faassen at codespeak.net Tue May 16 18:48:32 2006 From: faassen at codespeak.net (faassen at codespeak.net) Date: Tue, 16 May 2006 18:48:32 +0200 (CEST) Subject: [z3-checkins] r27284 - z3/hurry.query/trunk Message-ID: <20060516164832.152D810069@code0.codespeak.net> Author: faassen Date: Tue May 16 18:48:31 2006 New Revision: 27284 Added: z3/hurry.query/trunk/setup.py Log: Preliminary setup.py. Added: z3/hurry.query/trunk/setup.py ============================================================================== --- (empty file) +++ z3/hurry.query/trunk/setup.py Tue May 16 18:48:31 2006 @@ -0,0 +1,24 @@ +from setuptools import setup, find_packages + +setup( + name="hurry.query", + version="0.8.1", + packages=find_packages('src', exclude=["*.tests", "*.ftests"]), + + package_dir= {'':'src'}, + + namespace_packages=['hurry'], + package_data = { + '': ['*.txt', '*.zcml'], + }, + + zip_safe=False, + author='Infrae', + author_email='faassen at infrae.com', + description="""\ +hurry.query is a higher level query system built on top of the Zope 3 +catalog. It makes it easy to perform catalog queries in Zope 3 code. +""", + license='BSD', + keywords="zope zope3", + ) From faassen at codespeak.net Tue May 16 18:50:23 2006 From: faassen at codespeak.net (faassen at codespeak.net) Date: Tue, 16 May 2006 18:50:23 +0200 (CEST) Subject: [z3-checkins] r27285 - z3/hurry.query/trunk/src/hurry Message-ID: <20060516165023.6537B10069@code0.codespeak.net> Author: faassen Date: Tue May 16 18:50:22 2006 New Revision: 27285 Modified: z3/hurry.query/trunk/src/hurry/__init__.py Log: Helpful when we want to make an egg out of this. Modified: z3/hurry.query/trunk/src/hurry/__init__.py ============================================================================== --- z3/hurry.query/trunk/src/hurry/__init__.py (original) +++ z3/hurry.query/trunk/src/hurry/__init__.py Tue May 16 18:50:22 2006 @@ -1 +1,5 @@ -# this is a package +# this is a namespace package +try: + __import__('pkg_resources').declare_namespace(__name__) +except ImportError: + pass From faassen at codespeak.net Tue May 16 18:50:37 2006 From: faassen at codespeak.net (faassen at codespeak.net) Date: Tue, 16 May 2006 18:50:37 +0200 (CEST) Subject: [z3-checkins] r27286 - z3/hurry.query/trunk Message-ID: <20060516165037.8D02410069@code0.codespeak.net> Author: faassen Date: Tue May 16 18:50:36 2006 New Revision: 27286 Modified: z3/hurry.query/trunk/CHANGES.txt Log: Update this and go to 0.9. Modified: z3/hurry.query/trunk/CHANGES.txt ============================================================================== --- z3/hurry.query/trunk/CHANGES.txt (original) +++ z3/hurry.query/trunk/CHANGES.txt Tue May 16 18:50:36 2006 @@ -1,10 +1,12 @@ hurry changes ============= -0.8.1 (under development) +0.9 (under development) ------------------------- -Separate hurry.query from the rest. +* Separate hurry.query from the other hurry packages. Eggification work. + +* Support for ValueIndex from zc.catalog. 0.8 (2006-05-01) ---------------- From faassen at codespeak.net Tue May 16 18:52:19 2006 From: faassen at codespeak.net (faassen at codespeak.net) Date: Tue, 16 May 2006 18:52:19 +0200 (CEST) Subject: [z3-checkins] r27287 - z3/hurry.query/trunk Message-ID: <20060516165219.B694110069@code0.codespeak.net> Author: faassen Date: Tue May 16 18:52:18 2006 New Revision: 27287 Modified: z3/hurry.query/trunk/setup.py Log: Correct version number. Modified: z3/hurry.query/trunk/setup.py ============================================================================== --- z3/hurry.query/trunk/setup.py (original) +++ z3/hurry.query/trunk/setup.py Tue May 16 18:52:18 2006 @@ -2,7 +2,7 @@ setup( name="hurry.query", - version="0.8.1", + version="0.9", packages=find_packages('src', exclude=["*.tests", "*.ftests"]), package_dir= {'':'src'}, From faassen at codespeak.net Tue May 16 18:52:44 2006 From: faassen at codespeak.net (faassen at codespeak.net) Date: Tue, 16 May 2006 18:52:44 +0200 (CEST) Subject: [z3-checkins] r27288 - z3/hurry.query/trunk Message-ID: <20060516165244.98F0310069@code0.codespeak.net> Author: faassen Date: Tue May 16 18:52:43 2006 New Revision: 27288 Modified: z3/hurry.query/trunk/CHANGES.txt Log: Prepare for release. Modified: z3/hurry.query/trunk/CHANGES.txt ============================================================================== --- z3/hurry.query/trunk/CHANGES.txt (original) +++ z3/hurry.query/trunk/CHANGES.txt Tue May 16 18:52:43 2006 @@ -1,8 +1,8 @@ hurry changes ============= -0.9 (under development) -------------------------- +0.9 (2006-05-16) +---------------- * Separate hurry.query from the other hurry packages. Eggification work. From faassen at codespeak.net Tue May 16 19:06:44 2006 From: faassen at codespeak.net (faassen at codespeak.net) Date: Tue, 16 May 2006 19:06:44 +0200 (CEST) Subject: [z3-checkins] r27289 - z3/hurry.query/tag Message-ID: <20060516170644.96BB01006E@code0.codespeak.net> Author: faassen Date: Tue May 16 19:06:43 2006 New Revision: 27289 Added: z3/hurry.query/tag/ Log: Create tag directory. From faassen at codespeak.net Tue May 16 19:06:52 2006 From: faassen at codespeak.net (faassen at codespeak.net) Date: Tue, 16 May 2006 19:06:52 +0200 (CEST) Subject: [z3-checkins] r27290 - z3/hurry.query/tag/hurry.query-0.9 Message-ID: <20060516170652.7E22510078@code0.codespeak.net> Author: faassen Date: Tue May 16 19:06:51 2006 New Revision: 27290 Added: z3/hurry.query/tag/hurry.query-0.9/ - copied from r27289, z3/hurry.query/trunk/ Log: Tag hurry.query 0.9. From regebro at codespeak.net Wed May 17 14:32:52 2006 From: regebro at codespeak.net (regebro at codespeak.net) Date: Wed, 17 May 2006 14:32:52 +0200 (CEST) Subject: [z3-checkins] r27355 - z3/www/trunk Message-ID: <20060517123252.C55EC10063@code0.codespeak.net> Author: regebro Date: Wed May 17 14:32:51 2006 New Revision: 27355 Modified: z3/www/trunk/mkwebsite.py z3/www/trunk/publish.py Log: Added the possibility to specify decoding for some pages. I think this is needed for newer versions of docutils. Modified: z3/www/trunk/mkwebsite.py ============================================================================== --- z3/www/trunk/mkwebsite.py (original) +++ z3/www/trunk/mkwebsite.py Wed May 17 14:32:51 2006 @@ -85,8 +85,8 @@ site.registerPages( [ - publish.FileRstPage('text/index.txt'), - publish.FileRstPage('text/submission_guidelines.txt'), + publish.FileRstPage('text/index.txt', encoding='ascii'), + publish.FileRstPage('text/submission_guidelines.txt', encoding='ascii'), ], site.getRootLayouter(), '.', Modified: z3/www/trunk/publish.py ============================================================================== --- z3/www/trunk/publish.py (original) +++ z3/www/trunk/publish.py Wed May 17 14:32:51 2006 @@ -63,6 +63,7 @@ def save(self): """Save this resource. """ + print "Saving", self._destination_path try: os.makedirs(os.path.dirname(self._destination_path)) except os.error: @@ -124,14 +125,19 @@ return layouter.render(**kw) class RstPage(BasePage): + def __init__(self, data_source, name=None, encoding='ascii'): + BasePage.__init__(self, data_source, name=name) + self.encoding = encoding + def getData(self): - return html_parts(self._data, initial_header_level=2) + return html_parts(self._data, initial_header_level=2, + input_encoding=self.encoding) class FileRstPage(RstPage): """Convenience way to create a RstPage from file. """ - def __init__(self, path, name=None): - RstPage.__init__(self, PathSource(path), name) + def __init__(self, path, name=None, encoding='unicode'): + RstPage.__init__(self, PathSource(path), name, encoding=encoding) class SimplePage(BasePage): def __init__(self, name): From tseaver at codespeak.net Fri May 19 03:13:00 2006 From: tseaver at codespeak.net (tseaver at codespeak.net) Date: Fri, 19 May 2006 03:13:00 +0200 (CEST) Subject: [z3-checkins] r27435 - z3/CMFonFive/trunk Message-ID: <20060519011300.5575B1006E@code0.codespeak.net> Author: tseaver Date: Fri May 19 03:12:56 2006 New Revision: 27435 Modified: z3/CMFonFive/trunk/CHANGES.txt Log: Normalize STX, long lines. Modified: z3/CMFonFive/trunk/CHANGES.txt ============================================================================== --- z3/CMFonFive/trunk/CHANGES.txt (original) +++ z3/CMFonFive/trunk/CHANGES.txt Fri May 19 03:12:56 2006 @@ -1,35 +1,36 @@ CMFonFive Product Changelog CMFonFive 1.3.3 (unreleased) - - Got rid of some i18n warnings. - - - Fixed an incorrect import so it works in Zope 2.10 as well. - - The id of the action is now generated from the last part of the interface - the menu item is defined for, and the last part of the action. This should - generate enough uniqueness so that action id's does not clash too much, while - never generating two different ids. + - Got rid of some i18n warnings. + + - Fixed an incorrect import so it works in Zope 2.10 as well. + + - The id of the action is now generated from the last part of the interface + the menu item is defined for, and the last part of the action. This + should generate enough uniqueness so that action id's does not clash too + much, while never generating two different ids. - The reason for this change is that it enables you to add icons with the CMF - ActionIconsTool. + The reason for this change is that it enables you to add icons with the + CMF ActionIconsTool. - - GenericSetup is now optional. + - GenericSetup is now optional. CMFonFive 1.3.2 (2006-02-22) - - GenericSetup calls all action providers with both object and info - as None, which resulted in an attribute error. + - GenericSetup calls all action providers with both object and info + as None, which resulted in an attribute error. + + - Added a GenericSetup profile. This means you need to use CMF 1.6.0 or + later, or download and install GenericSetup. - - Added a GenericSetup profile. This means you need to use CMF 1.6.0 or - later, or download and install GenericSetup. - - - Got rid of a deprecation warning for product_name. + - Got rid of a deprecation warning for product_name. CMFonFive 1.3.1 (2006-02-10) - - The new zope.i18nmessageid.Message is actually a subclass of unicode, - so the test to make sure it was not a Message or a MessageID competely - failed, making menu item titles untranslated. + - The new zope.i18nmessageid.Message is actually a subclass of unicode, + so the test to make sure it was not a Message or a MessageID competely + failed, making menu item titles untranslated. CMFonFive 1.3.0 (2006-01-05) From jinty at codespeak.net Fri May 26 12:52:10 2006 From: jinty at codespeak.net (jinty at codespeak.net) Date: Fri, 26 May 2006 12:52:10 +0200 (CEST) Subject: [z3-checkins] r27720 - z3/sqlos/branch/jinty-sqlobject2/src/sqlos/testing Message-ID: <20060526105210.3D8E510076@code0.codespeak.net> Author: jinty Date: Fri May 26 12:52:08 2006 New Revision: 27720 Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/testing/sampleperson.py Log: Covert some of the test infrastructure from SQLOS -> SQLObject. Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/testing/sampleperson.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/testing/sampleperson.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/testing/sampleperson.py Fri May 26 12:52:08 2006 @@ -4,7 +4,6 @@ from zope.schema import TextLine, Text, Datetime from zope.app.container import constraints -from sqlos.zsqlobject import SQLOS from sqlos.interfaces import ISQLSchema, IISQLObjectIsolated, ISQLObjectIsolated from sqlos.interfaces.container import ISQLObjectContainer from sqlos.container import SQLObjectContainer, SQLIsolatedContainer @@ -55,7 +54,7 @@ implements(IPersonContainer) -class SamplePerson(SQLOS): +class SamplePerson(SQLObject): implements(IPerson, IPersonContained) @@ -64,7 +63,7 @@ password = StringCol(length=20, notNull=1) -class SampleIsolatedPerson(SQLOS): +class SampleIsolatedPerson(SQLObject): classProvides(IISQLObjectIsolated) implements(IPerson, ISQLObjectIsolated) @@ -120,7 +119,7 @@ description=u'The username of the dog\'s owner') -class Dog(SQLOS): +class Dog(SQLObject): implements(IDog) From jinty at codespeak.net Fri May 26 12:53:51 2006 From: jinty at codespeak.net (jinty at codespeak.net) Date: Fri, 26 May 2006 12:53:51 +0200 (CEST) Subject: [z3-checkins] r27721 - z3/sqlos/branch/jinty-sqlobject2/src/sqlos Message-ID: <20060526105351.D269C10077@code0.codespeak.net> Author: jinty Date: Fri May 26 12:53:49 2006 New Revision: 27721 Removed: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/meta.zcml z3/sqlos/branch/jinty-sqlobject2/src/sqlos/metaconfigure.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/metadirectives.py Log: Delete the zcml configuration. I am hoping not to be able to use plain utility directives in future. Deleted: /z3/sqlos/branch/jinty-sqlobject2/src/sqlos/meta.zcml ============================================================================== --- /z3/sqlos/branch/jinty-sqlobject2/src/sqlos/meta.zcml Fri May 26 12:53:49 2006 +++ (empty file) @@ -1,21 +0,0 @@ - - - - - - - - - - - Deleted: /z3/sqlos/branch/jinty-sqlobject2/src/sqlos/metaconfigure.py ============================================================================== --- /z3/sqlos/branch/jinty-sqlobject2/src/sqlos/metaconfigure.py Fri May 26 12:53:49 2006 +++ (empty file) @@ -1,75 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004 Enfold Systems LLC. All rights reserved. -# -# This software is distributed under the terms of the Zope Public -# License (ZPL) v2.1. See COPYING.txt for more information. -# -############################################################################## -""" -$Id: __init__.py 5216 2004-06-21 18:33:07Z dreamcatcher $ -""" - -from zope.interface.verify import verifyClass -from zope.interface import directlyProvides, implements -from zope.app.component.metaconfigure import utility, PublicPermission, proxify -from zope.security.checker import defineChecker, Checker -from zope.security.checker import getCheckerForInstancesOf, MultiChecker -from zope.component.factory import Factory, IFactory -from sqlos.interfaces import IISQLObject, IConnectionName -from sqlos.interfaces import IReadSQLObjectClass, IWriteSQLObjectClass - -def handler(_context, component, id, title=None, description=None): - if isinstance(component, basestring): - component = _context.resolve(component) - - factoryObj = Factory(component, title, description) - - # XXX We compute a permission name from the package top-level name - # plus the component (which should be a class) __name__ The - # permission should probably be part of the directive here. - package = component.__module__.split('.')[0] - add_perm = '%s.Add%s' % (package, component.__name__) - utility(_context, IFactory, factoryObj, - permission=add_perm, name=id) - - if not IISQLObject.providedBy(component): - if verifyClass(IISQLObject, component, tentative=1): - directlyProvides(component, IISQLObject) - - # XXX We are really creating a proxy for the *class* here. - # However, we don't want to modify the class, and we don't want - # this to conflict with the checker created by the - # directive, so we create a Proxy using a checker with computed - # permission names. The permissions should probably be part of - # the directive. - - checker = getCheckerForInstancesOf(component) - if checker is None: - read_perm = '%s.View%s' % (package, component.__name__) - change_perm = '%s.Change%s' % (package, component.__name__) - checker = MultiChecker(((IReadSQLObjectClass, read_perm), - (IWriteSQLObjectClass, change_perm), - )) - checker = Checker(checker.get_permissions, {}) - defineChecker(component, checker) - - proxied = proxify(component, checker) - - # XXX We pass permission=None here so that the utility handler - # doesn't override what we've just did above. - utility(_context, IISQLObject, proxied, - permission=None, name=id) - -class ConnectionName: - """A connection name utility""" - - implements(IConnectionName) - - def __init__(self, name): - self.name = name - -def connectionName(_context, name): - component = ConnectionName(name) - utility(_context, IConnectionName, component, - permission=PublicPermission, name='') Deleted: /z3/sqlos/branch/jinty-sqlobject2/src/sqlos/metadirectives.py ============================================================================== --- /z3/sqlos/branch/jinty-sqlobject2/src/sqlos/metadirectives.py Fri May 26 12:53:49 2006 +++ (empty file) @@ -1,51 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004 Enfold Systems LLC. All rights reserved. -# -# This software is distributed under the terms of the Zope Public -# License (ZPL) v2.1. See COPYING.txt for more information. -# -############################################################################## -""" -$Id: __init__.py 5216 2004-06-21 18:33:07Z dreamcatcher $ -""" - -from zope.interface import Interface -from zope.configuration.fields import GlobalObject, MessageID -from zope.schema import TextLine - -class IConnectionName(Interface): - - name = TextLine( - title=u"Connection Name", - required=True - ) - -class IFactoryDirective(Interface): - """ - Define a factory - """ - - component = GlobalObject( - title=u"Component to be used", - required=True - ) - - id = TextLine( - title=u"ID", - required=False - ) - - title = MessageID( - title=u"Title", - description=u""" - text suitable for use in the 'add content' menu of a - management interface""", - required=False - ) - - description = MessageID( - title=u"Description", - description=u"Longer narrative description of what this factory does", - required=False - ) From jinty at codespeak.net Fri May 26 20:54:25 2006 From: jinty at codespeak.net (jinty at codespeak.net) Date: Fri, 26 May 2006 20:54:25 +0200 (CEST) Subject: [z3-checkins] r27738 - in z3/sqlos/branch/jinty-sqlobject2: . src/sqlos src/sqlos/ftests src/sqlos/testing src/sqlos/tests Message-ID: <20060526185425.2502610092@code0.codespeak.net> Author: jinty Date: Fri May 26 20:54:17 2006 New Revision: 27738 Added: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/meta.zcml - copied unchanged from r27720, z3/sqlos/branch/jinty-sqlobject2/src/sqlos/meta.zcml z3/sqlos/branch/jinty-sqlobject2/src/sqlos/metaconfigure.py - copied unchanged from r27720, z3/sqlos/branch/jinty-sqlobject2/src/sqlos/metaconfigure.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/metadirectives.py - copied unchanged from r27720, z3/sqlos/branch/jinty-sqlobject2/src/sqlos/metadirectives.py Modified: z3/sqlos/branch/jinty-sqlobject2/makefile z3/sqlos/branch/jinty-sqlobject2/src/sqlos/_transaction.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/configure.zcml z3/sqlos/branch/jinty-sqlobject2/src/sqlos/connection.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/container.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftesting.zcml z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/test_transaction.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/testing/sampleperson.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/testing/testdb.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/tests/test_doctests.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/tests/test_transaction.py Log: Do a huge wack of porting, unit tests work now, functional tests not. We only support sqlite at the moment;) Modified: z3/sqlos/branch/jinty-sqlobject2/makefile ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/makefile (original) +++ z3/sqlos/branch/jinty-sqlobject2/makefile Fri May 26 20:54:17 2006 @@ -45,7 +45,7 @@ cp $< $@ .PHONY: sqlos-meta -sqlos-meta: $(z3includes)/sqlos-meta.zcml $(z3includes)/sqlos-configure.zcml $(z3includes)/sqlos-ftesting.zcml +sqlos-meta: $(z3includes)/sqlos-configure.zcml $(z3includes)/sqlos-ftesting.zcml .PHONY: Zope3-build Zope3-build: Zope3 Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/_transaction.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/_transaction.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/_transaction.py Fri May 26 20:54:17 2006 @@ -28,81 +28,10 @@ import transaction from transaction.interfaces import ISynchronizer from zope.interface import implements -from sqlobject.cache import CacheSet from zope.thread import local from sqlos.interfaces import ISQLObject - -class CacheSynchronizer: - """Synchronizer to expire the Global per thread cache at transaction start. - - Basically just an adapter for sqlobject.cache.CacheSet. - - Lets make a stub context: - - >>> class CacheStub: - ... def __init__(self, name): - ... self.name = name - ... def clear(self): - ... print 'clearing %s' % self.name - >>> class CacheSetStub: - ... def allSubCaches(self): - ... return self.caches - >>> cache_set_stub = CacheSetStub() - >>> cache_set_stub.caches = [CacheStub('cache 1'), CacheStub('cache 2')] - - Let's check that it implements the interface correctly: - - >>> from zope.interface import verify - >>> synch = CacheSynchronizer(cache_set_stub) - >>> verify.verifyObject(ISynchronizer, synch) - True - - Nothing Happens before or after transactions: - - >>> synch.beforeCompletion('fake txn') - >>> synch.afterCompletion('fake txn') - - But on new transactions, the cache is cleared: - - >>> synch.newTransaction('fake txn') - clearing cache 1 - clearing cache 2 - """ - # XXX this is probably the wrong place to put this code. - implements(ISynchronizer) - - def __init__(self, context): - # context must be a CacheSet but SQLObject aint goit interfaces - self.context = context - - def afterCompletion(self, transaction): - pass - - def beforeCompletion(self, transaction): - pass - - def newTransaction(self, transaction): - for cache in self.context.allSubCaches(): - cache.clear() # Blech, not optimal, don't know what is. - # expireAll, doesn't expire the objects. - - -class ThreadedCacheManager(local): - - def __init__(self): - self.cache = CacheSet() # one cache per thread - # we need to keep a solid reference to the synchronizer, because the - # transaction manager only keeps weak ones - self._synch = CacheSynchronizer(self.cache) - transaction.manager.registerSynch(self._synch) - -cache_manager = ThreadedCacheManager() # this should be a utility? - # waa actually I don't like this at all - # there must be a dead simple way. - - class DirtyObjectRegistry(local): """A thread local registry of dirty SQLObjects. @@ -266,7 +195,10 @@ while self._objects: obj = self._objects.pop() if not obj.sqlmeta._obsolete: - obj.syncUpdate() + # XXX: we don't need the sync, just syncUpdate, but SQLObject2 + # doesn't support that yet + #obj.syncUpdate() + obj.sync() def _addBeforeCommitHook(self): self._txn.addBeforeCommitHook(self.syncUpdateAll, ()) Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/configure.zcml ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/configure.zcml (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/configure.zcml Fri May 26 20:54:17 2006 @@ -33,7 +33,7 @@ @@ -41,20 +41,20 @@ - + + -
+ --> - - - - - - >> get().commit() >>> txn = begin() >>> person.username - 'andres' + u'andres' And finally call tearDown and cleanup: From jinty at codespeak.net Fri May 26 20:57:20 2006 From: jinty at codespeak.net (jinty at codespeak.net) Date: Fri, 26 May 2006 20:57:20 +0200 (CEST) Subject: [z3-checkins] r27739 - z3/sqlos/branch/jinty-sqlobject2/src/sqlos Message-ID: <20060526185720.4736B10097@code0.codespeak.net> Author: jinty Date: Fri May 26 20:57:18 2006 New Revision: 27739 Removed: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/meta.zcml z3/sqlos/branch/jinty-sqlobject2/src/sqlos/metaconfigure.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/metadirectives.py Log: oops Deleted: /z3/sqlos/branch/jinty-sqlobject2/src/sqlos/meta.zcml ============================================================================== --- /z3/sqlos/branch/jinty-sqlobject2/src/sqlos/meta.zcml Fri May 26 20:57:18 2006 +++ (empty file) @@ -1,21 +0,0 @@ - - - - - - - - - - - Deleted: /z3/sqlos/branch/jinty-sqlobject2/src/sqlos/metaconfigure.py ============================================================================== --- /z3/sqlos/branch/jinty-sqlobject2/src/sqlos/metaconfigure.py Fri May 26 20:57:18 2006 +++ (empty file) @@ -1,75 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004 Enfold Systems LLC. All rights reserved. -# -# This software is distributed under the terms of the Zope Public -# License (ZPL) v2.1. See COPYING.txt for more information. -# -############################################################################## -""" -$Id: __init__.py 5216 2004-06-21 18:33:07Z dreamcatcher $ -""" - -from zope.interface.verify import verifyClass -from zope.interface import directlyProvides, implements -from zope.app.component.metaconfigure import utility, PublicPermission, proxify -from zope.security.checker import defineChecker, Checker -from zope.security.checker import getCheckerForInstancesOf, MultiChecker -from zope.component.factory import Factory, IFactory -from sqlos.interfaces import IISQLObject, IConnectionName -from sqlos.interfaces import IReadSQLObjectClass, IWriteSQLObjectClass - -def handler(_context, component, id, title=None, description=None): - if isinstance(component, basestring): - component = _context.resolve(component) - - factoryObj = Factory(component, title, description) - - # XXX We compute a permission name from the package top-level name - # plus the component (which should be a class) __name__ The - # permission should probably be part of the directive here. - package = component.__module__.split('.')[0] - add_perm = '%s.Add%s' % (package, component.__name__) - utility(_context, IFactory, factoryObj, - permission=add_perm, name=id) - - if not IISQLObject.providedBy(component): - if verifyClass(IISQLObject, component, tentative=1): - directlyProvides(component, IISQLObject) - - # XXX We are really creating a proxy for the *class* here. - # However, we don't want to modify the class, and we don't want - # this to conflict with the checker created by the - # directive, so we create a Proxy using a checker with computed - # permission names. The permissions should probably be part of - # the directive. - - checker = getCheckerForInstancesOf(component) - if checker is None: - read_perm = '%s.View%s' % (package, component.__name__) - change_perm = '%s.Change%s' % (package, component.__name__) - checker = MultiChecker(((IReadSQLObjectClass, read_perm), - (IWriteSQLObjectClass, change_perm), - )) - checker = Checker(checker.get_permissions, {}) - defineChecker(component, checker) - - proxied = proxify(component, checker) - - # XXX We pass permission=None here so that the utility handler - # doesn't override what we've just did above. - utility(_context, IISQLObject, proxied, - permission=None, name=id) - -class ConnectionName: - """A connection name utility""" - - implements(IConnectionName) - - def __init__(self, name): - self.name = name - -def connectionName(_context, name): - component = ConnectionName(name) - utility(_context, IConnectionName, component, - permission=PublicPermission, name='') Deleted: /z3/sqlos/branch/jinty-sqlobject2/src/sqlos/metadirectives.py ============================================================================== --- /z3/sqlos/branch/jinty-sqlobject2/src/sqlos/metadirectives.py Fri May 26 20:57:18 2006 +++ (empty file) @@ -1,51 +0,0 @@ -############################################################################## -# -# Copyright (c) 2004 Enfold Systems LLC. All rights reserved. -# -# This software is distributed under the terms of the Zope Public -# License (ZPL) v2.1. See COPYING.txt for more information. -# -############################################################################## -""" -$Id: __init__.py 5216 2004-06-21 18:33:07Z dreamcatcher $ -""" - -from zope.interface import Interface -from zope.configuration.fields import GlobalObject, MessageID -from zope.schema import TextLine - -class IConnectionName(Interface): - - name = TextLine( - title=u"Connection Name", - required=True - ) - -class IFactoryDirective(Interface): - """ - Define a factory - """ - - component = GlobalObject( - title=u"Component to be used", - required=True - ) - - id = TextLine( - title=u"ID", - required=False - ) - - title = MessageID( - title=u"Title", - description=u""" - text suitable for use in the 'add content' menu of a - management interface""", - required=False - ) - - description = MessageID( - title=u"Description", - description=u"Longer narrative description of what this factory does", - required=False - ) From rocky at codespeak.net Sun May 28 23:58:46 2006 From: rocky at codespeak.net (rocky at codespeak.net) Date: Sun, 28 May 2006 23:58:46 +0200 (CEST) Subject: [z3-checkins] r27811 - in z3/pythonproducts/trunk: . src/pythonproducts Message-ID: <20060528215846.9CA2510057@code0.codespeak.net> Author: rocky Date: Sun May 28 23:37:55 2006 New Revision: 27811 Modified: z3/pythonproducts/trunk/ (props changed) z3/pythonproducts/trunk/src/pythonproducts/pythonproducts.py Log: Fixed up package loading to properly access last portion of package. Modified: z3/pythonproducts/trunk/src/pythonproducts/pythonproducts.py ============================================================================== --- z3/pythonproducts/trunk/src/pythonproducts/pythonproducts.py (original) +++ z3/pythonproducts/trunk/src/pythonproducts/pythonproducts.py Sun May 28 23:37:55 2006 @@ -119,7 +119,13 @@ for product_id in products.objectIds(): product = products[product_id] if hasattr(product, 'package_name'): - packages[product_id] = __import__(product.package_name) + pos = product.package_name.rfind('.') + if pos > -1: + packages[product_id] = __import__(product.package_name, + globals(), {}, + product.package_name[pos+1:]) + else: + packages[product_id] = __import__(product.package_name) elif old_product_packages.has_key(product_id): packages[product_id] = old_product_packages[product_id] @@ -173,12 +179,16 @@ return result try: - l = name.find('.') + l = name.rfind('.') if l > 0: realName = name[l + 1:] toplevel = name[:l] - m = __import__(toplevel) + pos = toplevel.rfind('.') + if pos > -1: + m = __import__(toplevel, globals(), {}, toplevel[pos+1:]) + else: + m = __import__(toplevel) d = os.path.join(m.__path__[0], prefix, realName) for s in suffixes: From jinty at codespeak.net Mon May 29 08:30:22 2006 From: jinty at codespeak.net (jinty at codespeak.net) Date: Mon, 29 May 2006 08:30:22 +0200 (CEST) Subject: [z3-checkins] r27816 - in z3/sqlos/branch/jinty-sqlobject2/src/sqlos: . ftests testing tests Message-ID: <20060529063022.7D73410063@code0.codespeak.net> Author: jinty Date: Mon May 29 08:29:49 2006 New Revision: 27816 Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/README.txt z3/sqlos/branch/jinty-sqlobject2/src/sqlos/_transaction.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/container.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftesting.zcml z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/connection.txt z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/containers.txt z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/isolated_containers.txt z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/test_transaction.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/testing/sampleperson.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/tests/test_doctests.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/zsqlobject.py Log: Loads of fix ups. Only one functional test still failing now. Of course the connections are still hard-wired. Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/README.txt ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/README.txt (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/README.txt Mon May 29 08:29:49 2006 @@ -230,13 +230,12 @@ >>> from zope.interface import implements >>> from sqlobject import * - >>> from sqlos.zsqlobject import SQLOS - >>> class Person(SQLOS): + >>> class Person(SQLObject): ... implements(IPerson) - ... username = StringCol('username', length=20, notNull=True) - ... fname = StringCol('fname', length=20, notNull=True) - ... lname = StringCol('lname', length=20, notNull=True) + ... username = StringCol(length=20, notNull=True) + ... fname = StringCol(length=20, notNull=True) + ... lname = StringCol(length=20, notNull=True) Here you can see that there is almost nothing special needed for making the object be recognized by Zope 3. In fact, if you remove the @@ -336,9 +335,9 @@ As always, the first step is to declare the interface:: >>> from zope.app.container.constraints import ItemTypePrecondition - >>> from sqlos.interfaces.container import ISQLObjectContainer + >>> from sqlos.interfaces import ISQLObjectContainer - >>> class IPersonContainer(ISQLObjectContainer) : + >>> class IPersonContainer(ISQLObjectContainer): ... ... def __setitem__(name, item) : ... pass @@ -351,7 +350,7 @@ >>> from sqlos.container import SQLObjectContainer - >>> class PersonContainer(SQLObjectContainer) : + >>> class PersonContainer(SQLObjectContainer): ... implements(IPersonContainer) All that needs to be done at this point is to connect an Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/_transaction.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/_transaction.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/_transaction.py Mon May 29 08:29:49 2006 @@ -44,6 +44,8 @@ ... _obsolete = False ... def __init__(self, name): ... self.name = name + ... def sync(self): + ... self.syncUpdate() ... def syncUpdate(self): ... synced.append(self.name) ... synced.sort() Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/container.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/container.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/container.py Mon May 29 08:29:49 2006 @@ -15,8 +15,7 @@ from sqlobject import * from persistent import Persistent -from zope.interface import implements -from zope.component import IFactory +from zope.interface import implements, providedBy, implementedBy import zope.component from zope.app.container.interfaces import IContained from zope.app.container.contained import ContainedProxy @@ -64,12 +63,8 @@ if ISQLObject.providedBy(obj): # Look for the SQLObject class our object is from, so get all # allowed factories - for name, factory in zope.component.getFactoriesFor(ISQLObject): - if checkFactory(self.context, None, factory): - # get the sqlobject class - utility = zope.component.queryUtility(IISQLObject, name) - if utility is None: - continue + for name, utility in zope.component.getUtilitiesFor(IISQLObject): + if checkUtility(self.context, None, utility): if obj.sqlmeta.table == utility.sqlmeta.table: # if the tables names are the same, we assume that the # sqlobject is an instance of that class, perhaps that @@ -77,6 +72,12 @@ return "%s.%s" % (name, obj.id) raise UserError("Cannot find a name") # XXX better message, i18n? +def checkUtility(container, name, utility): + """Check if a utility is allowed in a container.""" + assert ISQLObject.implementedBy(utility) + if not zope.component.interfaces.IFactory.providedBy(utility): + utility = zope.component.factory.Factory(utility) + return checkFactory(container, name, utility) class SQLObjectContainer(Persistent, Contained): @@ -86,15 +87,10 @@ pass def _getAllowedIISQLObjectUtilities(self): - for name, factory in zope.component.getFactoriesFor(ISQLObject): - if checkFactory(self, None, factory): - utility = zope.component.queryUtility(IISQLObject, name) - # Someone might have registered a factory implementing - # IISQLObject using for whatever reason. - # in this case queryUtility returns None and we can just - # ignore it - if utility is not None: - yield name, utility + utilities = zope.component.getUtilitiesFor(IISQLObject) + for name, utility in utilities: + if checkUtility(self, None, utility): + yield name, utility def keys(self): """ Return a sequence-like object containing the names @@ -188,7 +184,7 @@ Raises a KeyError if the object is not found. """ obj = self[name] - obj.destroySelf() + obj.destroy_self() def __setitem__(self, name, content): return name @@ -229,7 +225,7 @@ obj = self[name] domains = [d for d in obj.domains if d != self.container_id] if not domains: - obj.destroySelf() + obj.destroy_self() return obj.domains = tuple(domains) Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftesting.zcml ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftesting.zcml (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftesting.zcml Mon May 29 08:29:49 2006 @@ -19,7 +19,7 @@ /> @@ -67,7 +67,7 @@ @@ -107,7 +107,7 @@ Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/connection.txt ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/connection.txt (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/connection.txt Mon May 29 08:29:49 2006 @@ -1,58 +1,24 @@ Here we test how the connection descriptor works: - >>> from sqlos.connection import ConnectionDescriptor - >>> from sqlos.adapter import ConnectionAdapter - -Get the connection name defined in sqlos: - - >>> class Dummy: - ... connection = ConnectionDescriptor() - >>> dummy = Dummy() + >>> from sqlos.connection import ZopeConnectionHub + >>> hub = ZopeConnectionHub('testconnection') Assert that if we get a the real connection twice, we get the same low level connection: - >>> conn1 = dummy.connection.makeConnection() - >>> conn2 = dummy.connection.makeConnection() - >>> conn1 is conn2 - True - -getConnection gives us the same result: - - >>> conn2 = dummy.connection.getConnection() - >>> conn1 is conn2 + >>> conn1 = hub.get_connection() + >>> conn2 = hub.get_connection() + >>> conn1.raw_connection is conn2.raw_connection True But getting a connection in a different thread returns a different result: >>> log = [] >>> def f(): - ... log.append(dummy.connection.makeConnection()) + ... log.append(hub.get_connection()) >>> import threading >>> thread = threading.Thread(target=f) >>> thread.start() >>> thread.join() >>> log[0] is not conn1 True - -On a SQLOS object instance, the connection descriptor cannot be overridden: - - >>> from sqlos.testing import sampleperson - >>> sampleperson.createTestingTables() - - >>> from zope.app import zapi - >>> from sqlos.interfaces import IISQLObject - >>> SamplePerson = zapi.getUtility(IISQLObject, - ... u'sqlos.somename.SamplePerson') - >>> harry = SamplePerson(username='h', fullname='H', password='p') - - >>> tmpcon = harry._connection - >>> obj = 'x' - >>> harry._connection = obj - >>> harry._connection is not obj - True - >>> harry._connection = tmpcon # if this test fails, we don't want to break others - -CleanUp: - - >>> sampleperson.dropTestingTables() Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/containers.txt ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/containers.txt (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/containers.txt Mon May 29 08:29:49 2006 @@ -1,7 +1,7 @@ First let's get a container for sqlos objects: >>> from sqlos.testing import sampleperson - >>> from sqlos.interfaces.container import ISQLObjectContainer + >>> from sqlos.interfaces import ISQLObjectContainer >>> from zope.interface.verify import verifyObject >>> container = sampleperson.SamplePersonContainer() @@ -11,7 +11,7 @@ We are not in the business of letting errors pass silently, so looking inside we get a database error (it must be of the type DatabaseException): - >>> [i for i in container.items()] + XXX>>> [i for i in container.items()] Traceback (most recent call last): ... DatabaseException: ... @@ -63,10 +63,10 @@ >>> [i[0] for i in container.items()] [u'sqlos.somename.SamplePerson.1', u'sqlos.somename.SamplePerson.2'] - >>> [i[1] for i in container.items()] == [harry, sally] - True - >>> [i for i in container.values()] == [harry, sally] - True + >>> [i[1].username for i in container.items()] + [u'harry', u'sally'] + >>> [i.username for i in container.values()] + [u'harry', u'sally'] >>> [i for i in container.keys()] [u'sqlos.somename.SamplePerson.1', u'sqlos.somename.SamplePerson.2'] >>> [i for i in container] @@ -76,10 +76,10 @@ the instance: >>> harry_name = 'sqlos.somename.SamplePerson.%s' % harry.id - >>> container[harry_name] == harry - True - >>> container[unicode(harry_name)] == harry - True + >>> container[harry_name].username + u'harry' + >>> container[unicode(harry_name)].username + u'harry' Let's test to see what the container does with bad id's (must raise KeyError): @@ -90,8 +90,8 @@ You can get() as well: - >>> container.get(harry_name) == harry - True + >>> container.get(harry_name).username + u'harry' >>> container.get('sss', 'default') 'default' @@ -127,7 +127,7 @@ >>> fido = sampleperson.Dog(fullname='Fido', owner='sally') >>> len(multicontainer) 2 - >>> fido in [i for i in multicontainer.values()] + >>> u'Fido' in [i.fullname for i in multicontainer.values()] True CleanUp: Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/isolated_containers.txt ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/isolated_containers.txt (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/isolated_containers.txt Mon May 29 08:29:49 2006 @@ -1,7 +1,7 @@ First let's get a container for sqlos objects: >>> from sqlos.testing import sampleperson - >>> from sqlos.interfaces.container import IIsolatedSQLContainer + >>> from sqlos.interfaces import IIsolatedSQLContainer >>> from zope.interface.verify import verifyObject >>> container = sampleperson.SampleIsolatedPersonContainer() @@ -11,7 +11,7 @@ We are not in the business of letting errors pass silently, so looking inside we get a database error (it must be of the type DatabaseException): - >>> [i for i in container.items()] + XXX>>> [i for i in container.items()] Traceback (most recent call last): ... DatabaseException: ... @@ -72,10 +72,10 @@ >>> [i[0] for i in container.items()] [u'SampleIsolatedPerson.1', u'SampleIsolatedPerson.2'] - >>> [i[1] for i in container.items()] == [harry, sally] - True - >>> [i for i in container.values()] == [harry, sally] - True + >>> [i[1].username for i in container.items()] + [u'harry', u'sally'] + >>> [i.username for i in container.values()] + [u'harry', u'sally'] >>> [i for i in container.keys()] [u'SampleIsolatedPerson.1', u'SampleIsolatedPerson.2'] >>> [i for i in container] @@ -85,15 +85,15 @@ the instance: >>> harry_name = 'SampleIsolatedPerson.%s' % harry.id - >>> container[harry_name] == harry - True - >>> container[unicode(harry_name)] == harry - True + >>> container[harry_name].username + u'harry' + >>> container[unicode(harry_name)].username + u'harry' You can get() as well: - >>> container.get(harry_name) == harry - True + >>> container.get(harry_name).username + u'harry' >>> container.get('sss', 'default') 'default' @@ -115,27 +115,35 @@ And add harry to the second container as well: >>> container2['ignored'] = harry - >>> [i for i in container2.values()] == [harry] - True - >>> [i for i in container.values()] == [harry, sally] - True + >>> [i.username for i in container2.values()] + [u'harry'] + >>> [i.username for i in container.values()] + [u'harry', u'sally'] Finally lets delete harry from the first container: >>> del container[harry_name] - >>> [i for i in container2.values()] == [harry] - True - >>> [i for i in container.values()] == [sally] - True + >>> [i.username for i in container2.values()] + [u'harry'] + >>> [i.username for i in container.values()] + [u'sally'] + +Finally, lets delete harry completely + + >>> del container2[harry_name] + >>> [i.username for i in container2.values()] + [] + + TODO: make sure that harry is destroyed here If we make the ID's of the containers equal, then they will contain the same items: >>> container2.container_id = container.container_id - >>> [i for i in container2.values()] == [sally] - True - >>> [i for i in container.values()] == [sally] - True + >>> [i.username for i in container2.values()] + [u'sally'] + >>> [i.username for i in container.values()] + [u'sally'] TODO: when an object is removed from the last container containing it, we should check that it is removed from the DB Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/test_transaction.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/test_transaction.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/test_transaction.py Mon May 29 08:29:49 2006 @@ -15,12 +15,11 @@ import threading from transaction import get, begin -from zope.app.testing.functional import BrowserTestCase +from zope.app.testing.functional import BrowserTestCase, FunctionalTestCase import zope.component from zope.app.rdb.interfaces import IZopeDatabaseAdapter from sqlobject.manage.creation import create_tables -from sqlos.interfaces import IConnectionName from sqlos.testing.sampleperson import SamplePerson, test_hub __metaclass__ = type @@ -39,7 +38,8 @@ begin() def supportTransactions(self): - return SamplePerson._connection.supportTransactions + #return SamplePerson._connection.supportTransactions + return True def testChange(self): person = SamplePerson.get(self.personid) @@ -80,7 +80,6 @@ person.fullname = 'Sidnei Silva' person.username = 'dreamcatcher' person.password = 'pass' - assert person.dirty is True person.sync() # Sync to ensure that the DB is sent the SQL statements get().abort() begin() @@ -117,7 +116,6 @@ person = SamplePerson.get(self.personid) self.assertEqual(person.fullname, 'Sidnei da Silva') person.fullname = 'Sidnei Silva' - assert person.dirty is True person.sync() # Sync to ensure that the DB is sent the SQL # abort transaction and start a new one get().abort() @@ -129,7 +127,6 @@ username='brian', password='test') brian.fullname = "B. Sutherland" # make the object dirty - assert brian.dirty is True brianid = brian.id # commit the second transaction get().commit() @@ -232,9 +229,18 @@ get().commit() begin() +class TestLocalConnectionUtilities(FunctionalTestCase): + + def traverseOverSite(self, site): + pass + + def getDummySite(self): + """Make and return a dummy site for testing.""" + def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(TestTransaction)) + suite.addTest(unittest.makeSuite(TestLocalConnectionUtilities)) return suite Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces.py Mon May 29 08:29:49 2006 @@ -10,9 +10,10 @@ $Id: adapter.py 5212 2004-06-21 18:09:05Z philikon $ """ +from sqlobject import SQLObject from zope.schema import TextLine from zope.interface import Interface, Attribute -from zope.interface import Attribute +from zope.interface import classImplements, alsoProvides from zope.app.container.constraints import ItemTypePrecondition from zope.app.annotation.interfaces import IAttributeAnnotatable from zope.app.container.interfaces import IContainerNamesContainer @@ -38,17 +39,14 @@ "database table.") -class IConnectionName(Interface): - """A marker interface for providing a connection name""" - - name = TextLine( - title=u"Connection Name", - required=True - ) - - class IISQLObject(Interface): - """Class methods for SQLObject classes.""" + """Class methods for SQLObject classes. + + >>> IISQLObject.providedBy(SQLObject) + True + + """ + class ISQLAPIConnection(Interface): """A marker interface for SQL API connections""" @@ -75,9 +73,14 @@ """Marker interface for SQLObjects. Hopefully one day this will be a real interface in SQLObject. + + >>> ISQLObject.implementedBy(SQLObject) + True """ - +classImplements(SQLObject, ISQLObject) + + class ISQLObjectIsolated(ISQLObject): domains = Attribute("A _tuple_ of containers_ids which contain this object") Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/testing/sampleperson.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/testing/sampleperson.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/testing/sampleperson.py Mon May 29 08:29:49 2006 @@ -9,7 +9,7 @@ from sqlos.container import SQLObjectContainer, SQLIsolatedContainer from sqlos.connection import ZopeConnectionHub -test_hub = ZopeConnectionHub('sqlite') +test_hub = ZopeConnectionHub('testconnection') def createTestingTablesSubscriber(obj): # An event subscriber that can be used to create the testing tables Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/tests/test_doctests.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/tests/test_doctests.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/tests/test_doctests.py Mon May 29 08:29:49 2006 @@ -24,6 +24,7 @@ def test_suite(): return unittest.TestSuite([ DocTestSuite('sqlos.container', optionflags=doctest.ELLIPSIS), + DocTestSuite('sqlos.interfaces'), DocTestSuite('sqlos.connection'), DocTestSuite('sqlos._transaction'), ]) Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/zsqlobject.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/zsqlobject.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/zsqlobject.py Mon May 29 08:29:49 2006 @@ -14,7 +14,6 @@ from sqlobject.main import SQLObject from sqlobject import StringCol -from sqlos.connection import ConnectionDescriptor from sqlos.interfaces import ISQLObject from sqlos import _transaction From jinty at codespeak.net Mon May 29 08:53:14 2006 From: jinty at codespeak.net (jinty at codespeak.net) Date: Mon, 29 May 2006 08:53:14 +0200 (CEST) Subject: [z3-checkins] r27817 - in z3/sqlos/branch/jinty-sqlobject2/src/sqlos: . ftests Message-ID: <20060529065314.7CB4A10063@code0.codespeak.net> Author: jinty Date: Mon May 29 08:53:09 2006 New Revision: 27817 Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/localutilities.txt z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces.py Log: Fix some more tests Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/localutilities.txt ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/localutilities.txt (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/ftests/localutilities.txt Mon May 29 08:53:09 2006 @@ -25,8 +25,7 @@ Let's get the connection name: - >>> from sqlos.interfaces import IConnectionName - >>> connection_name = zapi.getUtility(IConnectionName).name + >>> connection_name = 'testconnection' Now we set up a local database utility @@ -63,19 +62,19 @@ there is currently no support for local sites in testcode. >>> cursor = localUtility().cursor() - >>> cursor.execute( + >>> r = cursor.execute( ... '''create table dog ( ... id integer primary key, ... fullname varchar(50) not null, ... owner varchar(20) not null)''') - >>> cursor.execute( + >>> r = cursor.execute( ... '''create table sample_isolated_person ( ... id integer primary key, ... domains text, ... fullname varchar(50) not null, ... username varchar(20) not null, ... password varchar(20) not null)''') - >>> cursor.execute( + >>> r = cursor.execute( ... '''create table sample_person ( ... id integer primary key, ... fullname varchar(50), @@ -114,6 +113,6 @@ And now try to see if the person has been actually created in the localUtility: >>> cursor = localUtility().cursor() - >>> cursor.execute("""select * from sample_person""") + >>> r = cursor.execute("""select * from sample_person""") >>> cursor.fetchone() [1, u'Bob', u'bob', u'obo'] Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/interfaces.py Mon May 29 08:53:09 2006 @@ -41,10 +41,6 @@ class IISQLObject(Interface): """Class methods for SQLObject classes. - - >>> IISQLObject.providedBy(SQLObject) - True - """ From jinty at codespeak.net Mon May 29 09:52:34 2006 From: jinty at codespeak.net (jinty at codespeak.net) Date: Mon, 29 May 2006 09:52:34 +0200 (CEST) Subject: [z3-checkins] r27821 - in z3/sqlos/branch/jinty-sqlobject2/src/sqlos: . testing Message-ID: <20060529075234.C162A10053@code0.codespeak.net> Author: jinty Date: Mon May 29 09:52:19 2006 New Revision: 27821 Added: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/events.py (contents, props changed) Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/__init__.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/_transaction.py z3/sqlos/branch/jinty-sqlobject2/src/sqlos/configure.zcml z3/sqlos/branch/jinty-sqlobject2/src/sqlos/testing/sampleperson.py Log: Enable lazy updates and connect up SQLObject events to SQLOS events. This breaks everything, not sure why yet. Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/__init__.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/__init__.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/__init__.py Mon May 29 09:52:19 2006 @@ -9,3 +9,27 @@ """ $Id$ """ + +from sqlobject import SQLObject +import sqlobject.events + +import sqlos.events + +# +# Connect SQLObject events to Zope3 events +# +SQLObject.event_hub.listen(sqlobject.events.RowCreateSignal, + sqlos.events.notifySQLObjectCreated, + weak=False) +SQLObject.event_hub.listen(sqlobject.events.RowDestroySignal, + sqlos.events.notifySQLObjectDirtied, + weak=False) +SQLObject.event_hub.listen(sqlobject.events.RowUpdateSignal, + sqlos.events.notifySQLObjectDirtied, + weak=False) +# +# Clean up the __init__.py +# +del SQLObject +del sqlos.events +del sqlobject.events Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/_transaction.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/_transaction.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/_transaction.py Mon May 29 09:52:19 2006 @@ -224,3 +224,6 @@ self._registered = False dirty_object_registry = DirtyObjectRegistry() + +def dirtyObjectSubscriber(event): + dirty_object_registry.register(event.object) Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/configure.zcml ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/configure.zcml (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/configure.zcml Mon May 29 09:52:19 2006 @@ -110,4 +110,9 @@ handler=".connection.clearCacheSubscriber" /> + + Added: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/events.py ============================================================================== --- (empty file) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/events.py Mon May 29 09:52:19 2006 @@ -0,0 +1,28 @@ +from zope.interface import implements +from zope.component.interfaces import ObjectEvent, IObjectEvent +from zope.event import notify +from sqlobject import SQLObject + +from sqlos.interfaces import ISQLObject + +class ISQLObjectDirtiedEvent(IObjectEvent): + """Event notifying of an SQLObject that was dirtied.""" + pass + +class SQLObjectDirtiedEvent(ObjectEvent): + + implements(ISQLObjectDirtiedEvent) + +# +# Functions to translate events from SQLObject events to zope events. +# +# In Zope we only have one event type, ISQLObjectDirtiedEvent. This can +# be further sub classed in future. +# + +def notifySQLObjectCreated(kwargs, post_funcs): + post_funcs.append(notifySQLObjectDirtied) + +def notifySQLObjectDirtied(object, *args): + assert ISQLObject.providedBy(object) # let's just be a bit suspicious + notify(SQLObjectDirtiedEvent(object)) Modified: z3/sqlos/branch/jinty-sqlobject2/src/sqlos/testing/sampleperson.py ============================================================================== --- z3/sqlos/branch/jinty-sqlobject2/src/sqlos/testing/sampleperson.py (original) +++ z3/sqlos/branch/jinty-sqlobject2/src/sqlos/testing/sampleperson.py Mon May 29 09:52:19 2006 @@ -63,6 +63,7 @@ class sqlmeta: connection_hub = test_hub + lazy = True fullname = StringCol(length=50, notNull=1) username = StringCol(length=20, notNull=1) @@ -76,6 +77,7 @@ class sqlmeta: connection_hub = test_hub + lazy = True # Using a StringCol for a list is probably not the right way to do things # from a Relational Database point of view, better would be some kind of @@ -138,6 +140,7 @@ class sqlmeta: connection_hub = test_hub + lazy = True fullname = StringCol(length=50, notNull=1) owner = StringCol(length=20, notNull=1) From rocky at codespeak.net Mon May 29 14:38:35 2006 From: rocky at codespeak.net (rocky at codespeak.net) Date: Mon, 29 May 2006 14:38:35 +0200 (CEST) Subject: [z3-checkins] r27843 - in z3/pythonproducts/trunk: . src/pythonproducts Message-ID: <20060529123835.29D9A10050@code0.codespeak.net> Author: rocky Date: Mon May 29 14:17:51 2006 New Revision: 27843 Modified: z3/pythonproducts/trunk/ (props changed) z3/pythonproducts/trunk/src/pythonproducts/pythonproducts.py Log: Made pythonproducts smarter and figuring out when it should patch zope and cmf. Modified: z3/pythonproducts/trunk/src/pythonproducts/pythonproducts.py ============================================================================== --- z3/pythonproducts/trunk/src/pythonproducts/pythonproducts.py (original) +++ z3/pythonproducts/trunk/src/pythonproducts/pythonproducts.py Mon May 29 14:17:51 2006 @@ -27,6 +27,11 @@ _zope_app = None +_original_initialize = None +_original__bobo_traverse__ = None +_originalGetPath = None +_originalListDefaultTypeInformation = None + def registerPackage(_context, package, initialize=None): """ZCML directive function for registering a python package product """ @@ -75,9 +80,37 @@ _zope_app = app global _zope_app - patch_ProductDispatcher__bobo_traverse__(app) - patch_externalmethod(app) - patch_listDefaultTypeInformation(app) + patch_zope = True + patch_cmf = True + + try: + # lets check to see if Zope itself has been fixed yet + from App.FactoryDispatcher import _product_packages + patch_zope = False + except ImportError: + patch_zope = True + + if patch_zope: + # make sure we're not using a Five that already has the patches + try: + from Products.Five import pythonproducts + patch_zope = False + except ImportError: + patch_zope = True + + try: + # make sure CMF has been installed before we try patching it + from Products.CMFCore.TypesTool import TypesTool + patch_cmf = True + except ImportError, e: + patch_cmf = False + + if patch_zope: + patch_ProductDispatcher__bobo_traverse__(app) + patch_externalmethod(app) + + if patch_cmf: + patch_listDefaultTypeInformation(app) def removePatches(): """Remove any monkey patches that had been applied @@ -87,16 +120,15 @@ from App import Extensions, FactoryDispatcher from Products.ExternalMethod import ExternalMethod - ProductDispatcher.__bobo_traverse__ = _original__bobo_traverse__ - Extensions.getPath = _originalGetPath - Products.Five.initialize = _original_initialize - - try: + if _original__bobo_traverse__ is not None: + ProductDispatcher.__bobo_traverse__ = _original__bobo_traverse__ + if _originalGetPath is not None: + Extensions.getPath = _originalGetPath + if _original_initialize is not None: + Products.Five.initialize = _original_initialize + if _originalListDefaultTypeInformation is not None: from Products.CMFCore.TypesTool import TypesTool TypesTool.listDefaultTypeInformation = _originalListDefaultTypeInformation - except ImportError, e: - # don't continue trying to monkey patch CMF if it doesn't exist - pass # BEGIN MONKEY PATCHES @@ -139,8 +171,8 @@ """ from App.FactoryDispatcher import FactoryDispatcher, ProductDispatcher - _original__bobo_traverse__ = ProductDispatcher.__bobo_traverse__ global _original__bobo_traverse__ + _original__bobo_traverse__ = ProductDispatcher.__bobo_traverse__ def __bobo_traverse__(self, REQUEST, name): product=self.aq_acquire('_getProducts')()._product(name) @@ -167,8 +199,8 @@ from App import Extensions, FactoryDispatcher from Products.ExternalMethod import ExternalMethod - _originalGetPath = Extensions.getPath global _originalGetPath + _originalGetPath = Extensions.getPath def getPath(prefix, name, checkProduct=1, suffixes=('',)): """Make sure to check paths of all registered product packages. @@ -208,14 +240,10 @@ be extended to check the regular prooduct packages as well. """ - try: - from Products.CMFCore.TypesTool import TypesTool - except ImportError, e: - # don't continue trying to monkey patch CMF if it doesn't exist - return - - _originalListDefaultTypeInformation = TypesTool.listDefaultTypeInformation + from Products.CMFCore.TypesTool import TypesTool + global _originalListDefaultTypeInformation + _originalListDefaultTypeInformation = TypesTool.listDefaultTypeInformation from Acquisition import aq_base @@ -263,6 +291,6 @@ _original_initialize(context) - _original_initialize = Products.Five.initialize global _original_initialize + _original_initialize = Products.Five.initialize Products.Five.initialize = initialize From rocky at codespeak.net Mon May 29 21:13:21 2006 From: rocky at codespeak.net (rocky at codespeak.net) Date: Mon, 29 May 2006 21:13:21 +0200 (CEST) Subject: [z3-checkins] r27880 - z3/pythonproducts/trunk Message-ID: <20060529191321.8431410053@code0.codespeak.net> Author: rocky Date: Mon May 29 20:58:40 2006 New Revision: 27880 Modified: z3/pythonproducts/trunk/ (props changed) z3/pythonproducts/trunk/README.txt Log: Fixed a documentation error where it was stated to use instead of for a zcml slug. Modified: z3/pythonproducts/trunk/README.txt ============================================================================== --- z3/pythonproducts/trunk/README.txt (original) +++ z3/pythonproducts/trunk/README.txt Mon May 29 20:58:40 2006 @@ -35,7 +35,7 @@ 2. copy your python package to ``$INSTANCE_HOME/lib/python`` 3. create a ZCML "slug" by creating the file ``$INSTANCE_HOME/etc/package-includes/yourpackage-configure.zcml`` and - populating it with ```` + populating it with ```` Explanation of Usage Step 1: Your python package needs to register itself as a Zope 2 product. From philikon at codespeak.net Mon May 29 23:22:25 2006 From: philikon at codespeak.net (philikon at codespeak.net) Date: Mon, 29 May 2006 23:22:25 +0200 (CEST) Subject: [z3-checkins] r27883 - z3/www/trunk/text Message-ID: <20060529212225.C33CC10063@code0.codespeak.net> Author: philikon Date: Mon May 29 23:22:21 2006 New Revision: 27883 Added: z3/www/trunk/text/five_releasefest2.txt - copied, changed from r27882, z3/www/trunk/text/five_releasefest.txt Log: 2nd five release fest Copied: z3/www/trunk/text/five_releasefest2.txt (from r27882, z3/www/trunk/text/five_releasefest.txt) ============================================================================== --- z3/www/trunk/text/five_releasefest.txt (original) +++ z3/www/trunk/text/five_releasefest2.txt Mon May 29 23:22:21 2006 @@ -1,9 +1,9 @@ -Five 1.2.4, 1.3.5, 1.4c and 1.5b released! -========================================== +Five release fest: Five 1.2.5, 1.3.6, 1.4 and 1.5c released! +============================================================ The Five team is happy to announce the release of two Five bugfix -releases, 1.2.4 and 1.3.5, as well as two Five betas, 1.4c and 1.5b -today. +releases, 1.2.5 and 1.3.6, a Five 1.4 final release and another Five +1.5c beta release today. What is Five @@ -55,17 +55,20 @@ Kerrin for making this possible! -Changes in Five 1.2.4/1.3.5 and 1.4c (compared to 1.4b) -------------------------------------------------------- +Changes in Five 1.2.5, 1.3.6, 1.4 (compared to 1.4c), 1.5c (compare to 1.5b) +---------------------------------------------------------------------------- -* Made sure that events are fired as expected in add and edit forms. +* Fixed an issue where based views that didn't have + template or attribute defined weren't getting BrowserView mixed in. -* Made sure LocalizerLanguages class normalized language codes to - xx-yy, instead of xx_YY or xx-YY. +* Fixed an issue where new-style classes could not be used for + view components with . -* Fixed a problem with the new traversal look-up order and the root - object (OFS.Application.Application). +* Five.testbrowser does not swallow cookies anymore, based on patch by + Daniel Nouri. +* Five.testbrowser capitalizes headers in the same way as the Zope2 + HTTPResponse. i.e. content-length -> Content-Length. About the Zope 3 Base --------------------- From philikon at codespeak.net Mon May 29 23:24:22 2006 From: philikon at codespeak.net (philikon at codespeak.net) Date: Mon, 29 May 2006 23:24:22 +0200 (CEST) Subject: [z3-checkins] r27884 - in z3/www/trunk: . text Message-ID: <20060529212422.6CE8010063@code0.codespeak.net> Author: philikon Date: Mon May 29 23:24:19 2006 New Revision: 27884 Modified: z3/www/trunk/mkwebsite.py z3/www/trunk/text/index.txt Log: new five releases Modified: z3/www/trunk/mkwebsite.py ============================================================================== --- z3/www/trunk/mkwebsite.py (original) +++ z3/www/trunk/mkwebsite.py Mon May 29 23:24:19 2006 @@ -142,34 +142,34 @@ 'http://codespeak.net/mailman/listinfo/z3-five'), ('z3-checkins mailing list', 'http://codespeak.net/mailman/listinfo/z3-checkins'), - ('Five 1.2.4 release', + ('Five 1.2.5 release', 'release/Five-1.2.4.tgz'), - ('Five 1.3.5 release', + ('Five 1.3.6 release', 'release/Five-1.3.5.tgz'), - ('Five 1.4c release', - 'release/Five-1.4c.tgz'), + ('Five 1.4 release', + 'release/Five-1.4.tgz'), ] site.registerReleases([ Z3ReleaseResource( - 'Five', 'svn://svn.zope.org/repos/main/Products.Five/tags/1.2.4'), + 'Five', 'svn://svn.zope.org/repos/main/Products.Five/tags/1.2.5'), Z3ReleaseResource( - 'Five', 'svn://svn.zope.org/repos/main/Products.Five/tags/1.3.5'), + 'Five', 'svn://svn.zope.org/repos/main/Products.Five/tags/1.3.6'), Z3ReleaseResource( - 'Five', 'svn://svn.zope.org/repos/main/Products.Five/tags/1.4c'), + 'Five', 'svn://svn.zope.org/repos/main/Products.Five/tags/1.4'), ], project.getName()) from z3publish import Z3TestPage site.registerPages([ - ZopeOrgPage('Products.Five/tags/1.5b', 'doc/main.txt', 'index'), - ZopeOrgPage('Products.Five/tags/1.5b', 'doc/features.txt'), - ZopeOrgPage('Products.Five/tags/1.5b', 'doc/directives.txt'), - ZopeOrgPage('Products.Five/tags/1.5b', 'doc/manual.txt'), - ZopeOrgPage('Products.Five/tags/1.5b', 'doc/i18n.txt'), - ZopeOrgPage('Products.Five/tags/1.5b', 'doc/localsite.txt'), - ZopeOrgPage('Products.Five/tags/1.5b', 'doc/event.txt'), - ZopeOrgPage('Products.Five/tags/1.5b', 'CHANGES.txt'), - ZopeOrgPage('Products.Five/tags/1.5b', 'INSTALL.txt'),], + ZopeOrgPage('Products.Five/tags/1.5c', 'doc/main.txt', 'index'), + ZopeOrgPage('Products.Five/tags/1.5c', 'doc/features.txt'), + ZopeOrgPage('Products.Five/tags/1.5c', 'doc/directives.txt'), + ZopeOrgPage('Products.Five/tags/1.5c', 'doc/manual.txt'), + ZopeOrgPage('Products.Five/tags/1.5c', 'doc/i18n.txt'), + ZopeOrgPage('Products.Five/tags/1.5c', 'doc/localsite.txt'), + ZopeOrgPage('Products.Five/tags/1.5c', 'doc/event.txt'), + ZopeOrgPage('Products.Five/tags/1.5c', 'CHANGES.txt'), + ZopeOrgPage('Products.Five/tags/1.5c', 'INSTALL.txt'),], site.getProjectLayouter(project), project.getName(), nav_links=nav_links, Modified: z3/www/trunk/text/index.txt ============================================================================== --- z3/www/trunk/text/index.txt (original) +++ z3/www/trunk/text/index.txt Mon May 29 23:24:19 2006 @@ -21,6 +21,8 @@ News ---- +* 2005-05-29 `Five`_ 1.2.5, 1.3.6, 1.4 and 1.5c released! + * 2005-05-04 `Five`_ 1.2.4, 1.3.5, 1.4c and 1.5b released! * 2005-02-25 `Five`_ 1.2.1 and 1.3.2 released! Download `Five 1.2.1`_ From philikon at codespeak.net Mon May 29 23:25:08 2006 From: philikon at codespeak.net (philikon at codespeak.net) Date: Mon, 29 May 2006 23:25:08 +0200 (CEST) Subject: [z3-checkins] r27885 - z3/www/trunk Message-ID: <20060529212508.07C9010063@code0.codespeak.net> Author: philikon Date: Mon May 29 23:25:05 2006 New Revision: 27885 Modified: z3/www/trunk/mkwebsite.py Log: gah, wron gurls Modified: z3/www/trunk/mkwebsite.py ============================================================================== --- z3/www/trunk/mkwebsite.py (original) +++ z3/www/trunk/mkwebsite.py Mon May 29 23:25:05 2006 @@ -143,9 +143,9 @@ ('z3-checkins mailing list', 'http://codespeak.net/mailman/listinfo/z3-checkins'), ('Five 1.2.5 release', - 'release/Five-1.2.4.tgz'), + 'release/Five-1.2.5.tgz'), ('Five 1.3.6 release', - 'release/Five-1.3.5.tgz'), + 'release/Five-1.3.6.tgz'), ('Five 1.4 release', 'release/Five-1.4.tgz'), ] From philikon at codespeak.net Mon May 29 23:44:51 2006 From: philikon at codespeak.net (philikon at codespeak.net) Date: Mon, 29 May 2006 23:44:51 +0200 (CEST) Subject: [z3-checkins] r27886 - z3/www/trunk/text Message-ID: <20060529214451.1947010063@code0.codespeak.net> Author: philikon Date: Mon May 29 23:44:46 2006 New Revision: 27886 Modified: z3/www/trunk/text/five_releasefest2.txt Log: Shorten heading Modified: z3/www/trunk/text/five_releasefest2.txt ============================================================================== --- z3/www/trunk/text/five_releasefest2.txt (original) +++ z3/www/trunk/text/five_releasefest2.txt Mon May 29 23:44:46 2006 @@ -55,8 +55,8 @@ Kerrin for making this possible! -Changes in Five 1.2.5, 1.3.6, 1.4 (compared to 1.4c), 1.5c (compare to 1.5b) ----------------------------------------------------------------------------- +Changes in Five 1.2.5, 1.3.6, 1.4 (vs. 1.4c), 1.5c (vs. 1.5b) +------------------------------------------------------------- * Fixed an issue where based views that didn't have template or attribute defined weren't getting BrowserView mixed in. From srichter at codespeak.net Tue Jun 6 03:07:55 2006 From: srichter at codespeak.net (srichter at codespeak.net) Date: Tue, 6 Jun 2006 03:07:55 +0200 (CEST) Subject: [z3-checkins] r28340 - z3/jsonserver/trunk Message-ID: <20060606010755.C1C1210036@code0.codespeak.net> Author: srichter Date: Tue Jun 6 03:07:52 2006 New Revision: 28340 Modified: z3/jsonserver/trunk/metaconfigure.py Log: Fix deprecation warning. Modified: z3/jsonserver/trunk/metaconfigure.py ============================================================================== --- z3/jsonserver/trunk/metaconfigure.py (original) +++ z3/jsonserver/trunk/metaconfigure.py Tue Jun 6 03:07:52 2006 @@ -83,8 +83,8 @@ _context.action( discriminator = ('view', for_, name, IJSONRPCRequest), callable = handler, - args = ('provideAdapter', - (for_, IJSONRPCRequest), Interface, name, class_, + args = ('registerAdapter', + class_, (for_, IJSONRPCRequest), Interface, name, _context.info) ) else: @@ -101,8 +101,8 @@ _context.action( discriminator = ('view', for_, name, IJSONRPCRequest), callable = handler, - args = ('provideAdapter', - (for_, IJSONRPCRequest), Interface, name, new_class, + args = ('registerAdapter', + new_class, (for_, IJSONRPCRequest), Interface, name, _context.info) ) From srichter at codespeak.net Tue Jun 6 12:15:28 2006 From: srichter at codespeak.net (srichter at codespeak.net) Date: Tue, 6 Jun 2006 12:15:28 +0200 (CEST) Subject: [z3-checkins] r28357 - z3/hurry/trunk/src/hurry/query Message-ID: <20060606101528.E947010053@code0.codespeak.net> Author: srichter Date: Tue Jun 6 12:15:27 2006 New Revision: 28357 Modified: z3/hurry/trunk/src/hurry/query/query.py Log: This assertion was far too strong, since it restricted the Term to a very narrow (and often non-useful) type of text indices. Modified: z3/hurry/trunk/src/hurry/query/query.py ============================================================================== --- z3/hurry/trunk/src/hurry/query/query.py (original) +++ z3/hurry/trunk/src/hurry/query/query.py Tue Jun 6 12:15:27 2006 @@ -121,7 +121,10 @@ def getIndex(self): index = super(Text, self).getIndex() - assert ITextIndex.providedBy(index) + # TODO: This assertion is too strong, since custom text indices often + # do not use this interface. I looked around, and unfortunately there + # is no alternative. (SR) + #assert ITextIndex.providedBy(index) return index def apply(self): From jinty at codespeak.net Tue Jun 6 15:57:58 2006 From: jinty at codespeak.net (jinty at codespeak.net) Date: Tue, 6 Jun 2006 15:57:58 +0200 (CEST) Subject: [z3-checkins] r28383 - z3/sqlos/trunk/src/sqlos Message-ID: <20060606135758.6219310036@code0.codespeak.net> Author: jinty Date: Tue Jun 6 15:57:54 2006 New Revision: 28383 Modified: z3/sqlos/trunk/src/sqlos/README.txt Log: Tweak noted by Roy Mathew. Modified: z3/sqlos/trunk/src/sqlos/README.txt ============================================================================== --- z3/sqlos/trunk/src/sqlos/README.txt (original) +++ z3/sqlos/trunk/src/sqlos/README.txt Tue Jun 6 15:57:54 2006 @@ -130,11 +130,11 @@ You can easily install sqlos from the python cheeseshop using easy_install. To do this, you will have to first install setuptools_. -For example, this command will install sqlos and it's dependencies in -~/lib/python2.4/site-packages. Note that ~/lib/python2.4/site-packages should -be on the python path. +For example, this command will install the latest version of sqlos and it's +dependencies in ~/lib/python2.4/site-packages. Note that +~/lib/python2.4/site-packages should be on the python path. - $ easy_install --install-dir=~/lib/python2.4/site-packages 'sqlos == 0.2' + $ easy_install --install-dir=~/lib/python2.4/site-packages sqlos After that, you should install the Zope Database Adapter you wish to use and copy the sqlos-*.zcml package includes (in the includes directory in the From rocky at codespeak.net Wed Jun 7 20:10:35 2006 From: rocky at codespeak.net (rocky at codespeak.net) Date: Wed, 7 Jun 2006 20:10:35 +0200 (CEST) Subject: [z3-checkins] r28480 - z3/pythonproducts/trunk Message-ID: <20060607181035.3891110075@code0.codespeak.net> Author: rocky Date: Wed Jun 7 19:55:53 2006 New Revision: 28480 Modified: z3/pythonproducts/trunk/ (props changed) z3/pythonproducts/trunk/setup.py Log: Updated setup.py to reflect a new beta release. Modified: z3/pythonproducts/trunk/setup.py ============================================================================== --- z3/pythonproducts/trunk/setup.py (original) +++ z3/pythonproducts/trunk/setup.py Wed Jun 7 19:55:53 2006 @@ -96,7 +96,7 @@ setup(cmdclass={'install': Installer}, name='pythonproducts', - version='1.0beta1', + version='1.0beta2', description='A mechanism to construct Zope 2 products as regular ' 'python packages', author='Rocky Burt', From rocky at codespeak.net Wed Jun 7 21:18:58 2006 From: rocky at codespeak.net (rocky at codespeak.net) Date: Wed, 7 Jun 2006 21:18:58 +0200 (CEST) Subject: [z3-checkins] r28485 - z3/pythonproducts/tags/1.0beta2 Message-ID: <20060607191858.6639510070@code0.codespeak.net> Author: rocky Date: Wed Jun 7 21:04:30 2006 New Revision: 28485 Added: z3/pythonproducts/tags/1.0beta2/ - copied from r28484, z3/pythonproducts/trunk/ Log: Tagged new 1.0beta2 release of pythonproducts. From gintas at codespeak.net Thu Jun 8 10:07:39 2006 From: gintas at codespeak.net (gintas at codespeak.net) Date: Thu, 8 Jun 2006 10:07:39 +0200 (CEST) Subject: [z3-checkins] r28498 - z3/z3reload/trunk Message-ID: <20060608080739.B614910060@code0.codespeak.net> Author: gintas Date: Thu Jun 8 10:07:39 2006 New Revision: 28498 Modified: z3/z3reload/trunk/reload.py Log: Fixed a couple of bugs: * in some cases __sanitize_bases would loop forever * sometimes SimpleView classes seem to have different bases; removed assertion that complained about those. Modified: z3/z3reload/trunk/reload.py ============================================================================== --- z3/z3reload/trunk/reload.py (original) +++ z3/z3reload/trunk/reload.py Thu Jun 8 10:07:39 2006 @@ -19,10 +19,15 @@ """ def __init__(self, *args, **kw): - assert len(self.__class__.__bases__) == 3 - reloader2, real_view, simple2 = self.__class__.__bases__ + bases = self.__class__.__bases__ + assert len(bases) >= 2 + reloader2, real_view = bases[:2] assert reloader2 is Reloader - assert simple2 in simple_view_classes + + rest = bases[2:] +# for c in rest: +# if c not in simple_view_classes: +# print >> sys.stderr, "Warning: %r has base %r" % (self.__class__, c) clsname = real_view.__name__ modname = real_view.__module__ @@ -30,7 +35,7 @@ if hasattr(module, clsname): reload(module) new_view = getattr(module, clsname) - self.__class__.__bases__ = (Reloader, new_view, simple2) + self.__class__.__bases__ = (Reloader, new_view) + rest else: # If the module does not have such an attribute, chances are that # the class was dynamically constructed. In this case reloading is @@ -53,7 +58,9 @@ bases = cls.__bases__ new_bases = [] for b in bases: - if hasattr(module, b.__name__): + bc = getattr(module, b.__name__, None) + if bc is not None and bc.__module__ != modname: + # Make sure that the base class comes from a different module. new_base = getattr(module, b.__name__) self.__sanitize_bases(new_base) new_bases.append(new_base) From gintas at codespeak.net Thu Jun 8 10:16:00 2006 From: gintas at codespeak.net (gintas at codespeak.net) Date: Thu, 8 Jun 2006 10:16:00 +0200 (CEST) Subject: [z3-checkins] r28501 - in z3/z3reload/trunk: . ftests Message-ID: <20060608081600.134D710070@code0.codespeak.net> Author: gintas Date: Thu Jun 8 10:15:59 2006 New Revision: 28501 Modified: z3/z3reload/trunk/ftests/dynamic.py z3/z3reload/trunk/ftests/dynamic_orig.py z3/z3reload/trunk/ftests/ftesting.zcml z3/z3reload/trunk/subscriber.py Log: Fixed deprecation warnings. Modified: z3/z3reload/trunk/ftests/dynamic.py ============================================================================== --- z3/z3reload/trunk/ftests/dynamic.py (original) +++ z3/z3reload/trunk/ftests/dynamic.py Thu Jun 8 10:15:59 2006 @@ -1,4 +1,4 @@ -from zope.app.publisher.browser import BrowserView +from zope.publisher.browser import BrowserView class SomeNumberView(BrowserView): Modified: z3/z3reload/trunk/ftests/dynamic_orig.py ============================================================================== --- z3/z3reload/trunk/ftests/dynamic_orig.py (original) +++ z3/z3reload/trunk/ftests/dynamic_orig.py Thu Jun 8 10:15:59 2006 @@ -1,4 +1,4 @@ -from zope.app.publisher.browser import BrowserView +from zope.publisher.browser import BrowserView class SomeNumberView(BrowserView): Modified: z3/z3reload/trunk/ftests/ftesting.zcml ============================================================================== --- z3/z3reload/trunk/ftests/ftesting.zcml (original) +++ z3/z3reload/trunk/ftests/ftesting.zcml Thu Jun 8 10:15:59 2006 @@ -3,19 +3,19 @@ - - - Modified: z3/z3reload/trunk/subscriber.py ============================================================================== --- z3/z3reload/trunk/subscriber.py (original) +++ z3/z3reload/trunk/subscriber.py Thu Jun 8 10:15:59 2006 @@ -2,7 +2,7 @@ from zope.component import getGlobalSiteManager from zope.publisher.interfaces import IRequest -from zope.component.site import AdapterRegistration +from zope.component.registry import AdapterRegistration from z3reload.reload import install_reloader, simple_view_classes from z3reload.metaconfigure import enabled_classes, enabled_modules @@ -22,8 +22,8 @@ reg.required[-1].isOrExtends(IRequest)): return False # this registration does not appear to be a view - return (type(reg.value) == type and - issubclass(reg.value, simple_view_classes)) + return (type(reg.factory) == type and + issubclass(reg.factory, simple_view_classes)) def reload_enabled_for(view_class): @@ -47,6 +47,6 @@ Hooks on the DatabaseOpened event. """ gsm = getGlobalSiteManager() - for reg in gsm.registrations(): - if is_simple_view(reg) and reload_enabled_for(reg.value): - install_reloader(reg.value) + for reg in gsm.registeredAdapters(): + if is_simple_view(reg) and reload_enabled_for(reg.factory): + install_reloader(reg.factory) From jwashin at codespeak.net Fri Jun 9 18:49:28 2006 From: jwashin at codespeak.net (jwashin at codespeak.net) Date: Fri, 9 Jun 2006 18:49:28 +0200 (CEST) Subject: [z3-checkins] r28593 - z3/jsonserver/trunk Message-ID: <20060609164928.7549710036@code0.codespeak.net> Author: jwashin Date: Fri Jun 9 18:49:25 2006 New Revision: 28593 Modified: z3/jsonserver/trunk/metaconfigure.py Log: registerAdapter vs provideAdapter Modified: z3/jsonserver/trunk/metaconfigure.py ============================================================================== --- z3/jsonserver/trunk/metaconfigure.py (original) +++ z3/jsonserver/trunk/metaconfigure.py Fri Jun 9 18:49:25 2006 @@ -17,8 +17,10 @@ like zope.app.publisher.xmlrpc.metaconfigure +registerAdapter vs provideAdapter jwashin 20060525 updated 2005-12-03 Roger Ineichen jwashin 2005-06-06 + """ import zope.interface from zope.interface import Interface @@ -84,7 +86,7 @@ discriminator = ('view', for_, name, IJSONRPCRequest), callable = handler, args = ('registerAdapter', - class_, (for_, IJSONRPCRequest), Interface, name, + class_,(for_, IJSONRPCRequest), Interface, name, _context.info) ) else: @@ -102,7 +104,7 @@ discriminator = ('view', for_, name, IJSONRPCRequest), callable = handler, args = ('registerAdapter', - new_class, (for_, IJSONRPCRequest), Interface, name, + new_class,(for_, IJSONRPCRequest), Interface, name, _context.info) ) From philikon at codespeak.net Sat Jun 10 16:27:24 2006 From: philikon at codespeak.net (philikon at codespeak.net) Date: Sat, 10 Jun 2006 16:27:24 +0200 (CEST) Subject: [z3-checkins] r28616 - z3/Sfive/trunk Message-ID: <20060610142724.07AB910060@code0.codespeak.net> Author: philikon Date: Sat Jun 10 16:27:19 2006 New Revision: 28616 Modified: z3/Sfive/trunk/presentation.py Log: Make Zope 2.10 compatible: immutable i18n messages (MessageID -> Message) Use zope.component.adapts for easier adapter registration in ZCML Modified: z3/Sfive/trunk/presentation.py ============================================================================== --- z3/Sfive/trunk/presentation.py (original) +++ z3/Sfive/trunk/presentation.py Sat Jun 10 16:27:19 2006 @@ -1,13 +1,14 @@ -from zope.i18n import MessageIDFactory -from zope.interface import implements -from zope.app.size.interfaces import ISized -_ = MessageIDFactory('sfive') +import zope.interface +import zope.component +from zope.size.interfaces import ISized +from zope.i18nmessageid import MessageFactory +_ = MessageFactory('sfive') from OFS.SimpleItem import SimpleItem from Products.Sfive.interfaces import IPresentation class Presentation(SimpleItem): - implements(IPresentation) + zope.interface.implements(IPresentation) meta_type = 'Sfive Presentation' def __init__(self, id, title): @@ -34,7 +35,8 @@ u'11 characters' >>> tearDown() """ - implements(ISized) + zope.interface.implements(ISized) + zope.component.adapts(IPresentation) def __init__(self, context): self.context = context @@ -44,6 +46,4 @@ def sizeForDisplay(self): unit, chars = self.sizeForSorting() - msg = _('${chars} characters') - msg.mapping['chars'] = chars - return msg + return _('${chars} characters', mapping={'chars': chars}) From philikon at codespeak.net Sat Jun 10 16:29:53 2006 From: philikon at codespeak.net (philikon at codespeak.net) Date: Sat, 10 Jun 2006 16:29:53 +0200 (CEST) Subject: [z3-checkins] r28617 - z3/Sfive/trunk Message-ID: <20060610142953.C830110060@code0.codespeak.net> Author: philikon Date: Sat Jun 10 16:29:47 2006 New Revision: 28617 Modified: z3/Sfive/trunk/interfaces.py Log: Make Zope 2.10 compatible: immutable i18n messages (MessageID -> Message) We'll require reST input from now on so we don't need the choice between different plain text formats anymore Modified: z3/Sfive/trunk/interfaces.py ============================================================================== --- z3/Sfive/trunk/interfaces.py (original) +++ z3/Sfive/trunk/interfaces.py Sat Jun 10 16:29:47 2006 @@ -1,7 +1,7 @@ from zope.interface import Interface from zope.schema import TextLine, SourceText, Choice -from zope.i18n import MessageIDFactory -_ = MessageIDFactory('sfive') +from zope.i18nmessageid import MessageFactory +_ = MessageFactory('sfive') class IPresentation(Interface): @@ -36,11 +36,3 @@ description=_(u"Presentation text"), required=True ) - - type = Choice( - title=_(u"Text type"), - description=_(u"Type of the text, e.g. structured text"), - default=u"zope.source.rest", - required=True, - vocabulary="SourceTypes" - ) From philikon at codespeak.net Sat Jun 10 16:30:24 2006 From: philikon at codespeak.net (philikon at codespeak.net) Date: Sat, 10 Jun 2006 16:30:24 +0200 (CEST) Subject: [z3-checkins] r28618 - z3/Sfive/trunk/ui Message-ID: <20060610143024.D9BED10060@code0.codespeak.net> Author: philikon Date: Sat Jun 10 16:30:04 2006 New Revision: 28618 Added: z3/Sfive/trunk/ui/outline.css (contents, props changed) Modified: z3/Sfive/trunk/ui/framing.css z3/Sfive/trunk/ui/opera.css z3/Sfive/trunk/ui/pretty.css z3/Sfive/trunk/ui/print.css z3/Sfive/trunk/ui/s5-core.css z3/Sfive/trunk/ui/slides.js Log: Update to S5 1.1 Modified: z3/Sfive/trunk/ui/framing.css ============================================================================== --- z3/Sfive/trunk/ui/framing.css (original) +++ z3/Sfive/trunk/ui/framing.css Sat Jun 10 16:30:04 2006 @@ -3,13 +3,13 @@ The commented lines can be uncommented (and modified, if necessary) to help you with the rearrangement process. */ -div#header, div#footer, div.slide {width: 100%; top: 0; left: 0;} +/* target = 1024x768 */ + +div#header, div#footer, .slide {width: 100%; top: 0; left: 0;} div#header {top: 0; height: 3em; z-index: 1;} div#footer {top: auto; bottom: 0; height: 2.5em; z-index: 5;} -div.slide {top: 0; width: 92%; padding: 3.5em 4% 4%; z-index: 2;} -div#controls {left: 50%; top: 0; width: 50%; height: 100%; z-index: 1;} -#footer>div#controls {bottom: 0; top: auto; height: auto;} - +.slide {top: 0; width: 92%; padding: 3.5em 4% 4%; z-index: 2; list-style: none;} +div#controls {left: 50%; bottom: 0; width: 50%; z-index: 100;} div#controls form {position: absolute; bottom: 0; right: 0; width: 100%; margin: 0;} #currentSlide {position: absolute; width: 10%; left: 45%; bottom: 1em; z-index: 10;} Modified: z3/Sfive/trunk/ui/opera.css ============================================================================== --- z3/Sfive/trunk/ui/opera.css (original) +++ z3/Sfive/trunk/ui/opera.css Sat Jun 10 16:30:04 2006 @@ -1,5 +1,5 @@ /* DO NOT CHANGE THESE unless you really want to break Opera Show */ -div.slide { +.slide { visibility: visible !important; position: static !important; page-break-before: always; Added: z3/Sfive/trunk/ui/outline.css ============================================================================== --- (empty file) +++ z3/Sfive/trunk/ui/outline.css Sat Jun 10 16:30:04 2006 @@ -0,0 +1,15 @@ +/* don't change this unless you want the layout stuff to show up in the outline view! */ + +.layout div, #footer *, #controlForm * {display: none;} +#footer, #controls, #controlForm, #navLinks, #toggle { + display: block; visibility: visible; margin: 0; padding: 0;} +#toggle {float: right; padding: 0.5em;} +html>body #toggle {position: fixed; top: 0; right: 0;} + +/* making the outline look pretty-ish */ + +#slide0 h1, #slide0 h2, #slide0 h3, #slide0 h4 {border: none; margin: 0;} +#slide0 h1 {padding-top: 1.5em;} +.slide h1 {margin: 1.5em 0 0; padding-top: 0.25em; + border-top: 1px solid #888; border-bottom: 1px solid #AAA;} +#toggle {border: 1px solid; border-width: 0 0 1px 1px; background: #FFF;} Modified: z3/Sfive/trunk/ui/pretty.css ============================================================================== --- z3/Sfive/trunk/ui/pretty.css (original) +++ z3/Sfive/trunk/ui/pretty.css Sat Jun 10 16:30:04 2006 @@ -1,9 +1,7 @@ -/* Following are the presentation styles -- edit away! - Note that the 'body' font size may have to be changed if the resolution is - different than expected. */ +/* Following are the presentation styles -- edit away! */ -body {background: #fff url(bodybg.gif) -16px 0 no-repeat; color: #000; font-size: 2em;} -:link, :visited {text-decoration: none;} +body {background: #FFF url(bodybg.gif) -16px 0 no-repeat; color: #000; font-size: 2em;} +:link, :visited {text-decoration: none; color: #00C;} #controls :active {color: #88A !important;} #controls :focus {outline: 1px dotted #227;} h1, h2, h3, h4 {font-size: 100%; margin: 0; padding: 0; font-weight: inherit;} @@ -20,16 +18,16 @@ kbd {font-weight: bold; font-size: 1em;} sup {font-size: smaller; line-height: 1px;} -code {padding: 2px 0.25em; font-weight: bold; color: #533;} -code.bad, code del {color: red;} -code.old {color: silver;} -pre {padding: 0; margin: 0.25em 0 0.5em 0.5em; color: #533; font-size: 90%;} -pre code {display: block;} -ul {margin-left: 5%; margin-right: 7%; list-style: disc;} -li {margin-top: 0.75em; margin-right: 0;} -ul ul {line-height: 1;} -ul ul li {margin: .2em; font-size: 85%; list-style: square;} -img.leader {display: block; margin: 0 auto;} +.slide code {padding: 2px 0.25em; font-weight: bold; color: #533;} +.slide code.bad, code del {color: red;} +.slide code.old {color: silver;} +.slide pre {padding: 0; margin: 0.25em 0 0.5em 0.5em; color: #533; font-size: 90%;} +.slide pre code {display: block;} +.slide ul {margin-left: 5%; margin-right: 7%; list-style: disc;} +.slide li {margin-top: 0.75em; margin-right: 0;} +.slide ul ul {line-height: 1;} +.slide ul ul li {margin: .2em; font-size: 85%; list-style: square;} +.slide img.leader {display: block; margin: 0 auto;} div#header, div#footer {background: #005; color: #AAB; font-family: Verdana, Helvetica, sans-serif;} @@ -47,28 +45,42 @@ .slide h3 {font-size: 130%;} h1 abbr {font-variant: small-caps;} -div#controls {position: absolute; z-index: 1; left: 50%; top: 0; - width: 50%; height: 100%; - text-align: right;} -#footer>div#controls {position: fixed; bottom: 0; padding: 1em 0; - top: auto; height: auto;} +div#controls {position: absolute; left: 50%; bottom: 0; + width: 50%; + text-align: right; font: bold 0.9em Verdana, Helvetica, sans-serif;} +html>body div#controls {position: fixed; padding: 0 0 1em 0; + top: auto;} div#controls form {position: absolute; bottom: 0; right: 0; width: 100%; margin: 0; padding: 0;} -div#controls a {font-size: 2em; padding: 0; margin: 0 0.5em; +#controls #navLinks a {padding: 0; margin: 0 0.5em; background: #005; border: none; color: #779; cursor: pointer;} -div#controls select {visibility: hidden; background: #DDD; color: #227;} -div#controls div:hover select {visibility: visible;} +#controls #navList {height: 1em;} +#controls #navList #jumplist {position: absolute; bottom: 0; right: 0; background: #DDD; color: #227;} #currentSlide {text-align: center; font-size: 0.5em; color: #449;} #slide0 {padding-top: 3.5em; font-size: 90%;} -#slide0 h1 {position: static; margin: 1em 0 1.33em; padding: 0; +#slide0 h1 {position: static; margin: 1em 0 0; padding: 0; font: bold 2em Helvetica, sans-serif; white-space: normal; color: #000; background: transparent;} -#slide0 h3 {margin-top: 0.5em; font-size: 1.5em;} +#slide0 h2 {font: bold italic 1em Helvetica, sans-serif; margin: 0.25em;} +#slide0 h3 {margin-top: 1.5em; font-size: 1.5em;} #slide0 h4 {margin-top: 0; font-size: 1em;} ul.urls {list-style: none; display: inline; margin: 0;} .urls li {display: inline; margin: 0;} .note {display: none;} +.external {border-bottom: 1px dotted gray;} +html>body .external {border-bottom: none;} +.external:after {content: " \274F"; font-size: smaller; color: #77B;} + +.incremental, .incremental *, .incremental *:after {color: #DDE; visibility: visible;} +img.incremental {visibility: hidden;} +.slide .current {color: #B02;} + + +/* diagnostics + +li:after {content: " [" attr(class) "]"; color: #F88;} + */ \ No newline at end of file Modified: z3/Sfive/trunk/ui/print.css ============================================================================== --- z3/Sfive/trunk/ui/print.css (original) +++ z3/Sfive/trunk/ui/print.css Sat Jun 10 16:30:04 2006 @@ -1,5 +1,5 @@ -/* The next rule is necessary to have all slides appear in print! DO NOT REMOVE IT! */ -div.slide, ul {page-break-inside: avoid; visibility: visible !important;} +/* The following rule is necessary to have all slides appear in print! DO NOT REMOVE IT! */ +.slide, ul {page-break-inside: avoid; visibility: visible !important;} h1 {page-break-after: avoid;} body {font-size: 12pt; background: white;} @@ -20,4 +20,5 @@ #footer h1 {margin: 0; border-bottom: 1px solid; color: gray; font-style: italic;} #footer h2, #controls {display: none;} -#currentSlide {display: none;} \ No newline at end of file +/* The following rule keeps the layout stuff out of print. Remove at your own risk! */ +.layout, .layout * {display: none !important;} Modified: z3/Sfive/trunk/ui/s5-core.css ============================================================================== --- z3/Sfive/trunk/ui/s5-core.css (original) +++ z3/Sfive/trunk/ui/s5-core.css Sat Jun 10 16:30:04 2006 @@ -1,9 +1,9 @@ /* Do not edit or override these styles! The system will likely break if you do. */ -div#header, div#footer, div.slide {position: absolute;} -html>body div#header, html>body div#footer, html>body div.slide {position: fixed;} -div.slide { visibility: hidden;} -#slide0 {visibility: visible;} -div#controls {position: absolute;} -#footer>div#controls {position: fixed;} +div#header, div#footer, div#controls, .slide {position: absolute;} +html>body div#header, html>body div#footer, + html>body div#controls, html>body .slide {position: fixed;} .handout {display: none;} +.layout {display: block;} +.slide, .hideme, .incremental {visibility: hidden;} +#slide0 {visibility: visible;} Modified: z3/Sfive/trunk/ui/slides.js ============================================================================== --- z3/Sfive/trunk/ui/slides.js (original) +++ z3/Sfive/trunk/ui/slides.js Sat Jun 10 16:30:04 2006 @@ -1,26 +1,51 @@ -// S5 slides.js -- released under CC by-sa 2.0 license +// S5 v1.1 slides.js -- released into the Public Domain // // Please see http://www.meyerweb.com/eric/tools/s5/credits.html for information // about all the wonderful and talented contributors to this code! +var undef; +var slideCSS = ''; var snum = 0; var smax = 1; -var undef; -var slcss = 1; +var incpos = 0; +var number = undef; +var s5mode = true; +var defaultView = 'slideshow'; +var controlVis = 'visible'; + var isIE = navigator.appName == 'Microsoft Internet Explorer' ? 1 : 0; var isOp = navigator.userAgent.indexOf('Opera') > -1 ? 1 : 0; var isGe = navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('Safari') < 1 ? 1 : 0; -var slideCSS = document.getElementById('slideProj').href; -function isClass(object, className) { +function hasClass(object, className) { + if (!object.className) return false; return (object.className.search('(^|\\s)' + className + '(\\s|$)') != -1); } +function hasValue(object, value) { + if (!object) return false; + return (object.search('(^|\\s)' + value + '(\\s|$)') != -1); +} + +function removeClass(object,className) { + if (!object) return; + object.className = object.className.replace(new RegExp('(^|\\s)'+className+'(\\s|$)'), RegExp.$1+RegExp.$2); +} + +function addClass(object,className) { + if (!object || hasClass(object, className)) return; + if (object.className) { + object.className += ' '+className; + } else { + object.className = className; + } +} + function GetElementsWithClassName(elementName,className) { var allElements = document.getElementsByTagName(elementName); var elemColl = new Array(); - for (i = 0; i< allElements.length; i++) { - if (isClass(allElements[i], className)) { + for (var i = 0; i< allElements.length; i++) { + if (hasClass(allElements[i], className)) { elemColl[elemColl.length] = allElements[i]; } } @@ -37,7 +62,7 @@ var result = ""; if (node.nodeType == 1) { var children = node.childNodes; - for ( i = 0; i < children.length; ++i ) { + for (var i = 0; i < children.length; ++i) { result += nodeValue(children[i]); } } @@ -48,18 +73,18 @@ } function slideLabel() { - var slideColl = GetElementsWithClassName('div','slide'); + var slideColl = GetElementsWithClassName('*','slide'); var list = document.getElementById('jumplist'); smax = slideColl.length; - for (n = 0; n < smax; n++) { + for (var n = 0; n < smax; n++) { var obj = slideColl[n]; var did = 'slide' + n.toString(); obj.setAttribute('id',did); - if(isOp) continue; + if (isOp) continue; var otext = ''; - var menu = obj.firstChild; + var menu = obj.firstChild; if (!menu) continue; // to cope with empty slides while (menu && menu.nodeType == 3) { menu = menu.nextSibling; @@ -67,10 +92,10 @@ if (!menu) continue; // to cope with slides with only text nodes var menunodes = menu.childNodes; - for (o = 0; o < menunodes.length; o++) { + for (var o = 0; o < menunodes.length; o++) { otext += nodeValue(menunodes[o]); } - list.options[list.length] = new Option(n+' : ' +otext,n); + list.options[list.length] = new Option(n + ' : ' + otext, n); } } @@ -91,50 +116,95 @@ } } -function go(inc) { - if (document.getElementById("slideProj").disabled) return; +function go(step) { + if (document.getElementById('slideProj').disabled || step == 0) return; + var jl = document.getElementById('jumplist'); var cid = 'slide' + snum; - if (inc != 'j') { - snum += inc; - lmax = smax - 1; - if (snum > lmax) snum = 0; - if (snum < 0) snum = lmax; - } else { - snum = parseInt(document.getElementById('jumplist').value); + var ce = document.getElementById(cid); + if (incrementals[snum].length > 0) { + for (var i = 0; i < incrementals[snum].length; i++) { + removeClass(incrementals[snum][i], 'current'); + removeClass(incrementals[snum][i], 'incremental'); + } } + if (step != 'j') { + snum += step; + lmax = smax - 1; + if (snum > lmax) snum = lmax; + if (snum < 0) snum = 0; + } else + snum = parseInt(jl.value); var nid = 'slide' + snum; var ne = document.getElementById(nid); if (!ne) { ne = document.getElementById('slide0'); snum = 0; } - document.getElementById(cid).style.visibility = 'hidden'; + if (step < 0) {incpos = incrementals[snum].length} else {incpos = 0;} + if (incrementals[snum].length > 0 && incpos == 0) { + for (var i = 0; i < incrementals[snum].length; i++) { + if (hasClass(incrementals[snum][i], 'current')) + incpos = i + 1; + else + addClass(incrementals[snum][i], 'incremental'); + } + } + if (incrementals[snum].length > 0 && incpos > 0) + addClass(incrementals[snum][incpos - 1], 'current'); + ce.style.visibility = 'hidden'; ne.style.visibility = 'visible'; - document.getElementById('jumplist').selectedIndex = snum; + jl.selectedIndex = snum; currentSlide(); + number = 0; +} + +function goTo(target) { + if (target >= smax || target == snum) return; + go(target - snum); +} + +function subgo(step) { + if (step > 0) { + removeClass(incrementals[snum][incpos - 1],'current'); + removeClass(incrementals[snum][incpos], 'incremental'); + addClass(incrementals[snum][incpos],'current'); + incpos++; + } else { + incpos--; + removeClass(incrementals[snum][incpos],'current'); + addClass(incrementals[snum][incpos], 'incremental'); + addClass(incrementals[snum][incpos - 1],'current'); + } } function toggle() { - var slideColl = GetElementsWithClassName('div','slide'); - var obj = document.getElementById('slideProj'); - if (!obj.disabled) { - obj.disabled = true; - for (n = 0; n < smax; n++) { - var slide = slideColl[n]; - slide.style.visibility = 'visible'; - } - } else { - obj.disabled = false; - for (n = 0; n < smax; n++) { - var slide = slideColl[n]; - slide.style.visibility = 'hidden'; - } - slideColl[snum].style.visibility = 'visible'; - } + var slideColl = GetElementsWithClassName('*','slide'); + var slides = document.getElementById('slideProj'); + var outline = document.getElementById('outlineStyle'); + if (!slides.disabled) { + slides.disabled = true; + outline.disabled = false; + s5mode = false; + fontSize('1em'); + for (var n = 0; n < smax; n++) { + var slide = slideColl[n]; + slide.style.visibility = 'visible'; + } + } else { + slides.disabled = false; + outline.disabled = true; + s5mode = true; + fontScale(); + for (var n = 0; n < smax; n++) { + var slide = slideColl[n]; + slide.style.visibility = 'hidden'; + } + slideColl[snum].style.visibility = 'visible'; + } } function showHide(action) { - var obj = document.getElementById('jumplist'); + var obj = GetElementsWithClassName('*','hideme')[0]; switch (action) { case 's': obj.style.visibility = 'visible'; break; case 'h': obj.style.visibility = 'hidden'; break; @@ -154,39 +224,99 @@ key = event; key.which = key.keyCode; } - switch (key.which) { - case 10: // return - case 13: // enter - if (window.event && isParentOrSelf(window.event.srcElement, "controls")) return; - if (key.target && isParentOrSelf(key.target, "controls")) return; - case 32: // spacebar - case 34: // page down - case 39: // rightkey - case 40: // downkey - go(1); - break; - case 33: // page up - case 37: // leftkey - case 38: // upkey - go(-1); - break; - case 84: // t - toggle(); - break; - case 67: // c - showHide('k'); - break; + if (key.which == 84) { + toggle(); + return; + } + if (s5mode) { + switch (key.which) { + case 10: // return + case 13: // enter + if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return; + if (key.target && isParentOrSelf(key.target, 'controls')) return; + if(number != undef) { + goTo(number); + break; + } + case 32: // spacebar + case 34: // page down + case 39: // rightkey + case 40: // downkey + if(number != undef) { + go(number); + } else if (!incrementals[snum] || incpos >= incrementals[snum].length) { + go(1); + } else { + subgo(1); + } + break; + case 33: // page up + case 37: // leftkey + case 38: // upkey + if(number != undef) { + go(-1 * number); + } else if (!incrementals[snum] || incpos <= 0) { + go(-1); + } else { + subgo(-1); + } + break; + case 36: // home + goTo(0); + break; + case 35: // end + goTo(smax-1); + break; + case 67: // c + showHide('k'); + break; + } + if (key.which < 48 || key.which > 57) { + number = undef; + } else { + if (window.event && isParentOrSelf(window.event.srcElement, 'controls')) return; + if (key.target && isParentOrSelf(key.target, 'controls')) return; + number = (((number != undef) ? number : 0) * 10) + (key.which - 48); + } } + return false; } function clicker(e) { + number = undef; var target; if (window.event) { target = window.event.srcElement; e = window.event; } else target = e.target; - if (target.href != null || isParentOrSelf(target, 'controls')) return true; - if (!e.which || e.which == 1) go(1); + if (target.getAttribute('href') != null || hasValue(target.rel, 'external') || isParentOrSelf(target, 'controls') || isParentOrSelf(target,'embed') || isParentOrSelf(target,'object')) return true; + if (!e.which || e.which == 1) { + if (!incrementals[snum] || incpos >= incrementals[snum].length) { + go(1); + } else { + subgo(1); + } + } +} + +function findSlide(hash) { + var target = null; + var slides = GetElementsWithClassName('*','slide'); + for (var i = 0; i < slides.length; i++) { + var targetSlide = slides[i]; + if ( (targetSlide.name && targetSlide.name == hash) + || (targetSlide.id && targetSlide.id == hash) ) { + target = targetSlide; + break; + } + } + while(target != null && target.nodeName != 'BODY') { + if (hasClass(target, 'slide')) { + return parseInt(target.id.slice(5)); + } + target = target.parentNode; + } + return null; } function slideJump() { @@ -197,60 +327,226 @@ if (matches != null) { dest = parseInt(matches[1]); } else { - var target = window.location.hash.slice(1); - var targetElement = null; - var aelements = document.getElementsByTagName("a"); - for (i = 0; i < aelements.length; i++) { - var aelement = aelements[i]; - if ( (aelement.name && aelement.name == target) - || (aelement.id && aelement.id == target) ) { - targetElement = aelement; - break; + dest = findSlide(window.location.hash.slice(1)); + } + if (dest != null) + go(dest - snum); +} + +function fixLinks() { + var thisUri = window.location.href; + thisUri = thisUri.slice(0, thisUri.length - window.location.hash.length); + var aelements = document.getElementsByTagName('A'); + for (var i = 0; i < aelements.length; i++) { + var a = aelements[i].href; + var slideID = a.match('\#slide[0-9]{1,2}'); + if ((slideID) && (slideID[0].slice(0,1) == '#')) { + var dest = findSlide(slideID[0].slice(1)); + if (dest != null) { + if (aelements[i].addEventListener) { + aelements[i].addEventListener("click", new Function("e", + "if (document.getElementById('slideProj').disabled) return;" + + "go("+dest+" - snum); " + + "if (e.preventDefault) e.preventDefault();"), true); + } else if (aelements[i].attachEvent) { + aelements[i].attachEvent("onclick", new Function("", + "if (document.getElementById('slideProj').disabled) return;" + + "go("+dest+" - snum); " + + "event.returnValue = false;")); + } } } - while(targetElement != null && targetElement.nodeName != "body") { - if (targetElement.className == "slide") break; - targetElement = targetElement.parentNode; - } - if (targetElement != null && targetElement.className == "slide") { - dest = parseInt(targetElement.id.slice(1)); + } +} + +function externalLinks() { + if (!document.getElementsByTagName) return; + var anchors = document.getElementsByTagName('a'); + for (var i=0; i' + + var hider = ' onmouseover="showHide(\'s\');" onmouseout="showHide(\'h\');"'; + var hideDiv, hideList = ''; + if (controlVis == 'hidden') { + hideDiv = hider; + } else { + hideList = hider; + } + controlsDiv.innerHTML = '
' + + '