Skip to content

/ Zope / gocept svn checkins / Archive / 2008 / 2008-06 / SVN: r5908 - in gocept.download/trunk: . src/gocept/download

[ << ] [ >> ]

[ SVN: r5892 - in Products.zope2makesite/trunk: . ... ] [ SVN: r5909 - ZopeDeSkin/trunk/skins/zds_images / ... ]

SVN: r5908 - in gocept.download/trunk: . src/gocept/download
Thomas Lotze <tl(at)gocept.com>
2008-06-10 08:55:38 [ FULL ]
Author: thomas
Date: Tue Jun 10 08:55:35 2008
New Revision: 5908

Log:
- Copy downloaded files that are not archives of any known type to the
  part's location.

- download-directory is now a part option that defaults to a buildout option
  of the same name.

- Only create and use a directory for storing downloaded resources if the
  download-directory option is specified.

- Take advantage of zc.buildout's download cache.

- Added tests.



Added:
   gocept.download/trunk/src/gocept/download/README.txt   (contents, props
changed)
   gocept.download/trunk/src/gocept/download/sample.tar.gz   (contents, props
changed)
   gocept.download/trunk/src/gocept/download/tests.py   (contents, props
changed)
Modified:
   gocept.download/trunk/CHANGES.txt
   gocept.download/trunk/README.txt
   gocept.download/trunk/src/gocept/download/__init__.py

Modified: gocept.download/trunk/CHANGES.txt
==============================================================================
--- gocept.download/trunk/CHANGES.txt	(original)
+++ gocept.download/trunk/CHANGES.txt	Tue Jun 10 08:55:35 2008
(at)(at) -1,3 +1,19 (at)(at)
+0.9.4
+=====
+
+  - Copy downloaded files that are not archives of any known type to the
+    part's location.
+
+  - download-directory is now a part option that defaults to a buildout option
+    of the same name.
+
+  - Only create and use a directory for storing downloaded resources if the
+    download-directory option is specified.
+
+  - Take advantage of zc.buildout's download cache.
+
+  - Added tests.
+
 0.9.3
 =====
 

Modified: gocept.download/trunk/README.txt
==============================================================================
--- gocept.download/trunk/README.txt	(original)
+++ gocept.download/trunk/README.txt	Tue Jun 10 08:55:35 2008
(at)(at) -21,3 +21,16 (at)(at)
 
 :destination:
     Where to put the extracted archive contents.
+
+:download-directory: (optional)
+    Where to put the downloaded archive.
+
+    This option uses a buildout option of the same name as a default if that
+    is specified.
+
+
+Caching
+=======
+
+The download directory, if given, acts as a cache. In addition,
+gocept.download takes advantage of zc.buildout's download cache.

Added: gocept.download/trunk/src/gocept/download/README.txt
==============================================================================
--- (empty file)
+++ gocept.download/trunk/src/gocept/download/README.txt	Tue Jun 10 08:55:35
2008
(at)(at) -0,0 +1,224 (at)(at)
+=========================================================================
+gocept.download - A zc.buildout recipe to download and extract an archive
+=========================================================================
+
+Downloading a file
+==================
+
+The gocept.download recipe downloads a resource from a URL and verifies its
+MD5 checksum. If the file isn't an archive of a known type, it is simply
+placed in the buildout part's location:
+
+    >>> import os.path
+    >>> import md5
+
+    >>> resource = os.path.join(tmpdir("server"), "resource")
+    >>> write(resource, "foo")
+
+    >>> write("buildout.cfg", """
+    ... [buildout]
+    ... parts = download
+    ...
+    ... [download]
+    ... recipe = gocept.download
+    ... url = file://%(resource)s
+    ... md5sum = %(md5sum)s
+    ...
+    ... """ % {"resource": resource,
+    ...        "md5sum": md5.new("foo").hexdigest()}
+    ... )
+
+    >>> print system(buildout),
+    Installing download.
+
+    >>> ls("parts", "download")
+    -  resource
+
+    >>> cat("parts", "download", "resource")
+    foo
+
+We can specify a download directory into which the recipe will place a copy of
+the downloaded file. This allows, for example, to create a distribution
+including all downloaded files. Either an absolute or a relative file system
+path to the download directory may be given; a relative path is considered
+relative to the buildout directory:
+
+    >>> write("buildout.cfg", """
+    ... [buildout]
+    ... parts = download
+    ...
+    ... [download]
+    ... recipe = gocept.download
+    ... download-directory = download-directory
+    ... url = file://%(resource)s
+    ... md5sum = %(md5sum)s
+    ...
+    ... """ % {"resource": resource,
+    ...        "md5sum": md5.new("foo").hexdigest()}
+    ... )
+
+    >>> print system(buildout),
+    Uninstalling download.
+    Installing download.
+
+    >>> ls("download-directory")
+    -  resource
+
+    >>> cat("download-directory", "resource")
+    foo
+
+The resource will not be downloaded again from the URL once it exists in the
+download directory:
+
+    >>> write(resource, "bar")
+    >>> remove("parts", "download")
+
+    >>> print system(buildout),
+    Uninstalling download.
+    Installing download.
+
+    >>> cat("download-directory", "resource")
+    foo
+
+    >>> cat("parts", "download", "resource")
+    foo
+
+
+Using the download cache
+========================
+
+When downloading a resource from its URL, the recipe tries to take advantage
+of buildout's download cache. So far no download cache has been used, so let's
+create one:
+
+    >>> download_cache = tmpdir("download-cache")
+    >>> ls(download_cache)
+
+The downloaded file will now be placed in the download cache in addition to
+the locations seen so far:
+
+    >>> write(resource, "foo")
+    >>> remove("parts", "download")
+    >>> remove("download-directory", "resource")
+
+    >>> write("buildout.cfg", """
+    ... [buildout]
+    ... parts = download
+    ... download-cache = %(download_cache)s
+    ...
+    ... [download]
+    ... recipe = gocept.download
+    ... download-directory = download-directory
+    ... url = file://%(resource)s
+    ... md5sum = %(md5sum)s
+    ...
+    ... """ % {"download_cache": download_cache,
+    ...        "resource": resource,
+    ...        "md5sum": md5.new("foo").hexdigest()}
+    ... )
+
+    >>> print system(buildout),
+    Uninstalling download.
+    Installing download.
+
+    >>> ls(download_cache)
+    d  dist
+
+    >>> ls(download_cache, "dist")
+    -  resource
+
+    >>> cat(download_cache, "dist", "resource")
+    foo
+
+    >>> cat("download-directory", "resource")
+    foo
+
+    >>> cat("parts", "download", "resource")
+    foo
+
+The same resource will not be downloaded again after it has been placed in the
+download cache:
+
+    >>> write(resource, "bar")
+    >>> remove("parts", "download")
+    >>> remove("download-directory", "resource")
+
+    >>> print system(buildout),
+    Uninstalling download.
+    Installing download.
+
+    >>> cat(download_cache, "dist", "resource")
+    foo
+
+    >>> cat("download-directory", "resource")
+    foo
+
+    >>> cat("parts", "download", "resource")
+    foo
+
+
+Extracting an archive
+=====================
+
+If the downloaded file is an archive of a type known to gocept.download, it
+gets automatically extracted:
+
+    >>> import pkg_resources
+
+    >>> resource = pkg_resources.resource_filename(
+    ...     "gocept.download", "sample.tar.gz")
+    >>> sample = pkg_resources.resource_string(
+    ...     "gocept.download", "sample.tar.gz")
+
+    >>> write("buildout.cfg", """
+    ... [buildout]
+    ... parts = download
+    ...
+    ... [download]
+    ... recipe = gocept.download
+    ... download-directory = download-directory
+    ... url = file://%(resource)s
+    ... md5sum = %(md5sum)s
+    ...
+    ... """ % {"resource": resource,
+    ...        "md5sum": md5.new(sample).hexdigest()}
+    ... )
+
+    >>> print system(buildout),
+    Uninstalling download.
+    Installing download.
+
+    >>> ls("download-directory")
+    -  ...
+    -  sample.tar.gz
+
+    >>> ls("parts", "download")
+    -  LICENSE.txt
+
+Our example archive contains a top-level directory which was, by default,
+stripped away after extracting. We can suppress the stripping:
+
+    >>> write("buildout.cfg", """
+    ... [buildout]
+    ... parts = download
+    ...
+    ... [download]
+    ... recipe = gocept.download
+    ... download-directory = download-directory
+    ... url = file://%(resource)s
+    ... md5sum = %(md5sum)s
+    ... strip-top-level-dir = false
+    ...
+    ... """ % {"resource": resource,
+    ...        "md5sum": md5.new(sample).hexdigest()}
+    ... )
+
+    >>> print system(buildout),
+    Uninstalling download.
+    Installing download.
+
+    >>> ls("parts", "download")
+    d  top-level
+
+    >>> ls("parts", "download", "top-level")
+    -  LICENSE.txt

Modified: gocept.download/trunk/src/gocept/download/__init__.py
==============================================================================
--- gocept.download/trunk/src/gocept/download/__init__.py	(original)
+++ gocept.download/trunk/src/gocept/download/__init__.py	Tue Jun 10 08:55:35
2008
(at)(at) -21,6 +21,8 (at)(at)
 import subprocess
 import shutil
 
+import zc.buildout.easy_install
+
 
 class Recipe:
     """Recipe that downloads a package from the net and unpacks it.
(at)(at) -31,6 +33,7 (at)(at)
         strip-top-level-dir
         md5sum
         destination
+        download-directory
 
     """
 
(at)(at) -39,9 +42,8 (at)(at)
         self.buildout = buildout
         self.name = name
 
-        buildout['buildout'].setdefault(
-            'download-directory',
-            os.path.join(buildout['buildout']['directory'], 'downloads'))
+        options.setdefault('download-directory',
+                           buildout['buildout'].get('download-directory', ''))
 
         if not options.get('destination'):
             options['location'] = os.path.join(
(at)(at) -54,14 +56,12 (at)(at)
 
         self.filename = urlparse.urlparse(options['url'])[2].split('/')[-1]
 
+        self.remove_after_install = []
+
     def update(self):
         pass
 
     def install(self):
-        download_dir = self.buildout['buildout']['download-directory']
-        if not os.path.isdir(download_dir):
-            os.mkdir(download_dir)
-
         destination = self.options.get('destination')
         # Fail if a destination is given and is not an empty directory.
         # Consider both None (destination option was not given) and ''
(at)(at) -75,20 +75,18 (at)(at)
                 "Destination %s must be an empty directory." % destination)
 
         # Step 1: Download the package (if not downloaded already)
-        download_filename = os.path.join(download_dir, self.filename)
-        if not os.path.exists(download_filename):
-            # XXX undefined behavior when file already exists
-            # XXX watch out for offline flag
-            urllib.urlretrieve(self.options['url'], download_filename)
+        download_filename = self.download()
 
         # Check MD5 sum
         if compute_md5sum(download_filename) != self.options['md5sum']:
             raise ValueError("Invalid MD5 sum for downloaded file %r" %
                              self.options['url'])
 
-        # Step 2: Extract the package
+        # Step 2: Extract the package if the file is an archive
         extract_dir = tempfile.mkdtemp("buildout-" + self.name)
+        self.remove_after_install.append(extract_dir)
         is_ext = download_filename.endswith
+        is_archive = True
         if is_ext('.tar.gz') or is_ext('.tgz'):
             call = ['tar', 'xzf', download_filename, '-C', extract_dir]
         elif is_ext('.tar.bz2') or is_ext('.tbz2'):
(at)(at) -96,16 +94,19 (at)(at)
         elif is_ext('.zip'):
             call = ['unzip', download_filename, '-d', extract_dir]
         else:
-            raise ValueError("Unsupported file type: %r" % download_filename)
+            is_archive = False
 
-        retcode = subprocess.call(call)
-        if retcode != 0:
-            raise Exception("Extraction of file %r failed (tempdir: %r)" %
-                            (download_filename, extract_dir))
+        if is_archive:
+            retcode = subprocess.call(call)
+            if retcode != 0:
+                raise Exception("Extraction of file %r failed (tempdir: %r)" %
+                                (download_filename, extract_dir))
+        else:
+            shutil.copy(download_filename, extract_dir)
 
         # Step 3: Move the desired element into the place of the part
-        top_level_contents = os.listdir(extract_dir)
-        if self.options['strip-top-level-dir'] == 'true':
+        if is_archive and self.options['strip-top-level-dir'] == 'true':
+            top_level_contents = os.listdir(extract_dir)
             if len(top_level_contents) != 1:
                 raise ValueError("Can't strip top level directory because "
                                  "there is more than one element in the "
(at)(at) -127,9 +128,55 (at)(at)
             shutil.move(os.path.join(base, filename),
                         os.path.join(destination, filename))
 
-        shutil.rmtree(extract_dir)
+        for path in self.remove_after_install:
+            shutil.rmtree(path)
         return part_directories
 
+    def download(self):
+        # XXX undefined behavior when file already exists
+        # XXX watch out for offline flag
+
+        # If a download directory is given, the file will ultimately be placed
+        # in it. If the file already exists there, we are finished.
+        filename = None
+        download_dir = self.options.get('download-directory')
+        if download_dir:
+            download_dir = os.path.join(
+                self.buildout['buildout']['directory'], download_dir)
+            if not os.path.isdir(download_dir):
+                os.mkdir(download_dir)
+            filename = os.path.join(download_dir, self.filename)
+            if os.path.exists(filename):
+                return filename
+
+        # If a download cache is being used, we either take the file from it
+        # (copying to the download directory first if there is one) or
+        # remember to place a copy in the cache later.
+        cache_filename = None
+        cache_dir = zc.buildout.easy_install.download_cache()
+        if cache_dir:
+            cache_filename = os.path.join(cache_dir, self.filename)
+            if os.path.exists(cache_filename):
+                if filename:
+                    shutil.copy(cache_filename, filename)
+                return cache_filename
+
+        # We really need to download the resource. For simplicity and to avoid
+        # partial downloads littering the cache, we download it to a temporary
+        # file, copy it to the download directory and the download cache as
+        # needed and always return the temporary file to the installer.
+        temp_dir = tempfile.mkdtemp()
+        self.remove_after_install.append(temp_dir)
+
+        download_filename = os.path.join(temp_dir, self.filename)
+        urllib.urlretrieve(self.options['url'], download_filename)
+
+        if filename:
+            shutil.copy(download_filename, filename)
+        if cache_filename:
+            shutil.copy(download_filename, cache_filename)
+        return download_filename
+
 
 def compute_md5sum(filename):
     hash = md5.new('')

Added: gocept.download/trunk/src/gocept/download/sample.tar.gz
==============================================================================
Binary file. No diff available.

Added: gocept.download/trunk/src/gocept/download/tests.py
==============================================================================
--- (empty file)
+++ gocept.download/trunk/src/gocept/download/tests.py	Tue Jun 10 08:55:35 2008
(at)(at) -0,0 +1,30 (at)(at)
+# Copyright (c) 2008 gocept gmbh & co. kg and Contributors.
+# See also LICENSE.txt
+
+
+import unittest
+
+import zope.testing.doctest
+
+import zc.buildout.testing
+
+
+flags = (zope.testing.doctest.NORMALIZE_WHITESPACE |
+         zope.testing.doctest.ELLIPSIS)
+
+
+def setUp(test):
+    zc.buildout.testing.buildoutSetUp(test)
+    zc.buildout.testing.install_develop("gocept.download", test)
+
+
+def test_suite():
+    return unittest.TestSuite((
+        zope.testing.doctest.DocFileSuite(
+        "README.txt",
+        setUp=setUp,
+        tearDown=zc.buildout.testing.buildoutTearDown,
+        package="gocept.download",
+        optionflags=flags,
+        ),
+        ))

SVN: r5924 - gocept.objectquery/trunk/src/gocept/objectquery
Sebastian Wehrmann <sw(at)gocept.com>
2008-06-11 16:30:43 [ FULL ]
Author: sweh
Date: Wed Jun 11 16:30:39 2008
New Revision: 5924

Log:
updated delete method to meet the changed behavior of the objectparser


Modified:
   gocept.objectquery/trunk/src/gocept/objectquery/collection.py
   gocept.objectquery/trunk/src/gocept/objectquery/collection.txt
   gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.py
   gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.txt
   gocept.objectquery/trunk/src/gocept/objectquery/processor.txt

Modified: gocept.objectquery/trunk/src/gocept/objectquery/collection.py
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/collection.py	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/collection.py	Wed Jun 11
16:30:39 2008
(at)(at) -90,16 +90,17 (at)(at)
         """ Return the object corresponding to oid. """
         return self.conn.get(oid)
 
-    def delete(self, object_oid, parent_oid=None):
+    def delete(self, object_oid, parent_oid=None, pdb=None):
         """ Main remove method. """
         object = self._get_object(object_oid)
         classname = self._get_classname(object)
-        self._structureindex.delete(object_oid, parent_oid)
+        if self._structureindex.has_key(object_oid):
+            self._structureindex.delete(object_oid, parent_oid)
         if not self._structureindex.has_key(object_oid):
-            self._classindex.delete(classname, object_oid)
-            self._objectparser.parse(object)
-            for attr in self._objectparser.result("attributes"):
-                self._attributeindex.delete(attr, object_oid)
-            descendants = self._objectparser.result("descendants")[:]
-            for desc in descendants:
-                self.delete(self._get_oid(desc), object_oid)
+             self._classindex.delete(classname, object_oid)
+        self._objectparser.parse(object)
+        for attr in self._objectparser.result("attributes"):
+             self._attributeindex.delete(attr, object_oid)
+        descendants = self._objectparser.result("descendants")[:]
+        for desc in descendants:
+            self.delete(self._get_oid(desc), object_oid)

Modified: gocept.objectquery/trunk/src/gocept/objectquery/collection.txt
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/collection.txt	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/collection.txt	Wed Jun 11
16:30:39 2008
(at)(at) -33,6 +33,7 (at)(at)
 Using the ObjectCollection
 ==========================
 
+
 Example usage of ObjectCollection
 ---------------------------------
 
(at)(at) -40,8 +41,8 (at)(at)
 
     >>> t1 = testobjects.Telephone(number="22")
     >>> t2 = testobjects.Telephone(number="66")
-    >>> p1 = testobjects.Person(name="Sebastian", work=[t1, t2])
-    >>> a1 = testobjects.Address(street="Meckelstrasse",
city="Halle", ref=[p1])
+    >>> p1 = testobjects.Person(name="Sebastian")
+    >>> a1 = testobjects.Address(street="Meckelstrasse",
city="Halle")
     >>> dbroot['test'] = a1
     >>> transaction.commit()
 
(at)(at) -49,6 +50,17 (at)(at)
     >>> oc.root()[0] == a1._p_oid
     True
 
+    >>> a1.ref.append(p1)
+    >>> transaction.commit()
+    >>> oc.add(p1, a1._p_oid)
+
+    >>> p1.work.append(t1)
+    >>> p1.work.append(t2)
+    >>> transaction.commit()
+    >>> oc.add(t1, p1._p_oid)
+    >>> oc.add(t2, p1._p_oid)
+
+
 Verify the indexes:
 
     >>> result = oc._classindex.get("Telephone")
(at)(at) -64,6 +76,7 (at)(at)
     ...
     IndexError: list index out of range
 
+
 Search by classname:
 
     >>> r = oc.by_class("Telephone")
(at)(at) -75,6 +88,7 (at)(at)
     >>> conn.get(r[0][0])
     <gocept.objectquery.testobjects.Address object at 0x...>
 
+
 Adding and removing objects:
 ----------------------------
 
(at)(at) -111,13 +125,13 (at)(at)
     >>> len(oc.by_class("Telephone"))
     2
 
-    >>> oc.delete(p2._p_oid)
+    >>> oc.delete(p2._p_oid, pdb=True)
     >>> a1.ref.remove(p2)
     >>> transaction.commit()
-    >>> len(oc.by_class("Telephone"))
-    1
     >>> len(oc.by_class("Person"))
     1
+    >>> len(oc.by_class("Telephone"))
+    1
 
 Adding circles to collection
 ----------------------------

Modified: gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.py
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.py	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.py	Wed Jun 11
16:30:39 2008
(at)(at) -36,6 +36,10 (at)(at)
 
     def delete(self, key, value):
         """ Delete value from key. """
+        if not self.index.has_key(key):
+            return
+        if value not in self.index[key]:
+            return
         self.index[key].remove(value)
         if len(self.index[key]) == 0:
             del self.index[key]

Modified: gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.txt
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.txt	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.txt	Wed Jun 11
16:30:39 2008
(at)(at) -52,10 +52,6 (at)(at)
     >>> ci.delete("Student", 2)
     >>> ci.get('Student')
     [3]
-    >>> ci.delete("Student", 2)
-    Traceback (most recent call last):
-    ...
-    KeyError: 2
     >>> ci.delete("Course", 1)
     >>> ci.get("Course")
     []

Modified: gocept.objectquery/trunk/src/gocept/objectquery/processor.txt
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/processor.txt	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/processor.txt	Wed Jun 11
16:30:39 2008
(at)(at) -159,8 +159,10 (at)(at)
     >>> len(r) == 1 and r[0] == plo1
     True
 
-    >>> r = query('/Plone/_/Document')
-    >>> len(r) == 1 and r[0] == doc2
+    >>> r = query('/Plone/Folder/Document')
+    >>> len(r)
+    1
+    >>> r[0] == doc2
     True
 
 Get all Documents which are under any number of Folders:

SVN: r5934 - in gocept.infrastructure/trunk/util/backup: . src/gocept/backup/share
Christian Kauhaus <kc(at)gocept.com>
2008-06-16 13:37:46 [ FULL ]
Author: ckauhaus
Date: Mon Jun 16 13:37:42 2008
New Revision: 5934

Log:
version bump


Modified:
   gocept.infrastructure/trunk/util/backup/buildout.cfg
   gocept.infrastructure/trunk/util/backup/setup.py
   gocept.infrastructure/trunk/util/backup/src/gocept/backup/share/client.sh

Modified: gocept.infrastructure/trunk/util/backup/buildout.cfg
==============================================================================
--- gocept.infrastructure/trunk/util/backup/buildout.cfg	(original)
+++ gocept.infrastructure/trunk/util/backup/buildout.cfg	Mon Jun 16 13:37:42
2008
(at)(at) -16,7 +16,7 (at)(at)
 [test]
 recipe = zc.recipe.testrunner
 eggs = gocept.backup[test]
-defaults = ['--tests-pattern', 'test']
+defaults = ['--tests-pattern', 'test', '-c']
 
 [server.cfg]
 recipe = inquant.recipe.textfile

Modified: gocept.infrastructure/trunk/util/backup/setup.py
==============================================================================
--- gocept.infrastructure/trunk/util/backup/setup.py	(original)
+++ gocept.infrastructure/trunk/util/backup/setup.py	Mon Jun 16 13:37:42 2008
(at)(at) -2,7 +2,7 (at)(at)
 
 setup(
     name='gocept.backup',
-    version='0.1',
+    version='0.2',
     author='Christian Kauhaus',
     author_email='kc(at)gocept.com',
     url='http://www.gocept.com/',

Modified:
gocept.infrastructure/trunk/util/backup/src/gocept/backup/share/client.sh
==============================================================================
---
gocept.infrastructure/trunk/util/backup/src/gocept/backup/share/client.sh	(original)
+++
gocept.infrastructure/trunk/util/backup/src/gocept/backup/share/client.sh	Mon
Jun 16 13:37:42 2008
(at)(at) -4,7 +4,7 (at)(at)
 # further actions.
 set -e
 
-VERSION="0.1"
+VERSION="0.2"
 ETCDIR="${ROOTDIR}/etc"
 CONFDIR="${ETCDIR}/gocept-backup"

SVN: r5942 - in gocept.ooo2html/trunk/src/gocept/ooo2html: . testdata
Christian Zagrodnick <cz(at)gocept.com>
2008-06-17 11:01:43 [ FULL ]
Author: zagy
Date: Tue Jun 17 11:01:40 2008
New Revision: 5942

Log:
added tables and missing styles




Modified:
   gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt
   gocept.ooo2html/trunk/src/gocept/ooo2html/style.py
   gocept.ooo2html/trunk/src/gocept/ooo2html/testdata/testarticle.odt
   gocept.ooo2html/trunk/src/gocept/ooo2html/text.py

Modified: gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt
==============================================================================
--- gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt	(original)
+++ gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt	Tue Jun 17 11:01:40
2008
(at)(at) -12,6 +12,7 (at)(at)
 'application/vnd.oasis.opendocument.text'
 >>> import lxml.etree
 >>> html = file('/tmp/art.html', 'w')
+>>> print >>html, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML
1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
 >>> print >>html, "<html><head><style
type='text/css'>"
 >>> print >>html, convert.get_styles()
 >>> print >>html, "</style></head><body>"

Modified: gocept.ooo2html/trunk/src/gocept/ooo2html/style.py
==============================================================================
--- gocept.ooo2html/trunk/src/gocept/ooo2html/style.py	(original)
+++ gocept.ooo2html/trunk/src/gocept/ooo2html/style.py	Tue Jun 17 11:01:40 2008
(at)(at) -4,8 +4,16 (at)(at)
 
 import gocept.ooo2html.text
 
+BASE_STYLE = """\
+.Meta, 
+.Title,
+.Heading_20_1,
+.Autor {
+    display: none;
+}
+"""
 
-class StyleProcessor(gocept.ooo2html.text.Processor):
+class StyleProcessorBase(gocept.ooo2html.text.Processor):
     """Process style."""
 
     def __init__(self, node):
(at)(at) -18,11 +26,18 (at)(at)
         return ''.join(args)
 
 
-class Style(StyleProcessor):
+class StyleProcessor(StyleProcessorBase):
+
+    def apply(self):
+        css = super(StyleProcessor, self).apply()
+        return BASE_STYLE + css
+
+
+class Style(StyleProcessorBase):
     pass
 
 
-class BasePropertyProcessor(StyleProcessor):
+class BasePropertyProcessor(StyleProcessorBase):
 
     def apply(self):
         styles = self.get_styles()
(at)(at) -42,6 +57,14 (at)(at)
         ('{urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0}'
          'font-style'): 'font-style',
         ('{urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0}'
+         'margin-left'): 'margin-left',
+        ('{urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0}'
+         'margin-top'): 'margin-top',
+        ('{urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0}'
+         'margin-right'): 'margin-right',
+        ('{urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0}'
+         'margin-bottom'): 'margin-bottom',
+        ('{urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0}'
          'border-left'): 'border-left',
         ('{urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0}'
          'border-top'): 'border-top',
(at)(at) -49,6 +72,12 (at)(at)
          'border-right'): 'border-right',
         ('{urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0}'
          'border-bottom'): 'border-bottom',
+        ('{urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0}'
+         'text-transform'): 'text-transform',
+        ('{urn:oasis:names:tc:opendocument:xmlns:style:1.0}'
+         'column-width'): 'width',
+        ('{urn:oasis:names:tc:opendocument:xmlns:style:1.0}'
+         'width'): 'width',
     }
 
     def get_styles(self):
(at)(at) -58,17 +87,31 (at)(at)
             if value is not None:
                 styles[css_name] = value
 
-        # underline <style:text-properties
style:text-underline-color="font-color" style:text-underline-style="solid"
style:text-underline-width="auto"/>
-        # case-modification: upparcase, lowercase, capitalize
-        # Text-align left/right/justify
+        underline = self.node.get(
+            '{urn:oasis:names:tc:opendocument:xmlns:style:1.0}'
+            'text-underline-style')
+
+        if underline == 'solid':
+            styles['text-decoration'] = 'underline'
+
+        align = self.node.get(
+            '{urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0}'
+            'text-align')
+        if align == 'end':
+            styles['text-align'] = 'right'
+        elif align == 'justify':
+            styles['text-align'] = 'justify'
+        elif align == 'center':
+            styles['text-align'] = 'center'
+
         return styles
 
     def get_descriptor(self):
-        return '.%s' % (self.name, )
+        return '.%s' % (self.name.replace('.', '\\.'), )
 
 
 
-class ListStyle(StyleProcessor):
+class ListStyle(StyleProcessorBase):
     pass
 
 class ListLevelStyleNumber(BasePropertyProcessor):
(at)(at) -94,7 +137,7 (at)(at)
             level = int(level)
         except (ValueError, TypeError):
             level = 1
-        tag_name = 'ol.%s ' % self.name
+        tag_name = 'ol.%s ' % self.name.replace('.', '\\.')
         return (level * tag_name).strip()
 
     def get_style_type(self):
(at)(at) -108,8 +151,8 (at)(at)
     bullet_map = {
         u'\u25cf': 'disc',
         u'\u25a0': 'square',
-        u'\u25a0': 'dash',
-        u'\u2013': 'dash',
+        u'\u25a0': 'disc',
+        u'\u2013': 'disc',
         u'\u2022': 'disc',
         u'\u25cb': 'circle',
     }

Modified: gocept.ooo2html/trunk/src/gocept/ooo2html/testdata/testarticle.odt
==============================================================================
Binary files. No diff available.

Modified: gocept.ooo2html/trunk/src/gocept/ooo2html/text.py
==============================================================================
--- gocept.ooo2html/trunk/src/gocept/ooo2html/text.py	(original)
+++ gocept.ooo2html/trunk/src/gocept/ooo2html/text.py	Tue Jun 17 11:01:40 2008
(at)(at) -3,8 +3,17 (at)(at)
 
 import lxml.objectify
 
+
+PROCESSORS = {}
+
+def add_processor(processor):
+    PROCESSORS[processor.odt_tag] = processor
+
+
 class Processor(object):
 
+    odt_tag = None
+
     def __init__(self, node):
         self.node = node
         self.processors = PROCESSORS
(at)(at) -25,48 +34,124 (at)(at)
         return result_node
 
     def create_node(self, *args, **kwargs):
-        node = getattr(lxml.objectify.E, self.tag)(*args, **kwargs)
+        node = getattr(lxml.objectify.E, self.html_tag)(*args, **kwargs)
         lxml.objectify.deannotate(node)
-        style_name = self.node.get(
-            '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name')
-        if style_name is not None:
-            node.set('class', style_name)
+        styles = []
+        styles.append(self.node.get(
+            '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name'))
+        styles.append(self.node.get(
+            '{urn:oasis:names:tc:opendocument:xmlns:table:1.0}style-name'))
+        styles = ' '.join(s for s in styles if s)
+        if styles:
+            node.set('class', styles)
         return node
 
 
 class TextProcessor(Processor):
 
-    tag = 'div'
+    html_tag = 'div'
 
 
 
 class ParagraphProcessor(Processor):
     """Process <p> nodes."""
 
-    tag = 'p'
+    html_tag = 'p'
+    odt_tag = '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}p'
+
+add_processor(ParagraphProcessor)
+
+
+class SpanProcessor(Processor):
+    """Process <text:span>."""
+
+    html_tag = 'span'
+    odt_tag = '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}span'
+
+add_processor(SpanProcessor)
 
 
-class SpanProcessor(ParagraphProcessor):
+class HeadingProcessor(Processor):
     """Process <text:span>."""
 
-    tag = 'span'
+    odt_tag = '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}h'
+
+    (at)property
+    def html_tag(self):
+        level = self.node.get(
+            '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}outline-level')
+        if not level:
+            level = 1
+        return 'h%s' % (int(level) + 1)
+
+add_processor(HeadingProcessor)
 
 
 class ListProcessor(Processor):
 
-    tag = 'ol'
+    html_tag = 'ol'
+    odt_tag = '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}list'
+
+add_processor(ListProcessor)
 
 
 class ListItemProcessor(Processor):
 
-    tag = 'li'
+    html_tag = 'li'
+    odt_tag = '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}list-item'
+
+add_processor(ListItemProcessor)
+
+
+class TableProcessor(Processor):
+
+    html_tag = 'table'
+    odt_tag = '{urn:oasis:names:tc:opendocument:xmlns:table:1.0}table'
+
+    def create_node(self, *args, **kwargs):
+        node = super(TableProcessor, self).create_node(*args, **kwargs)
+        node.set('style', 'border-collapse: separate; border-spacing: 0')
+        return node
+
+
+add_processor(TableProcessor)
+
+
+class TableRowProcessor(Processor):
+
+    html_tag = 'tr'
+    odt_tag = '{urn:oasis:names:tc:opendocument:xmlns:table:1.0}table-row'
+
+add_processor(TableRowProcessor)
+
+
+class TableCellProcessor(Processor):
+
+    html_tag = 'td'
+    odt_tag = '{urn:oasis:names:tc:opendocument:xmlns:table:1.0}table-cell'
+
+    def create_node(self, *args, **kwargs):
+        node = super(TableCellProcessor, self).create_node(*args, **kwargs)
+        colspan = self.node.get(
+            '{urn:oasis:names:tc:opendocument:xmlns:table:1.0}'
+            'number-columns-spanned')
+        if colspan:
+            node.set('colspan', colspan)
+        rowspan = self.node.get(
+            '{urn:oasis:names:tc:opendocument:xmlns:table:1.0}'
+            'number-rows-spanned')
+        if rowspan:
+            node.set('rowspan', rowspan)
+        return node
+
+add_processor(TableCellProcessor)
+
+
+class TableHeaderProcessor(Processor):
 
+    html_tag = 'thead'
+    odt_tag = ('{urn:oasis:names:tc:opendocument:xmlns:table:1.0}'
+               'table-header-rows')
 
-PROCESSORS = {
-    '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}p': ParagraphProcessor,
-    '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}span': SpanProcessor,
-    '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}list': ListProcessor,
-    '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}list-item':
-        ListItemProcessor,
-}
 
+add_processor(TableHeaderProcessor)

SVN: r5946 - in buildout-recipes/gocept.nginx/trunk: . gocept/nginx
Christian Theune <ct(at)gocept.com>
2008-06-18 10:21:13 [ FULL ]
Author: ctheune
Date: Wed Jun 18 10:21:11 2008
New Revision: 5946

Log:
Fix error in ctl script.



Modified:
   buildout-recipes/gocept.nginx/trunk/README.txt
   buildout-recipes/gocept.nginx/trunk/gocept/nginx/nginxctl.in
   buildout-recipes/gocept.nginx/trunk/setup.py

Modified: buildout-recipes/gocept.nginx/trunk/README.txt
==============================================================================
--- buildout-recipes/gocept.nginx/trunk/README.txt	(original)
+++ buildout-recipes/gocept.nginx/trunk/README.txt	Wed Jun 18 10:21:11 2008
(at)(at) -26,8 +26,13 (at)(at)
 Changes
 =======
 
+0.9.1 (2008-06-18)
+------------------
+
+- Fix configtest command in the generated ctl script.
+
 0.9 (2008-01-14)
-+++
+----------------
 
 - Allowing configuration of config file location.
 

Modified: buildout-recipes/gocept.nginx/trunk/gocept/nginx/nginxctl.in
==============================================================================
--- buildout-recipes/gocept.nginx/trunk/gocept/nginx/nginxctl.in	(original)
+++ buildout-recipes/gocept.nginx/trunk/gocept/nginx/nginxctl.in	Wed Jun 18
10:21:11 2008
(at)(at) -27,7 +27,7 (at)(at)
     ;;
 configtest)
     echo "Testing nginx configuration "
-    $NGINX -t
+    $NGINX -c $CONFIGURATION -t
     ERROR=$?
     ;;
 esac

Modified: buildout-recipes/gocept.nginx/trunk/setup.py
==============================================================================
--- buildout-recipes/gocept.nginx/trunk/setup.py	(original)
+++ buildout-recipes/gocept.nginx/trunk/setup.py	Wed Jun 18 10:21:11 2008
(at)(at) -3,7 +3,7 (at)(at)
 name = "gocept.nginx"
 setup(
     name = name,
-    version = "0.9",
+    version = "0.9.1",
     author = "Christian Theune",
     author_email = "ct(at)gocept.com",
     description = "zc.buildout recipe for configuring an nginx server",

SVN: r5952 - in gocept.ooo2html/trunk/src/gocept/ooo2html: . testdata
Christian Zagrodnick <cz(at)gocept.com>
2008-06-18 14:01:39 [ FULL ]
Author: zagy
Date: Wed Jun 18 14:01:36 2008
New Revision: 5952

Log:
added template support
a

allowed to register the converter as global utility


Modified:
   gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt
   gocept.ooo2html/trunk/src/gocept/ooo2html/convert.py
   gocept.ooo2html/trunk/src/gocept/ooo2html/interfaces.py
   gocept.ooo2html/trunk/src/gocept/ooo2html/testdata/testarticle.odt

Modified: gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt
==============================================================================
--- gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt	(original)
+++ gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt	Wed Jun 18 14:01:36
2008
(at)(at) -1,18 +1,24 (at)(at)
 OOO2HTML
 ========
 
+Converting
+++++++++++
 
 >>> import os.path
 >>> import gocept.ooo2html.convert
 >>> filename = os.path.join(
 ...     os.path.dirname(__file__), 'testdata', 'testarticle.odt')
->>> ooo = file(filename, 'rb')
+>>> ooo = file(filename, 'rb+')
 >>> convert = gocept.ooo2html.convert.Convert(ooo)
 >>> convert.mimetype
 'application/vnd.oasis.opendocument.text'
 
 
->>> result = convert.apply()
+Let's use the `Converter` class:
+
+>>> converter = gocept.ooo2html.convert.Converter()
+>>> ooo.seek(0, 0)
+>>> result = converter.to_html(ooo)
 >>> result.created
 datetime.datetime(2004, 1, 14, 14, 46, 15)
 >>> result.modified
(at)(at) -557,4 +563,20 (at)(at)
 }
 
 
+Template support
+++++++++++++++++
 
+>>> odt = converter.get_template('Lorem ipsum', 'dolor', 'foo / bar')
+>>> result = converter.to_html(odt)
+>>> result.title
+'Lorem ipsum'
+>>> result.description
+'dolor'
+>>> result.section
+'foo / bar'
+>>> import datetime
+>>> now = datetime.datetime.now()
+>>> result.created.year == now.year
+True
+>>> result.modified.year == now.year
+True

Modified: gocept.ooo2html/trunk/src/gocept/ooo2html/convert.py
==============================================================================
--- gocept.ooo2html/trunk/src/gocept/ooo2html/convert.py	(original)
+++ gocept.ooo2html/trunk/src/gocept/ooo2html/convert.py	Wed Jun 18 14:01:36
2008
(at)(at) -1,7 +1,9 (at)(at)
 # Copyright (c) 2008 gocept gmbh & co. kg
 # See also LICENSE.txt
 
-import os
+import datetime
+import os.path
+import tempfile
 import zipfile
 
 import iso8601
(at)(at) -15,17 +17,46 (at)(at)
 import gocept.ooo2html.text
 
 
+TEMPLATE = os.path.join(os.path.dirname(__file__), 'template.odt')
+
+
 class Result(object):
 
     zope.interface.implements(gocept.ooo2html.interfaces.IResult)
 
 
-class Convert(object):
+class Converter(object):
+    """Central converter support."""
 
     zope.interface.implements(gocept.ooo2html.interfaces.IConverter)
 
+    def to_html(self, odt_file):
+        """Convert to html."""
+        convert = Convert(odt_file)
+        return convert.apply()
+
+    def get_template(self, title, description, section):
+        """Return template."""
+        odt = tempfile.TemporaryFile()
+        odt.write(file(TEMPLATE, 'rb').read())
+        odt.seek(0, 0)
+        convert = Convert(odt)
+        convert.set_title(title)
+        convert.set_description(description)
+        convert.set_section(section)
+        now = datetime.datetime.now()
+        convert.set_modified(now)
+        convert.set_created(now)
+        convert.write()
+        return odt
+
+
+class Convert(object):
+    """Internal convert class."""
+
     def __init__(self, infile):
-        self.zipfile = zipfile.ZipFile(infile, 'r')
+        infile.seek(0)
+        self.zipfile = zipfile.ZipFile(infile, 'a')
         self.mimetype = self.zipfile.read('mimetype')
         if self.mimetype != 'application/vnd.oasis.opendocument.text':
             raise ValueError("%s is not an ODT (got %s)" % (
(at)(at) -46,6 +77,8 (at)(at)
             '{http://purl.org/dc/elements/1.1/}date')
         result.image = self.get_text(
             '{urn:oasis:names:tc:opendocument:xmlns:meta:1.0}keyword')
+        result.section = self.get_text(
+            '{http://purl.org/dc/elements/1.1/}subject')
 
         result.css = self.get_styles()
         result.body = self.get_body()
(at)(at) -82,3 +115,45 (at)(at)
             dt = iso8601.parse_date(value)
             # Make naive because actually there is no tz info
             return dt.replace(tzinfo=None)
+
+    #
+    # Mutators
+    #
+
+    def set_title(self, title):
+        self._set_meta('{http://purl.org/dc/elements/1.1/}title',
title)
+
+    def set_description(self, description):
+        self._set_meta('{http://purl.org/dc/elements/1.1/}description',
+                       description)
+
+    def set_section(self, section):
+        self._set_meta('{http://purl.org/dc/elements/1.1/}subject',
+                       section)
+
+    def set_created(self, created):
+        self._set_date(
+            '{urn:oasis:names:tc:opendocument:xmlns:meta:1.0}creation-date',
+            created)
+
+    def set_modified(self, modified):
+        self._set_date(
+            '{http://purl.org/dc/elements/1.1/}date',
+            modified)
+
+    def write(self):
+        self.zipfile.writestr(
+            'meta.xml',
+            lxml.etree.tostring(self.meta,
+                                encoding='utf8',
+                                xml_declaration=True))
+
+    def _set_meta(self, name, value):
+        path = lxml.objectify.ObjectPath(
+            '.{urn:oasis:names:tc:opendocument:xmlns:office:1.0}meta.' +
+            name)
+        path.setattr(self.meta, value)
+
+    def _set_date(self, name, value):
+        value = value.strftime('%Y-%m-%dT%H:%M:%S')
+        self._set_meta(name, value)

Modified: gocept.ooo2html/trunk/src/gocept/ooo2html/interfaces.py
==============================================================================
--- gocept.ooo2html/trunk/src/gocept/ooo2html/interfaces.py	(original)
+++ gocept.ooo2html/trunk/src/gocept/ooo2html/interfaces.py	Wed Jun 18 14:01:36
2008
(at)(at) -8,15 +8,19 (at)(at)
 class IConverter(zope.interface.Interface):
     """Convert."""
 
-    def apply():
+    def to_html(odt_file):
         """Apply converter, return IResult instance."""
 
+    def get_template(title, description, section):
+        """Return template with filled in data."""
+
 
 class IResult(zope.interface.Interface):
     """Result of converter."""
 
     title = zope.schema.TextLine(title=u"Title")
     description = zope.schema.TextLine(title=u"Description")
+    section = zope.schema.TextLine(title=u"Section")
     created = zope.schema.Datetime(title=u"Creation date")
     modifed = zope.schema.Datetime(title=u"Modifcation date")
     image = zope.schema.TextLine(title=u"Nr. of Image")

Modified: gocept.ooo2html/trunk/src/gocept/ooo2html/testdata/testarticle.odt
==============================================================================
Binary files. No diff available.

SVN: r5957 - in gocept.vendo/trunk: . src
Sebastian Wehrmann <sw(at)gocept.com>
2008-06-18 14:52:06 [ FULL ]
Author: sweh
Date: Wed Jun 18 14:52:02 2008
New Revision: 5957

Log:
updated propsets



Modified:
   gocept.vendo/trunk/   (props changed)
   gocept.vendo/trunk/src/   (props changed)

SVN: r5960 - in gocept.infrastructure/trunk/util/backup: . src/gocept/backup
Christian Kauhaus <kc(at)gocept.com>
2008-06-19 09:55:47 [ FULL ]
Author: ckauhaus
Date: Thu Jun 19 09:55:46 2008
New Revision: 5960

Log:
ping hosts to check connectivity before backup [gocept #65212]


Modified:
   gocept.infrastructure/trunk/util/backup/buildout.cfg
   gocept.infrastructure/trunk/util/backup/src/gocept/backup/errors.txt
   gocept.infrastructure/trunk/util/backup/src/gocept/backup/metadata.py
   gocept.infrastructure/trunk/util/backup/src/gocept/backup/server.py
   gocept.infrastructure/trunk/util/backup/src/gocept/backup/server.txt
   gocept.infrastructure/trunk/util/backup/src/gocept/backup/test_metadata.py

Modified: gocept.infrastructure/trunk/util/backup/buildout.cfg
==============================================================================
--- gocept.infrastructure/trunk/util/backup/buildout.cfg	(original)
+++ gocept.infrastructure/trunk/util/backup/buildout.cfg	Thu Jun 19 09:55:46
2008
(at)(at) -25,8 +25,10 (at)(at)
 etc-directory = ${buildout:etc-directory}
 var-directory = ${buildout:var-directory}
 backup-directory = ${buildout:backup-directory}
+location = ${buildout:parts-directory}/server.cfg
 
 [hosts.cfg]
 recipe = inquant.recipe.textfile
 template-directory = ${buildout:template-directory}
 template = hosts.cfg
+location = ${buildout:parts-directory}/hosts.cfg

Modified: gocept.infrastructure/trunk/util/backup/src/gocept/backup/errors.txt
==============================================================================
---
gocept.infrastructure/trunk/util/backup/src/gocept/backup/errors.txt	(original)
+++ gocept.infrastructure/trunk/util/backup/src/gocept/backup/errors.txt	Thu
Jun 19 09:55:46 2008
(at)(at) -112,12 +112,16 (at)(at)
    >>> m = mock.replace(gocept.backup.metadata)
    >>> meta = m.Metadata(mocker.ARGS)
    >>> mock.count(2)
+   >>> e = meta.host_reachable()
+   >>> mock.result(True)
+   >>> mock.count(2)
    >>> e = meta.load()
    >>> mock.count(2)
    >>> e = meta.partitions()
    >>> mock.result([u'/part-a1', u'/part-a2'])
    >>> e = meta.partitions()
    >>> mock.result([u'/part-b1'])
-   >>> shellcmd = mock.replace(gocept.backup.shellcmd.shellcmd)
-   >>> e = shellcmd(u'ssh-keygen', mocker.ARGS)
+   >>> keygen = mock.replace(gocept.backup.shellcmd.shellcmd)
+   >>> e = keygen(u'ssh-keygen', mocker.ARGS)
+   >>> mock.count(1, None)
    >>> mock.count(1, None)

Modified: gocept.infrastructure/trunk/util/backup/src/gocept/backup/metadata.py
==============================================================================
---
gocept.infrastructure/trunk/util/backup/src/gocept/backup/metadata.py	(original)
+++ gocept.infrastructure/trunk/util/backup/src/gocept/backup/metadata.py	Thu
Jun 19 09:55:46 2008
(at)(at) -96,9 +96,14 (at)(at)
         """Indicate that all partitions on the host have been backed up."""
         file(self.successmarker, 'w').write(time.asctime() + u'\n')
 
-    (at)property
     def host_skippable(self):
         """Return true if there is a recent enough backup of this host."""
         if not os.path.exists(self.successmarker):
             return False
         return time.asctime()[0:10] == file(self.successmarker).read()[0:10]
+
+    def host_reachable(self):
+        """Return true if the host responds to ping."""
+        (stdout, stderr, returncode) = shellcmd(
+            u'ping', [u'-c4', u'-q'], accept_failure=True)
+        return (0 == returncode)

Modified: gocept.infrastructure/trunk/util/backup/src/gocept/backup/server.py
==============================================================================
---
gocept.infrastructure/trunk/util/backup/src/gocept/backup/server.py	(original)
+++ gocept.infrastructure/trunk/util/backup/src/gocept/backup/server.py	Thu Jun
19 09:55:46 2008
(at)(at) -112,10 +112,13 (at)(at)
         keyfiles = self.sshkeys.check(self.hosts)
         for host in self.hosts:
             meta = gocept.backup.metadata.Metadata(host, self.conf)
-            if meta.host_skippable:
+            if meta.host_skippable():
                 self.log.info(u'Skipping %s since we have a recent backup',
                               host)
                 continue
+            if not meta.host_reachable():
+                self.log.info(u'Skipping %s because of failed ping', host)
+                continue
             try:
                 meta.load()
                 for partition in meta.partitions():

Modified: gocept.infrastructure/trunk/util/backup/src/gocept/backup/server.txt
==============================================================================
---
gocept.infrastructure/trunk/util/backup/src/gocept/backup/server.txt	(original)
+++ gocept.infrastructure/trunk/util/backup/src/gocept/backup/server.txt	Thu
Jun 19 09:55:46 2008
(at)(at) -152,20 +152,45 (at)(at)
 >>> re.search(r'^Errors 0$', file(summary).read(), re.M) >= 0
 True
 
+All mocker expectations should have been met:
+
+>>> mock.restore()
+>>> mock.verify()
 
-Cleanup
--------
+
+Testing for host connectivity
+-----------------------------
+
+The backup server checks if a host is alive by performing a ping test first.
If
+ping does not succeed, no backup is being taken.
+
+>>> mock = mocker.Mocker()
+>>> shellcmd = mock.replace('gocept.backup.shellcmd.shellcmd')
+>>> e = shellcmd(u'ping', mocker.ARGS, mocker.KWARGS)
+>>> e = mock.result(('', '', 1))
+>>> mock.replay()
+>>> os.remove(u'server/localhost/success')
+>>> s.run()
+>>> show_log()
+Checking SSH keys for [localhost]
+Skipping localhost because of failed ping
 
 All mocker expectations should have been met.
 
 >>> mock.restore()
 >>> mock.verify()
 
-Test files should be deleted as well:
+
+Cleanup
+-------
+
+Delete test files:
 
 >>> os.unlink(u'hosts.cfg')
 >>> os.unlink(u'backup_localhost.tar.gz')
 >>> os.unlink(u'backup_grampa.whq.gocept.com.tar.gz')
+>>> shutil.rmtree(u'server')
+>>> shutil.rmtree(u'backup')
 
 
 Footnotes
(at)(at) -189,16 +214,12 (at)(at)
    deleted:
 
    >>> shutil.rmtree('server', ignore_errors=True)
+   >>> shutil.rmtree('backup/localhost', ignore_errors=True)
 
    We suppress console output:
 
    >>> sys.argv[1:] = [u'-q']
 
-   There may be runtime data left from previous tests which should be deleted:
-
-   >>> shutil.rmtree('server', ignore_errors=True)
-   >>> shutil.rmtree('backup/localhost', ignore_errors=True)
-
    We plug in a test logger to capture progress:
 
    >>> log = StringIO()
(at)(at) -233,4 +254,6 (at)(at)
    ...   return ('', '', 0)
    >>> e = shellcmd(u'rdiff-backup', mocker.ARGS, mocker.KWARGS)
    >>> e = mock.call(create_mock_backup)
+   >>> e = shellcmd(u'ping', mocker.ARGS, mocker.KWARGS)
+   >>> e = mock.result(('', '', 0))
    >>> mock.replay()

Modified:
gocept.infrastructure/trunk/util/backup/src/gocept/backup/test_metadata.py
==============================================================================
---
gocept.infrastructure/trunk/util/backup/src/gocept/backup/test_metadata.py	(original)
+++
gocept.infrastructure/trunk/util/backup/src/gocept/backup/test_metadata.py	Thu
Jun 19 09:55:46 2008
(at)(at) -112,10 +112,10 (at)(at)
         mocker.expect(asctime()).result('Mon Jun  9 23:59:00 2008')
         self.mock.replay()
         self.meta.mark_success()
-        self.assertEqual(True, self.meta.host_skippable)
+        self.assertEqual(True, self.meta.host_skippable())
 
     def test_not_skippable_if_no_marker(self):
-        self.assertEqual(False, self.meta.host_skippable)
+        self.assertEqual(False, self.meta.host_skippable())
 
     def test_not_skippable_on_next_day(self):
         asctime = self.mock.replace(u'time.asctime')
(at)(at) -123,7 +123,22 (at)(at)
         mocker.expect(asctime()).result('Tue Jun 10 00:00:00 2008')
         self.mock.replay()
         self.meta.mark_success()
-        self.assertEqual(False, self.meta.host_skippable)
+        self.assertEqual(False, self.meta.host_skippable())
+
+    def test_host_unreachable(self):
+        shellcmd = self.mock.replace('gocept.backup.shellcmd.shellcmd')
+        shellcmd('ping', mocker.ARGS, mocker.KWARGS)
+        self.mock.result(('', '', 1))
+        self.mock.replay()
+        self.assertEqual(False, self.meta.host_reachable())
+
+
+    def test_host_reachable(self):
+        shellcmd = self.mock.replace('gocept.backup.shellcmd.shellcmd')
+        shellcmd('ping', mocker.ARGS, mocker.KWARGS)
+        self.mock.result(('', '', 0))
+        self.mock.replay()
+        self.assertEqual(True, self.meta.host_reachable())
 
 
 class MetadataMinimalFilesTest(MetadataTestBase):

SVN: r5963 - gocept.ooo2html/trunk/src/gocept/ooo2html
Christian Zagrodnick <cz(at)gocept.com>
2008-06-19 14:21:08 [ FULL ]
Author: zagy
Date: Thu Jun 19 14:21:05 2008
New Revision: 5963

Log:
added template



Added:
   gocept.ooo2html/trunk/src/gocept/ooo2html/template.odt   (contents, props
changed)

Added: gocept.ooo2html/trunk/src/gocept/ooo2html/template.odt
==============================================================================
Binary file. No diff available.

SVN: r5965 - gocept.ooo2html/trunk/src/gocept/ooo2html
Daniel Havlik <dh(at)gocept.com>
2008-06-20 14:02:53 [ FULL ]
Author: nilo
Date: Fri Jun 20 14:02:52 2008
New Revision: 5965

Log:
adding support for converting creator



Modified:
   gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt
   gocept.ooo2html/trunk/src/gocept/ooo2html/convert.py

Modified: gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt
==============================================================================
--- gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt	(original)
+++ gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt	Fri Jun 20 14:02:52
2008
(at)(at) -24,6 +24,8 (at)(at)
 >>> result.modified
 datetime.datetime(2008, 6, 17, 11, 46, 44)
 
+>>> result.creator
+'Chrstian Zagrodnick'
 >>> result.title
 'Kontakt gesucht: Osee Romeo Tcheupgoum, Kamerun'
 >>> result.description

Modified: gocept.ooo2html/trunk/src/gocept/ooo2html/convert.py
==============================================================================
--- gocept.ooo2html/trunk/src/gocept/ooo2html/convert.py	(original)
+++ gocept.ooo2html/trunk/src/gocept/ooo2html/convert.py	Fri Jun 20 14:02:52
2008
(at)(at) -73,6 +73,8 (at)(at)
             '{http://purl.org/dc/elements/1.1/}description')
         result.created = self.get_date(
             '{urn:oasis:names:tc:opendocument:xmlns:meta:1.0}creation-date')
+        result.creator = self.get_text(
+            '{http://purl.org/dc/elements/1.1/}creator')
         result.modified = self.get_date(
             '{http://purl.org/dc/elements/1.1/}date')
         result.image = self.get_text(

SVN: r5967 - in gocept.vendo/trunk/src/gocept/vendo: . browser tests
Sebastian Wehrmann <sw(at)gocept.com>
2008-06-20 16:40:30 [ FULL ]
Author: sweh
Date: Fri Jun 20 16:40:29 2008
New Revision: 5967

Log:
fixed an error in template



Modified:
   gocept.vendo/trunk/src/gocept/vendo/browser/finish_checkout.pt
   gocept.vendo/trunk/src/gocept/vendo/configure.zcml
   gocept.vendo/trunk/src/gocept/vendo/tests/browser.txt

Modified: gocept.vendo/trunk/src/gocept/vendo/browser/finish_checkout.pt
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/browser/finish_checkout.pt	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/browser/finish_checkout.pt	Fri Jun 20
16:40:29 2008
(at)(at) -47,7 +47,7 (at)(at)
       <input type="text" name="EXPDATE_year" value=""/><br/>
       <input type="text" name="CARDISSUE" value=""/><br/>
       <input type="text" name="CVV2" value=""/><br/>
-      <input type="text" name="FIRSTNAME" value="" tal:attributes="value
view/payment_address/firstname_" /><br/>
+      <input type="text" name="FIRSTNAME" value="" tal:attributes="value
view/payment_address/firstname" /><br/>
       <input type="text" name="LASTNAME" value="" tal:attributes="value
view/payment_address/lastname" /><br/>
       <input type="text" name="STREET" value="" tal:attributes="value
view/payment_address/street" /><br/>
       <input type="text" name="STREET2" value="" tal:attributes="value
view/payment_address/street2" /><br/>

Modified: gocept.vendo/trunk/src/gocept/vendo/configure.zcml
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/configure.zcml	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/configure.zcml	Fri Jun 20 16:40:29 2008
(at)(at) -10,11 +10,6 (at)(at)
     <include package=".content" />
     <include package=".portlets" />
 
-    <adapter factory=".cart.SessionCart" />
-    <adapter factory=".shipping.ShippingProvider" />
-    <adapter factory=".order.OrderFactory" />
-    <adapter factory=".payment.PayPalDataProvider" />
-
     <genericsetup:registerProfile
       name="default"
       title="Vendo Content Types"
(at)(at) -23,6 +18,11 (at)(at)
       provides="Products.GenericSetup.interfaces.EXTENSION"
      />
 
+    <adapter factory=".cart.SessionCart" />
+    <adapter factory=".shipping.ShippingProvider" />
+    <adapter factory=".order.OrderFactory" />
+    <adapter factory=".payment.PayPalDataProvider" />
+
     <subscriber
       handler=".eventhandler.onObjectAdded"
     />

Modified: gocept.vendo/trunk/src/gocept/vendo/tests/browser.txt
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/tests/browser.txt	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/tests/browser.txt	Fri Jun 20 16:40:29
2008
(at)(at) -7,7 +7,7 (at)(at)
 
 We need a testbrowser:
 
-    >>> from zope.testbrowser import Browser
+    >>> from Products.Five.testbrowser import Browser
     >>> browser = Browser()
     >>> portal_url = self.portal.absolute_url()

SVN: r5970 - gocept.vendo/trunk/src/gocept/vendo
Daniel Havlik <dh(at)gocept.com>
2008-06-23 08:41:21 [ FULL ]
Author: nilo
Date: Mon Jun 23 08:41:20 2008
New Revision: 5970

Log:
adding currency field to paymentdataprovider



Modified:
   gocept.vendo/trunk/src/gocept/vendo/payment.py

Modified: gocept.vendo/trunk/src/gocept/vendo/payment.py
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/payment.py	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/payment.py	Mon Jun 23 08:41:20 2008
(at)(at) -18,6 +18,7 (at)(at)
         self.username = shop.getPaypal_username()
         self.password = shop.getPaypal_password()
         self.signature = shop.getPaypal_signature()
+        self.currency = shop.getCurrency()
         self.version = shop.getPaypal_version()
         self.paypal_url = shop.getPaypal_url()
         self.api_endpoint = shop.getPaypal_api_endpoint()

SVN: r5971 - gocept.vendo/trunk/src/gocept/vendo
Daniel Havlik <dh(at)gocept.com>
2008-06-23 08:41:51 [ FULL ]
Author: nilo
Date: Mon Jun 23 08:41:49 2008
New Revision: 5971

Log:
using persistentlist to store cart items



Modified:
   gocept.vendo/trunk/src/gocept/vendo/cart.py

Modified: gocept.vendo/trunk/src/gocept/vendo/cart.py
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/cart.py	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/cart.py	Mon Jun 23 08:41:49 2008
(at)(at) -2,7 +2,7 (at)(at)
 from zope.component import adapts, getUtility
 from OFS.SimpleItem import SimpleItem
 from Products.CMFCore.utils import getToolByName
-
+import persistent.list
 from gocept.vendo.interfaces.cart import ICart, ICartItem, ICartProvider,\
         ICartUtility
 from gocept.vendo.config import SHIPS_TO
(at)(at) -58,7 +58,7 (at)(at)
     implements(ICart)
 
     def __init__(self):
-        self._cart_content = []
+        self._cart_content = persistent.list.PersistentList()
         self._shipping_method = None
         self._shipping_address = None
         self._invoice_address = None

SVN: r5972 - gocept.vendo/trunk/src/gocept/vendo/browser
Daniel Havlik <dh(at)gocept.com>
2008-06-23 08:42:33 [ FULL ]
Author: nilo
Date: Mon Jun 23 08:42:31 2008
New Revision: 5972

Log:
added some css ids and classes to templates



Modified:
   gocept.vendo/trunk/src/gocept/vendo/browser/cart.pt
   gocept.vendo/trunk/src/gocept/vendo/browser/cart_macros.pt
   gocept.vendo/trunk/src/gocept/vendo/browser/checkout.pt
   gocept.vendo/trunk/src/gocept/vendo/browser/checkout.py
   gocept.vendo/trunk/src/gocept/vendo/browser/finish_checkout.pt

Modified: gocept.vendo/trunk/src/gocept/vendo/browser/cart.pt
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/browser/cart.pt	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/browser/cart.pt	Mon Jun 23 08:42:31
2008
(at)(at) -13,26 +13,26 (at)(at)
       Shopping Cart (overview)
     </h1>
 
-    <form
+    <form id="vendocart_form"
       method="get"
       tal:attributes="action string:${context/absolute_url}/${view/__name__}"
       tal:define="cart view/cart">
       <input type="hidden" name="form.submitted" value="1" />
-      <table>
+      <table id="vendocart" cellspacing="0" cellpadding="0">
         <thead>
           <tr>
             <th>Pos.</th>
             <th>Product</th>
             <th>Amount</th>
-            <th>Price ()</th>
-            <th>Total ()</th>
+            <th>Price</th>
+            <th>Total</th>
             <th></th>
           </tr>
         </thead>
         <tbody>
-          <tr tal:repeat="cartitem cart/get_items">
+          <tr class="itemline" tal:repeat="cartitem cart/get_items">
             <td tal:content="repeat/cartitem/number" />
-            <td tal:content="cartitem/title" />
+            <td class="itemname" tal:content="cartitem/title" />
             <td>
               <input type="text" size="2" name="amount_id"
                      tal:attributes="
(at)(at) -75,7 +75,7 (at)(at)
           <tr>
             <td></td>
             <td colspan="3">
-              Tax (<span tal:replace="cart/get_vat_rate" />)
+              Tax (<span tal:replace="cart/get_vat_rate" /> %)
             </td>
             <td tal:content="cart/get_vat/(at)(at)pricedisplay" />
             <td></td>

Modified: gocept.vendo/trunk/src/gocept/vendo/browser/cart_macros.pt
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/browser/cart_macros.pt	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/browser/cart_macros.pt	Mon Jun 23
08:42:31 2008
(at)(at) -6,20 +6,20 (at)(at)
 <!-- ********************** -->
 
 <div metal:define-macro="display_cart">
-    <table>
+    <table id="vendocart" cellpadding="0" cellspacing="0">
       <thead>
         <tr>
           <td>Pos.</td>
           <td>Product</td>
           <td>Amount</td>
-          <td>Price ()</td>
-          <td>Total ()</td>
+          <td>Price</td>
+          <td>Total</td>
         </tr>
       </thead>
       <tbody>
-        <tr tal:repeat="cartitem cart/get_items">
+        <tr class="itemline" tal:repeat="cartitem cart/get_items">
           <td tal:content="repeat/cartitem/number" />
-          <td tal:content="cartitem/title" />
+          <td class="itemname" tal:content="cartitem/title" />
           <td tal:content="cartitem/amount" />
           <td tal:content="cartitem/price" />
           <td tal:content="cartitem/sum" />
(at)(at) -39,7 +39,7 (at)(at)
         <tr>
           <td></td>
           <td colspan="3">
-            Tax (<span tal:replace="cart/get_vat_rate" />)
+            Tax (<span tal:replace="cart/get_vat_rate" /> %)
           </td>
           <td tal:content="cart/get_vat" />
         </tr>
(at)(at) -62,7 +62,7 (at)(at)
 <!-- * address::Address    * -->
 <!-- *********************** -->
 
-<div metal:define-macro="display_address">
+<div metal:define-macro="display_address" class="disp_address">
     <span tal:content="address/firstname" /> <span
tal:content="address/lastname"/>
     <div tal:condition="address/company" tal:content="address/company"
/>
     <div tal:condition="address/street" tal:content="address/street" />

Modified: gocept.vendo/trunk/src/gocept/vendo/browser/checkout.pt
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/browser/checkout.pt	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/browser/checkout.pt	Mon Jun 23 08:42:31
2008
(at)(at) -10,7 +10,7 (at)(at)
 <metal:main fill-slot="main">
   <tal:main-macro metal:define-macro="main" tal:define="cart view/cart">
     <h1 class="documentFirstHeading">
-      Shopping Cart (CheckOut)
+      Shopping Cart
     </h1>
     <div metal:use-macro="context/(at)(at)cart_macros/display_cart" />
     <hr />
(at)(at) -20,7 +20,7 (at)(at)
       tal:define="cart view/cart; errors view/errors">
       <table><tr><td>
       <div id="shipping_address">
-      <label>Shipping address:</label>
+      <h3>Shipping address:</h3>
       <table tal:define="address cart/get_shipping_address"
         id="shipping_address">
         <tr>
(at)(at) -28,7 +28,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('shipping_firstname',\
                               None) and 'field error' or 'field'">
-              <label id="firstname">
+              <label for="firstname">
                 Firstname:
               </label>
               <span tal:replace="python: 'firstname' in
address.required_fields\
(at)(at) -48,7 +48,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('shipping_lastname',\
                               None) and 'field error' or 'field'">
-              <label id="lastname">
+              <label for="lastname">
                 Lastname:
               </label>
               <span tal:replace="python: 'lastname' in
address.required_fields\
(at)(at) -68,7 +68,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('shipping_company',\
                               None) and 'field error' or 'field'">
-              <label id="company">
+              <label for="company">
                 Company:
               </label>
               <span tal:replace="python: 'company' in
address.required_fields\
(at)(at) -88,7 +88,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('shipping_street',\
                               None) and 'field error' or 'field'">
-              <label id="street">
+              <label for="street">
                 Street:
               </label>
               <span tal:replace="python: 'street' in
address.required_fields\
(at)(at) -108,7 +108,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('shipping_street2',\
                               None) and 'field error' or 'field'">
-              <label id="street2">
+              <label for="street2">
                 Street2:
               </label>
               <span tal:replace="python: 'street2' in
address.required_fields\
(at)(at) -128,7 +128,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('shipping_city',\
                               None) and 'field error' or 'field'">
-              <label id="city">
+              <label for="city">
                 City:
               </label>
               <span tal:replace="python: 'city' in address.required_fields\
(at)(at) -148,7 +148,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('shipping_zip',\
                               None) and 'field error' or 'field'">
-              <label id="zip">
+              <label for="zip">
                 Zip:
               </label>
               <span tal:replace="python: 'zip' in address.required_fields\
(at)(at) -168,7 +168,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('shipping_country',\
                               None) and 'field error' or 'field'">
-              <label id="country">
+              <label for="country">
                 Country:
               </label>
               <span tal:replace="python: 'country' in
address.required_fields\
(at)(at) -199,7 +199,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('shipping_phone',\
                               None) and 'field error' or 'field'">
-              <label id="phone">
+              <label for="phone">
                 Phone:
               </label>
               <span tal:replace="python: 'phone' in
address.required_fields\
(at)(at) -219,7 +219,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('shipping_mail',\
                               None) and 'field error' or 'field'">
-              <label id="mail">
+              <label for="mail">
                 Mail:
               </label>
               <span tal:replace="python: 'mail' in address.required_fields\
(at)(at) -238,7 +238,7 (at)(at)
       </div>
       </td><td>
       <div id="invoice_address">
-      <label>Invoice address:</label><br />
+          <h3>Invoice address:</h3>
       <input type="checkbox" name="invoice_same_as_shipping"
value="Selected"
         tal:attributes="checked python: cart.get_invoice_same_as_shipping()\
                           and 'CHECKED' or ''" />
(at)(at) -250,7 +250,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('invoice_firstname',\
                               None) and 'field error' or 'field'">
-              <label id="firstname">
+              <label for="firstname">
                 Firstname:
               </label>
               <span tal:replace="python: 'firstname' in
address.required_fields\
(at)(at) -270,7 +270,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('invoice_lastname',\
                               None) and 'field error' or 'field'">
-              <label id="lastname">
+              <label for="lastname">
                 Lastname:
               </label>
               <span tal:replace="python: 'lastname' in
address.required_fields\
(at)(at) -290,7 +290,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('invoice_company',\
                               None) and 'field error' or 'field'">
-              <label id="company">
+              <label for="company">
                 Company:
               </label>
               <span tal:replace="python: 'company' in
address.required_fields\
(at)(at) -310,7 +310,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('invoice_street',\
                               None) and 'field error' or 'field'">
-              <label id="street">
+              <label for="street">
                 Street:
               </label>
               <span tal:replace="python: 'street' in
address.required_fields\
(at)(at) -330,7 +330,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('invoice_street2',\
                               None) and 'field error' or 'field'">
-              <label id="street2">
+              <label for="street2">
                 Street2:
               </label>
               <span tal:replace="python: 'street2' in
address.required_fields\
(at)(at) -350,7 +350,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('invoice_city',\
                               None) and 'field error' or 'field'">
-              <label id="city">
+              <label for="city">
                 City:
               </label>
               <span tal:replace="python: 'city' in address.required_fields\
(at)(at) -370,7 +370,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('invoice_zip',\
                               None) and 'field error' or 'field'">
-              <label id="zip">
+              <label for="zip">
                 Zip:
               </label>
               <span tal:replace="python: 'zip' in address.required_fields\
(at)(at) -390,7 +390,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('invoice_country',\
                               None) and 'field error' or 'field'">
-              <label id="country">
+              <label for="country">
                 Country:
               </label>
               <span tal:replace="python: 'country' in
address.required_fields\
(at)(at) -421,7 +421,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('invoice_phone',\
                               None) and 'field error' or 'field'">
-              <label id="phone">
+              <label for="phone">
                 Phone:
               </label>
               <span tal:replace="python: 'phone' in
address.required_fields\
(at)(at) -441,7 +441,7 (at)(at)
             <div
               tal:attributes="class python: errors.get('invoice_mail',\
                               None) and 'field error' or 'field'">
-              <label id="mail">
+              <label for="mail">
                 Mail:
               </label>
               <span tal:replace="python: 'mail' in address.required_fields\
(at)(at) -462,7 +462,7 (at)(at)
       <div
         tal:attributes="class python: errors.get('terms_and_conditions',\
                         None) and 'field error' or 'field'">
-        <label id="terms_and_consitions">
+        <label for="terms_and_consitions">
           Terms and Conditions:
         </label>
         <span tal:replace="python: 'terms_and_conditions' in
cart.extra_required\

Modified: gocept.vendo/trunk/src/gocept/vendo/browser/checkout.py
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/browser/checkout.py	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/browser/checkout.py	Mon Jun 23 08:42:31
2008
(at)(at) -34,17 +34,17 (at)(at)
         self.invoice_address = self.cart.get_invoice_address()
         shipping_address = self.shipping_address =
self.cart.get_shipping_address()
         payment_address = {}
-	payment_address['firstname'] = shipping_address.firstname
-	payment_address['lastname'] = shipping_address.lastname
-	payment_address['street'] = shipping_address.street
-	payment_address['street2'] = shipping_address.street2
-	payment_address['city'] = shipping_address.city
-	payment_address['state'] = shipping_address.us_state
-	payment_address['country'] = shipping_address.country
-	payment_address['zip'] = shipping_address.zip
+        payment_address['firstname'] = shipping_address.firstname
+        payment_address['lastname'] = shipping_address.lastname
+        payment_address['street'] = shipping_address.street
+        payment_address['street2'] = shipping_address.street2
+        payment_address['city'] = shipping_address.city
+        payment_address['state'] = shipping_address.us_state
+        payment_address['country'] = shipping_address.country
+        payment_address['zip'] = shipping_address.zip
         
-	self.payment_address = payment_address
-	form = self.request.form
+        self.payment_address = payment_address
+        form = self.request.form
         response = self.request.RESPONSE
         submitted = form.get('submitted')
         change_address = form.get('change_address')
(at)(at) -54,12 +54,11 (at)(at)
 
         callback_url, callback_cancel_url = _get_callback_and_cancel_urls(
                                                         shop, self.request)
-        #token = paypal.SetExpressCheckout(final_amount, callback_url,
-        #                                  callback_cancel_url)
+        token = paypal.SetExpressCheckout(final_amount, callback_url,
+                                          callback_cancel_url)
         # no expresscheckout for now
-	token = ''
-	
-	self.paypal_url = "%s%s" % (shop.paypal_url, token)
+        #token = ''
+        self.paypal_url = "%s%s" % (shop.paypal_url, token)
 
         if submitted and change_address:
             #redirect to checkout view

Modified: gocept.vendo/trunk/src/gocept/vendo/browser/finish_checkout.pt
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/browser/finish_checkout.pt	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/browser/finish_checkout.pt	Mon Jun 23
08:42:31 2008
(at)(at) -12,31 +12,31 (at)(at)
     <h1 class="documentFirstHeading">
       Payment (CheckOut)
     </h1>
-    <form method="get" tal:attributes="
+    <form id="finish_form" method="get" tal:attributes="
             action string:${context/absolute_url}/${view/__name__}">
     <input type="hidden" name="submitted" value="1" />
     <div metal:use-macro="context/(at)(at)cart_macros/display_cart" />
-    <input type="submit" name="change_cart" value="Edit cart" />
+    <input type="submit" id="editcart" name="change_cart" value="Edit cart"
/>
         <hr />
     <tal:shipping define="address cart/shipping_address">
-      <h3 tal:condition="not: cart/get_invoice_same_as_shipping">
+      <h3 id="address" tal:condition="not:
cart/get_invoice_same_as_shipping">
         Shipping Address
       </h3>
-      <h3 tal:condition="cart/get_invoice_same_as_shipping">
+      <h3 id="address"
tal:condition="cart/get_invoice_same_as_shipping">
         Shipping and Invoice Address
       </h3>
       <div metal:use-macro="context/(at)(at)cart_macros/display_address"
/>
     </tal:shipping>
 
     <tal:invoice define="address cart/invoice_address">
-      <h3 tal:condition="not: cart/get_invoice_same_as_shipping">
+      <h3 id="inv_address" tal:condition="not:
cart/get_invoice_same_as_shipping">
         Invoice Address
       </h3>
       <div metal:use-macro="context/(at)(at)cart_macros/display_address"
/>
     </tal:invoice>
     <input type="submit" name="change_address" value="Edit address" />
     </form>
-    <h3>Payment</h3>
+    <h3 id="payment">Payment</h3>
     <form method="post" tal:attributes="
             action string:${context/absolute_url}/${view/__name__}">
       <input type="text" name="CARDTYPE" value=""/><br/>

SVN: r5973 - in gocept.ooo2html/trunk/src/gocept/ooo2html: . testdata
Christian Zagrodnick <cz(at)gocept.com>
2008-06-23 10:38:22 [ FULL ]
Author: zagy
Date: Mon Jun 23 10:38:21 2008
New Revision: 5973

Log:
fixed author retrieving


Modified:
   gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt
   gocept.ooo2html/trunk/src/gocept/ooo2html/convert.py
   gocept.ooo2html/trunk/src/gocept/ooo2html/testdata/testarticle.odt

Modified: gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt
==============================================================================
--- gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt	(original)
+++ gocept.ooo2html/trunk/src/gocept/ooo2html/README.txt	Mon Jun 23 10:38:21
2008
(at)(at) -23,9 +23,8 (at)(at)
 datetime.datetime(2004, 1, 14, 14, 46, 15)
 >>> result.modified
 datetime.datetime(2008, 6, 17, 11, 46, 44)
-
 >>> result.creator
-'Chrstian Zagrodnick'
+'Von Klaus Vogel, Das Internationale Jugendprogramm in Deutschland e.V.'
 >>> result.title
 'Kontakt gesucht: Osee Romeo Tcheupgoum, Kamerun'
 >>> result.description
(at)(at) -36,14 +35,14 (at)(at)
 The body is wrapped in a div:
 
 >>> print result.body
-<div ...
+<div>...
 
 Let's pretty print it:
 
 >>> import lxml.etree
 >>> print lxml.etree.tostring(lxml.etree.fromstring(result.body),
 ...                           pretty_print=True)
-<div xmlns:py="http://codespeak.net/lxml/objectify/pytype"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<div>
   <p class="P1"/>
   <p class="Title"/>
   <h2 class="Heading_20_1">Osee Romeo Tcheupgoum ist 22 Jahre alt und
nimmt am Programm auf der Goldstufe teil. Er kann Deutsch lesen und schreiben.
</h2>

Modified: gocept.ooo2html/trunk/src/gocept/ooo2html/convert.py
==============================================================================
--- gocept.ooo2html/trunk/src/gocept/ooo2html/convert.py	(original)
+++ gocept.ooo2html/trunk/src/gocept/ooo2html/convert.py	Mon Jun 23 10:38:21
2008
(at)(at) -73,8 +73,10 (at)(at)
             '{http://purl.org/dc/elements/1.1/}description')
         result.created = self.get_date(
             '{urn:oasis:names:tc:opendocument:xmlns:meta:1.0}creation-date')
-        result.creator = self.get_text(
-            '{http://purl.org/dc/elements/1.1/}creator')
+        result.creator = self.content.xpath(
+            'string(//text:p[(at)text:style-name="Autor"])',
+            namespaces={
+                'text': 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'})
         result.modified = self.get_date(
             '{http://purl.org/dc/elements/1.1/}date')
         result.image = self.get_text(

Modified: gocept.ooo2html/trunk/src/gocept/ooo2html/testdata/testarticle.odt
==============================================================================
Binary files. No diff available.

SVN: r5976 - in gocept.cvs/trunk/src/gocept/cvs: . tests
Roman Joost <rj(at)gocept.com>
2008-06-24 17:04:32 [ FULL ]
Author: roman
Date: Tue Jun 24 17:04:30 2008
New Revision: 5976

Log:
- don't checkout HEAD with a sticky tag
- always update with the '-A' option, which removes sticky tags



Added:
   gocept.cvs/trunk/src/gocept/cvs/tests/tags.txt
Modified:
   gocept.cvs/trunk/src/gocept/cvs/__init__.py
   gocept.cvs/trunk/src/gocept/cvs/tests/README.txt
   gocept.cvs/trunk/src/gocept/cvs/tests/cvsrep.py
   gocept.cvs/trunk/src/gocept/cvs/tests/test_recipe.py

Modified: gocept.cvs/trunk/src/gocept/cvs/__init__.py
==============================================================================
--- gocept.cvs/trunk/src/gocept/cvs/__init__.py	(original)
+++ gocept.cvs/trunk/src/gocept/cvs/__init__.py	Tue Jun 24 17:04:30 2008
(at)(at) -99,13 +99,14 (at)(at)
         if LOCALCHANGES_REGEXP.match(output):
             raise ValueError(
                 "Local changes are made in %s. Revert them"
-                " first to update/uninstall using buildout." %dest)
+                " first to update/uninstall using buildout."
+                " \n--\n%s" %(dest, output))
 
 
 def single_checkout(path, location, dest, tag, cvsroot):
     dest_dir, dest_name = os.path.split(dest)
     cmd = ['cvs', 'co']
-    if tag:
+    if tag and not tag == 'HEAD':
         cmd.append('-r%s' % tag)
     cmd += ['-d%s' % dest_name, path]
     os.putenv('CVSROOT', cvsroot)
(at)(at) -114,7 +115,7 (at)(at)
 
 
 def single_update(location, dest, tag):
-    cmd = ['cvs', 'up', '-d', '-P']
+    cmd = ['cvs', 'up', '-d', '-P', '-A']
     if tag:
         cmd.append('-r%s' % tag)
     cmd.append(dest)

Modified: gocept.cvs/trunk/src/gocept/cvs/tests/README.txt
==============================================================================
--- gocept.cvs/trunk/src/gocept/cvs/tests/README.txt	(original)
+++ gocept.cvs/trunk/src/gocept/cvs/tests/README.txt	Tue Jun 24 17:04:30 2008
(at)(at) -1,8 +1,6 (at)(at)
 Test for gocept.cvs
 ===================
 
-This test suite works for the Native (with pysvn) implementation.
-
 Setup
 -----
 
(at)(at) -64,6 +62,11 (at)(at)
 Updating cvspart.
 ? gocept.test/README.txt
 cvs update: Updating gocept.test
+>>> print system(buildout)
+Updating cvspart.
+? gocept.test/README.txt
+cvs update: Updating gocept.test
+
 
 If we change the buildout.cfg and run buildout again, it should fail,
 because of local modifications in the parts directory:
(at)(at) -89,6 +92,8 (at)(at)
 ...
 ValueError:
 Local changes are made in gocept.test. Revert them first to update/uninstall
using buildout.
+--
+? gocept.test/README.txt
 
 After the new file is deleted, buildout runs smoothly and checks out the
 second module:
(at)(at) -127,4 +132,5 (at)(at)
 ...
 ValueError:
 Local changes are made in gocept.test. Revert them first to update/uninstall
using buildout.
-
+--
+M gocept.test/file

Modified: gocept.cvs/trunk/src/gocept/cvs/tests/cvsrep.py
==============================================================================
--- gocept.cvs/trunk/src/gocept/cvs/tests/cvsrep.py	(original)
+++ gocept.cvs/trunk/src/gocept/cvs/tests/cvsrep.py	Tue Jun 24 17:04:30 2008
(at)(at) -10,7 +10,7 (at)(at)
         self.cvsrep_path = tempfile.mkdtemp()
         self.projects = {}
 
-    def import_project(self, projectpath, name):
+    def import_project(self, projectpath, name, tag):
         """Imports the project given by path to the repository."""
         if not os.path.exists(projectpath):
             return ValueError("Given projectpath is not accessable.")
(at)(at) -20,16 +20,16 (at)(at)
         os.chdir(projectpath)
         logmessage = "Initial testimport."
         commandlist = ["cvs", "import", "-m '%s'" % logmessage,
-                       name, "HEAD", "test"]
+                       name, tag, "test"]
         subprocess.Popen(
             commandlist, stdout=subprocess.PIPE).communicate()
         self.projects[name] = projectpath
 
-    def create_testproject(self):
+    def create_testproject(self, tag='HEAD'):
         """Creates a test project."""
         testproject_path = os.path.join(os.path.dirname(__file__),
                                         "testdata")
-        self.import_project(testproject_path, "gocept.test")
+        self.import_project(testproject_path, "gocept.test", tag)
 
     def create(self):
         """Creates and initializes the cvs repository."""

Added: gocept.cvs/trunk/src/gocept/cvs/tests/tags.txt
==============================================================================
--- (empty file)
+++ gocept.cvs/trunk/src/gocept/cvs/tests/tags.txt	Tue Jun 24 17:04:30 2008
(at)(at) -0,0 +1,85 (at)(at)
+Test for gocept.cvs
+===================
+
+Setup
+-----
+
+We set up the CVS repository:
+
+>>> import cvsrep
+>>> cvstest = cvsrep.CVSTestRepository()
+>>> cvstest.create()
+>>> cvstest.create_testproject('myTestTag')
+
+Tags
+----
+
+We setup a new testproject with a given TAG:
+
+>>> cd(sample_buildout)
+>>> buildout_contents = '''
+... [buildout]
+... parts = cvspart
+...
+... [cvspart]
+... recipe = gocept.cvs
+... cvsroot = %s
+... destination = products
+... modules = gocept.test;myTestTag;gocept.test''' % cvstest.cvsrep_path
+>>> write('buildout.cfg', buildout_contents)
+
+And run buildout:
+
+>>> print system(buildout)
+Installing cvspart.
+U  gocept.test/.cvsignore
+U  gocept.test/file
+cvs checkout: Updating gocept.test
+
+The checkout should now have a sticky tag:
+
+>>> print system('cvs st parts/products/gocept.test/file')
+====...
+Sticky Tag:  myTestTag (branch: 1.1.1)
+...
+
+
+HEAD checkouts
+--------------
+
+We add another module, which we checkout from the HEAD. This checked out
+product shouldn't have any sticky tags:
+
+>>> buildout_contents = '''
+... [buildout]
+... parts = cvspart
+...
+... [cvspart]
+... recipe = gocept.cvs
+... cvsroot = %s
+... destination = products
+... modules = gocept.test;myTestTag;gocept.test
+...           gocept.test;HEAD;secondgocept.test''' % cvstest.cvsrep_path
+>>> write('buildout.cfg', buildout_contents)
+
+And run buildout:
+
+>>> print system(buildout)
+Uninstalling cvspart.
+Running uninstall recipe.
+Installing cvspart.
+U gocept.test/.cvsignore
+U gocept.test/file
+U secondgocept.test/.cvsignore
+U secondgocept.test/file
+cvs update: Updating gocept.test
+cvs checkout: Updating gocept.test
+cvs checkout: Updating secondgocept.test
+
+The checkout itself was a HEAD checkout, but it should not have a sticky
+"HEAD" tag:
+
+>>> print system('cvs st parts/products/secondgocept.test/file')
+===...
+Sticky Tag: (none)
+...

Modified: gocept.cvs/trunk/src/gocept/cvs/tests/test_recipe.py
==============================================================================
--- gocept.cvs/trunk/src/gocept/cvs/tests/test_recipe.py	(original)
+++ gocept.cvs/trunk/src/gocept/cvs/tests/test_recipe.py	Tue Jun 24 17:04:30
2008
(at)(at) -22,13 +22,22 (at)(at)
 
 
 def test_suite():
-    return unittest.TestSuite([doctest.DocFileSuite(
+    suite = unittest.TestSuite()
+    suite.addTest(doctest.DocFileSuite(
         os.path.join(os.path.dirname(__file__), 'README.txt'),
         optionflags=FLAGS,
         globs=globals(),
         setUp=setUp,
         tearDown=tearDown,
-        module_relative=False)])
+        module_relative=False))
+    suite.addTest(doctest.DocFileSuite(
+        os.path.join(os.path.dirname(__file__), 'tags.txt'),
+        optionflags=FLAGS,
+        globs=globals(),
+        setUp=setUp,
+        tearDown=tearDown,
+        module_relative=False))
+    return suite
 
 
 if __name__ == '__main__':

SVN: r5977 - gocept.cvs/trunk/src/gocept/cvs/tests
Daniel Havlik <dh(at)gocept.com>
2008-06-25 09:22:39 [ FULL ]
Author: nilo
Date: Wed Jun 25 09:22:38 2008
New Revision: 5977

Log:
added an additional test, which verifies that buildout does a reinstall when
changing the tag from a tag to head



Modified:
   gocept.cvs/trunk/src/gocept/cvs/tests/tags.txt

Modified: gocept.cvs/trunk/src/gocept/cvs/tests/tags.txt
==============================================================================
--- gocept.cvs/trunk/src/gocept/cvs/tests/tags.txt	(original)
+++ gocept.cvs/trunk/src/gocept/cvs/tests/tags.txt	Wed Jun 25 09:22:38 2008
(at)(at) -43,6 +43,29 (at)(at)
 Sticky Tag:  myTestTag (branch: 1.1.1)
 ...
 
+Now we change the configuration to use the HEAD,
+
+>>> buildout_contents = buildout_contents.replace('myTestTag',
'HEAD')
+>>> write('buildout.cfg', buildout_contents)
+
+and run the buildout again, which leads to reinstalling the part:
+
+>>> print system(buildout)
+Uninstalling cvspart.
+Running uninstall recipe.
+Installing cvspart.
+U gocept.test/.cvsignore
+U gocept.test/file
+...
+
+We should now have no sticky tag.
+
+>>> print system('cvs st parts/products/gocept.test/file')
+===...
+Sticky Tag: (none)
+...
+
+
 
 HEAD checkouts
 --------------

SVN: r5980 - gocept.vendo/trunk/src/gocept/vendo
Daniel Havlik <dh(at)gocept.com>
2008-06-25 11:56:48 [ FULL ]
Author: nilo
Date: Wed Jun 25 11:56:47 2008
New Revision: 5980

Log:
- display the title of product and variation in the cart
- adding support for multiple shop instances



Modified:
   gocept.vendo/trunk/src/gocept/vendo/cart.py

Modified: gocept.vendo/trunk/src/gocept/vendo/cart.py
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/cart.py	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/cart.py	Wed Jun 25 11:56:47 2008
(at)(at) -200,7 +200,7 (at)(at)
 
         for obj, amount in self._get_object_cart_content():
             price = obj.getDefault_price()
-            title = obj.Title()
+            title = '%s (%s)' % (obj.aq_parent.Title(), obj.Title())
             fullsku = obj.getFull_sku()
             unit = (amount == 1)\
                        and obj.getUnit_singular()\
(at)(at) -331,13 +331,15 (at)(at)
         """ Return a Cart object. """
 
         session = request.SESSION
-        cart = session.get('VendoCart', None)
-
+        shop = getUtility(IShopUtility)
+        prefix = shop.shop_prefix
+        cartname = 'VendoShop-%s' % prefix
+        cart = session.get(cartname, None)
         if cart is not None:
             return cart.__of__(self.context)
 
         cart = Cart()
-        session.set('VendoCart', cart)
+        session.set(cartname, cart)
         return cart.__of__(self.context)
 
 class CartUtility(SimpleItem):

SVN: r5981 - gocept.infrastructure/trunk/util/backup/src/gocept/backup
Christian Kauhaus <kc(at)gocept.com>
2008-06-26 10:09:56 [ FULL ]
Author: ckauhaus
Date: Thu Jun 26 10:09:55 2008
New Revision: 5981

Log:
removed {ex,in}clude_file


Modified:
   gocept.infrastructure/trunk/util/backup/src/gocept/backup/metadata.py
   gocept.infrastructure/trunk/util/backup/src/gocept/backup/test_metadata.py

Modified: gocept.infrastructure/trunk/util/backup/src/gocept/backup/metadata.py
==============================================================================
---
gocept.infrastructure/trunk/util/backup/src/gocept/backup/metadata.py	(original)
+++ gocept.infrastructure/trunk/util/backup/src/gocept/backup/metadata.py	Thu
Jun 26 10:09:55 2008
(at)(at) -26,8 +26,6 (at)(at)
         self.hoststatedir = os.path.join(self.conf.statedir, host)
         self.hostbackupdir = os.path.join(self.conf.backupdir, host)
         self._partitions = None
-        self.exclude_file = None # FIXME: remove
-        self.include_file = None # FIXME: remove
         self.excludes = []
         self.includes = []
         self.successmarker = os.path.join(self.hoststatedir, u'success')

Modified:
gocept.infrastructure/trunk/util/backup/src/gocept/backup/test_metadata.py
==============================================================================
---
gocept.infrastructure/trunk/util/backup/src/gocept/backup/test_metadata.py	(original)
+++
gocept.infrastructure/trunk/util/backup/src/gocept/backup/test_metadata.py	Thu
Jun 26 10:09:55 2008
(at)(at) -147,11 +147,11 (at)(at)
         super(MetadataMinimalFilesTest, self).setUp()
         self.meta.unpack(self.construct_tar({u'partitions': u'/\n'}))
 
-    def test_exclude_file_should_be_none(self):
-        self.assertEqual(None, self.meta.exclude_file)
+    def test_excludes_should_be_empty(self):
+        self.assertEqual([], self.meta.excludes)
 
-    def test_include_file_should_be_none(self):
-        self.assertEqual(None, self.meta.include_file)
+    def test_includes_should_be_empty(self):
+        self.assertEqual([], self.meta.includes)
 
 
 class MetadataIncludeExcludeTest(MetadataTestBase):

SVN: r5982 - in gocept.infrastructure/trunk/util/backup: . src/gocept/backup/share
Christian Kauhaus <kc(at)gocept.com>
2008-06-26 10:11:10 [ FULL ]
Author: ckauhaus
Date: Thu Jun 26 10:11:09 2008
New Revision: 5982

Log:
bumped version to 0.3


Modified:
   gocept.infrastructure/trunk/util/backup/setup.py
   gocept.infrastructure/trunk/util/backup/src/gocept/backup/share/client.sh

Modified: gocept.infrastructure/trunk/util/backup/setup.py
==============================================================================
--- gocept.infrastructure/trunk/util/backup/setup.py	(original)
+++ gocept.infrastructure/trunk/util/backup/setup.py	Thu Jun 26 10:11:09 2008
(at)(at) -2,7 +2,7 (at)(at)
 
 setup(
     name='gocept.backup',
-    version='0.2',
+    version='0.3',
     author='Christian Kauhaus',
     author_email='kc(at)gocept.com',
     url='http://www.gocept.com/',

Modified:
gocept.infrastructure/trunk/util/backup/src/gocept/backup/share/client.sh
==============================================================================
---
gocept.infrastructure/trunk/util/backup/src/gocept/backup/share/client.sh	(original)
+++
gocept.infrastructure/trunk/util/backup/src/gocept/backup/share/client.sh	Thu
Jun 26 10:11:09 2008
(at)(at) -4,7 +4,7 (at)(at)
 # further actions.
 set -e
 
-VERSION="0.2"
+VERSION="0.3"
 ETCDIR="${ROOTDIR}/etc"
 CONFDIR="${ETCDIR}/gocept-backup"

SVN: r5984 - gocept.vendo/trunk/src/gocept/vendo/browser
Daniel Havlik <dh(at)gocept.com>
2008-06-26 11:49:45 [ FULL ]
Author: nilo
Date: Thu Jun 26 11:49:44 2008
New Revision: 5984

Log:
support for not displaying messages in classes subclassing the allproducts
class



Modified:
   gocept.vendo/trunk/src/gocept/vendo/browser/shop.py

Modified: gocept.vendo/trunk/src/gocept/vendo/browser/shop.py
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/browser/shop.py	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/browser/shop.py	Thu Jun 26 11:49:44
2008
(at)(at) -12,6 +12,7 (at)(at)
     """ View for the Shop listing all products. """
 
     template = ViewPageTemplateFile('allproducts.pt')
+    messages = True
 
     def __call__(self):
         variations = []
(at)(at) -30,7 +31,8 (at)(at)
 		else:
 		    unit = 'Items'
 		self.cart.add_item(product_id, amount)
-		getToolByName(self, "plone_utils").addPortalMessage(
+		if self.messages:
+		    getToolByName(self, "plone_utils").addPortalMessage(
 			"%i %s added to cart." % (amount, unit))
         return self.template()

SVN: r5985 - gocept.paypal/trunk/src/gocept/paypal
Daniel Havlik <dh(at)gocept.com>
2008-06-26 13:12:13 [ FULL ]
Author: nilo
Date: Thu Jun 26 13:12:11 2008
New Revision: 5985

Log:
support for setting the LOCALECODE parameter on SetExpressCheckoutDetails



Modified:
   gocept.paypal/trunk/src/gocept/paypal/paypal.py

Modified: gocept.paypal/trunk/src/gocept/paypal/paypal.py
==============================================================================
--- gocept.paypal/trunk/src/gocept/paypal/paypal.py	(original)
+++ gocept.paypal/trunk/src/gocept/paypal/paypal.py	Thu Jun 26 13:12:11 2008
(at)(at) -31,7 +31,7 (at)(at)
         self.signature = urllib.urlencode(self.signature_values) + "&"
 
     # API METHODS
-    def SetExpressCheckout(self, amount, callback_url, callback_cancel_url):
+    def SetExpressCheckout(self, amount, callback_url, callback_cancel_url,
lang=None):
         self._update_values()
         params = {
             'METHOD' : "SetExpressCheckout",
(at)(at) -42,6 +42,8 (at)(at)
             'AMT' : amount,
             'CURRENCYCODE' : self.CURRENCY,
         }
+        if lang is not None:
+            params['LOCALECODE'] = lang
 
         params_string = self.signature + urllib.urlencode(params)
         response = urllib.urlopen(self.API_ENDPOINT, params_string).read()

SVN: r5988 - in gocept.vendo/trunk/src/gocept/vendo: browser content
Daniel Havlik <dh(at)gocept.com>
2008-06-27 11:18:47 [ FULL ]
Author: nilo
Date: Fri Jun 27 11:18:46 2008
New Revision: 5988

Log:
support for Skr currency



Modified:
   gocept.vendo/trunk/src/gocept/vendo/browser/priceadapter.py
   gocept.vendo/trunk/src/gocept/vendo/content/shop.py

Modified: gocept.vendo/trunk/src/gocept/vendo/browser/priceadapter.py
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/browser/priceadapter.py	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/browser/priceadapter.py	Fri Jun 27
11:18:46 2008
(at)(at) -11,12 +11,16 (at)(at)
 
     def __str__(self):
         raw_price = self.context
-    	if type(raw_price) not in [type(''), type(u'')]:
+        if type(raw_price) not in [type(''), type(u'')]:
             raw_price = raw_price()
-	    
-	shop = getUtility(IShopUtility)
+
+    shop = getUtility(IShopUtility)
         cur = shop.getCurrency()
         if cur == 'GBP':
-	    cur = u'£'
-	return u"%s %s" % (cur, raw_price)
+            cur = u'£'
+        elif cur == 'SKR':
+            cur = u'Skr'
+        elif cur == 'EUR':
+            cur = u'€'
+    return u"%s %s" % (cur, raw_price)
 

Modified: gocept.vendo/trunk/src/gocept/vendo/content/shop.py
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/content/shop.py	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/content/shop.py	Fri Jun 27 11:18:46
2008
(at)(at) -19,7 +19,7 (at)(at)
                       required=True,
                       searchable=False,
                       storage=atapi.AnnotationStorage(),
-                      vocabulary=['EUR', 'GBP'],
+                      vocabulary=['EUR', 'GBP', 'SKR'],
                       widget=atapi.SelectionWidget(
                           label=_(u'Curreny'),
                           description=_(u'The currency for this shop')

SVN: r5989 - in gocept.vendo/trunk/src/gocept/vendo: browser content
Daniel Havlik <dh(at)gocept.com>
2008-06-27 11:19:48 [ FULL ]
Author: nilo
Date: Fri Jun 27 11:19:47 2008
New Revision: 5989

Log:
using correct ISO 4217 code for Skr: SEK



Modified:
   gocept.vendo/trunk/src/gocept/vendo/browser/priceadapter.py
   gocept.vendo/trunk/src/gocept/vendo/content/shop.py

Modified: gocept.vendo/trunk/src/gocept/vendo/browser/priceadapter.py
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/browser/priceadapter.py	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/browser/priceadapter.py	Fri Jun 27
11:19:47 2008
(at)(at) -18,7 +18,7 (at)(at)
         cur = shop.getCurrency()
         if cur == 'GBP':
             cur = u'£'
-        elif cur == 'SKR':
+        elif cur == 'SEK':
             cur = u'Skr'
         elif cur == 'EUR':
             cur = u'€'

Modified: gocept.vendo/trunk/src/gocept/vendo/content/shop.py
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/content/shop.py	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/content/shop.py	Fri Jun 27 11:19:47
2008
(at)(at) -19,7 +19,7 (at)(at)
                       required=True,
                       searchable=False,
                       storage=atapi.AnnotationStorage(),
-                      vocabulary=['EUR', 'GBP', 'SKR'],
+                      vocabulary=['EUR', 'GBP', 'SEK'],
                       widget=atapi.SelectionWidget(
                           label=_(u'Curreny'),
                           description=_(u'The currency for this shop')

SVN: r5990 - gocept.vendo/trunk/src/gocept/vendo/browser
Daniel Havlik <dh(at)gocept.com>
2008-06-27 11:23:29 [ FULL ]
Author: nilo
Date: Fri Jun 27 11:23:28 2008
New Revision: 5990

Log:
fixed indentation error



Modified:
   gocept.vendo/trunk/src/gocept/vendo/browser/priceadapter.py

Modified: gocept.vendo/trunk/src/gocept/vendo/browser/priceadapter.py
==============================================================================
--- gocept.vendo/trunk/src/gocept/vendo/browser/priceadapter.py	(original)
+++ gocept.vendo/trunk/src/gocept/vendo/browser/priceadapter.py	Fri Jun 27
11:23:28 2008
(at)(at) -14,7 +14,7 (at)(at)
         if type(raw_price) not in [type(''), type(u'')]:
             raw_price = raw_price()
 
-    shop = getUtility(IShopUtility)
+        shop = getUtility(IShopUtility)
         cur = shop.getCurrency()
         if cur == 'GBP':
             cur = u'£'
(at)(at) -22,5 +22,5 (at)(at)
             cur = u'Skr'
         elif cur == 'EUR':
             cur = u'€'
-    return u"%s %s" % (cur, raw_price)
+        return u"%s %s" % (cur, raw_price)

SVN: r5991 - gocept.objectquery/trunk/src/gocept/objectquery
Christian Theune <ct(at)gocept.com>
2008-06-27 16:36:30 [ FULL ]
Author: ctheune
Date: Fri Jun 27 16:36:29 2008
New Revision: 5991

Log:
- avoid indexing objects that don't have an identity in the database
- more strict (actually too strict) recursion protection to avoid infinite
  loop which we met in a live database



Modified:
   gocept.objectquery/trunk/src/gocept/objectquery/collection.py

Modified: gocept.objectquery/trunk/src/gocept/objectquery/collection.py
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/collection.py	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/collection.py	Fri Jun 27
16:36:29 2008
(at)(at) -35,8 +35,10 (at)(at)
 
     def add(self, obj, parent_oid=None, cycle_prev=None):
         """ Index the object to the ObjectCollection. """
+        if not hasattr(obj, '_p_oid'):
+            return
         if cycle_prev is None:
-            cycle_prev = []
+            cycle_prev = set()
         if obj._p_oid in cycle_prev:
             return
         classname = self._get_classname(obj)
(at)(at) -46,9 +48,9 (at)(at)
             self._attributeindex.insert(attr, obj._p_oid)
         self._structureindex.insert(obj._p_oid, parent_oid)
         descendants = self._objectparser.result("descendants")[:]
-        cycle_prev.append(obj._p_oid)
+        cycle_prev.add(obj._p_oid)
         for desc in descendants:
-            self.add(desc, obj._p_oid, cycle_prev[:])
+            self.add(desc, obj._p_oid, cycle_prev)
 
     def root(self):
         """ Return the root object. """

SVN: r5992 - gocept.objectquery/trunk/src/gocept/objectquery
Sebastian Wehrmann <sw(at)gocept.com>
2008-06-27 16:46:12 [ FULL ]
Author: sweh
Date: Fri Jun 27 16:46:11 2008
New Revision: 5992

Log:
index now adds references if object is already added


Modified:
   gocept.objectquery/trunk/src/gocept/objectquery/collection.py

Modified: gocept.objectquery/trunk/src/gocept/objectquery/collection.py
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/collection.py	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/collection.py	Fri Jun 27
16:46:11 2008
(at)(at) -40,6 +40,8 (at)(at)
         if cycle_prev is None:
             cycle_prev = set()
         if obj._p_oid in cycle_prev:
+            if not self._structureindex.is_successor(obj._p_oid, parent_oid):
+                self._structureindex.insert(obj._p_oid, parent_oid)
             return
         classname = self._get_classname(obj)
         self._classindex.insert(classname, obj._p_oid)

SVN: r5993 - gocept.objectquery/trunk/src/gocept/objectquery
Sebastian Wehrmann <sw(at)gocept.com>
2008-06-27 17:32:06 [ FULL ]
Author: sweh
Date: Fri Jun 27 17:32:04 2008
New Revision: 5993

Log:
- Revert Theunis changes to get tests working (have to look at it later)
- stabilized structure index
- added much more tests for indexsupport



Modified:
   gocept.objectquery/trunk/src/gocept/objectquery/collection.py
   gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.py
   gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.txt

Modified: gocept.objectquery/trunk/src/gocept/objectquery/collection.py
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/collection.py	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/collection.py	Fri Jun 27
17:32:04 2008
(at)(at) -38,7 +38,7 (at)(at)
         if not hasattr(obj, '_p_oid'):
             return
         if cycle_prev is None:
-            cycle_prev = set()
+            cycle_prev = []
         if obj._p_oid in cycle_prev:
             if not self._structureindex.is_successor(obj._p_oid, parent_oid):
                 self._structureindex.insert(obj._p_oid, parent_oid)
(at)(at) -50,9 +50,9 (at)(at)
             self._attributeindex.insert(attr, obj._p_oid)
         self._structureindex.insert(obj._p_oid, parent_oid)
         descendants = self._objectparser.result("descendants")[:]
-        cycle_prev.add(obj._p_oid)
+        cycle_prev.append(obj._p_oid)
         for desc in descendants:
-            self.add(desc, obj._p_oid, cycle_prev)
+            self.add(desc, obj._p_oid, cycle_prev[:])
 
     def root(self):
         """ Return the root object. """

Modified: gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.py
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.py	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.py	Fri Jun 27
17:32:04 2008
(at)(at) -116,11 +116,12 (at)(at)
             return
         for elem in self.index[key][:]:
             if parent is None or ( len(elem) > 1 and elem[-2] == parent ):
-                if len(elem) > 1 and key in self.index['childs'][elem[-2]]:
+                if len(elem) > 1 and key in
self.index['childs'].get(elem[-2],[]):
                     self.index['childs'][elem[-2]].remove(key)
-                self.index[key].remove(elem)
+                if elem in self.index.get(key, []):
+                    self.index[key].remove(elem)
                 self._purge(key, elem)
-        if len(self.index[key]) == 0:
+        if self.index.has_key(key) and len(self.index[key]) == 0:
             del self.index[key]
             del self.index['childs'][key]
 
(at)(at) -177,13 +178,13 (at)(at)
 
     def _purge(self, key, tupel):
         """ Purge the child nodes of key with tupel. """
-        for child in self.index['childs'][key]:
+        for child in self.index['childs'].get(key, []):
             if self.index.has_key(child):
                 for elem in self.index[child][:]:
                     if elem[:-1] == tupel:
                         self.index[child].remove(elem)
                         self._purge(child, elem)
-                if len(self.index[child]) == 0:
+                if len(self.index.get(child, [])) == 0:
                     self.delete(child, key)
 
     def _check_path(self, path1, path2):

Modified: gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.txt
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.txt	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.txt	Fri Jun 27
17:32:04 2008
(at)(at) -28,30 +28,30 (at)(at)
     >>> ci.index
     <BTrees.OOBTree.OOBTree object at 0x...>
 
-ClassIndex holds integer values (like Object Identifiers from ZODB):
+ClassIndex holds any kind of values (e.g. OIDs from peristent objects):
 
     >>> ci.insert("Course", 1)
     >>> ci.insert("Student", 2)
-    >>> ci.insert("Student", 3)
+    >>> ci.insert("Student", 'bar')
 
 Validate the stored data:
 
     >>> ci.has_key('Student')
     True
     >>> ci.get('Student')
-    [2, 3]
+    [2, 'bar']
     >>> ci.has_key('Foo')
     False
     >>> ci.get('Course')
     [1]
-    >>> ci.all()
-    [1, 2, 3]
+    >>> sorted(ci.all())
+    [1, 2, 'bar']
 
 Delete some items from the index:
 
     >>> ci.delete("Student", 2)
     >>> ci.get('Student')
-    [3]
+    ['bar']
     >>> ci.delete("Course", 1)
     >>> ci.get("Course")
     []
(at)(at) -104,14 +104,18 (at)(at)
     >>> si.index['childs'][4]
     []
 
-The method get lists all paths to the given element:
+The method get(key) lists all paths to the given element:
 
+    >>> si.get(1)
+    [(1,)]
     >>> si.get(2)
     [(1, 2), (1, 3, 2)]
     >>> si.get(3)
     [(1, 3)]
     >>> si.get(4)
     [(1, 2, 4), (1, 3, 2, 4), (1, 5, 4)]
+    >>> si.get(5)
+    [(1, 5)]
     >>> si.get(0)
     Traceback (most recent call last):
     ...
(at)(at) -154,35 +158,65 (at)(at)
     >>> si.validate(4, [(1, 3)])
     True
 
-You delete keys as follows:
 
-    >>> si.delete(2, 3)
+Adding a circle to the index:
+
+    >>> si.insert(1, 4)
+
+We now have the circle 1 -> 5 -> 4 -> 1 and 1 -> 2 -> 4 -> 1
and others. Lets
+habe a look at the tuples, which are now accessible by many other nodes:
+
+    >>> si.get(1)
+    [(1,), (1, 2, 4, 1), (1, 3, 2, 4, 1), (1, 5, 4, 1)]
     >>> si.get(2)
-    [(1, 2)]
+    [(1, 2), (1, 3, 2), (1, 2, 4, 1, 2), (1, 3, 2, 4, 1, 2), (1, 5, 4, 1, 2),
(1, 2, 4, 1, 3, 2), (1, 3, 2, 4, 1, 3, 2), (1, 5, 4, 1, 3, 2)]
+    >>> si.get(3)
+    [(1, 3), (1, 2, 4, 1, 3), (1, 3, 2, 4, 1, 3), (1, 5, 4, 1, 3)]
     >>> si.get(4)
-    [(1, 2, 4), (1, 5, 4)]
+    [(1, 2, 4), (1, 3, 2, 4), (1, 5, 4), (1, 2, 4, 1, 2, 4), (1, 3, 2, 4, 1,
2, 4), (1, 5, 4, 1, 2, 4), (1, 2, 4, 1, 3, 2, 4), (1, 3, 2, 4, 1, 3, 2, 4), (1,
5, 4, 1, 3, 2, 4), (1, 2, 4, 1, 5, 4), (1, 3, 2, 4, 1, 5, 4), (1, 5, 4, 1, 5,
4)]
+    >>> si.get(5)
+    [(1, 5), (1, 2, 4, 1, 5), (1, 3, 2, 4, 1, 5), (1, 5, 4, 1, 5)]
+
+Now validate the successor relationship with cases, which retured in the
+uncircled environment False:
+
+    >>> si.is_successor(1, 4)
+    True
+    >>> si.is_child(3, 2)
+    False
+    >>> si.is_successor(3, 2)
+    True
+    >>> si.is_successor(1, 5)
+    True
+
+You delete keys as follows:
+
     >>> si.delete(2)
-    >>> si.get(4)
-    [(1, 5, 4)]
-    >>> si.delete(5)
-    >>> si.get(4)
+    >>> si.get(2)
     Traceback (most recent call last):
     ...
-    KeyError: 4
-    >>> si.get(3)
-    [(1, 3)]
+    KeyError: 2
+    >>> si.get(4)
+    [(1, 5, 4), (1, 5, 4, 1, 5, 4)]
+
+    >>> si.insert(4, 3)
+    >>> si.get(4)
+    [(1, 5, 4), (1, 5, 4, 1, 5, 4), (1, 3, 4), (1, 5, 4, 1, 3, 4)]
+    >>> si.delete(4, 5)
+    >>> si.get(4)
+    [(1, 3, 4)]
 
 Lets look at the childs index:
 
     >>> list(si.index['childs'])
-    [0, 1, 3]
+    [0, 1, 3, 4, 5]
     >>> si.index['childs'][1]
-    [3]
+    [3, 5]
     >>> si.index['childs'][2]
     Traceback (most recent call last):
     ...
     KeyError: 2
-    >>> si.index['childs'][3]
+    >>> si.index['childs'][5]
     []
 
 Special cases
(at)(at) -190,46 +224,10 (at)(at)
 
 Delete the first node:
 
-    >>> si.delete(1, 0)
+    >>> si.delete(1)
     >>> si.get(1)
     Traceback (most recent call last):
     ...
     KeyError: 1
     >>> list(si.index['childs'])
     [0]
-
-Cycles are supported as well:
-
-    >>> si.insert(1)
-    >>> si.insert(2, 1)
-    >>> si.insert(3, 2)
-    >>> si.insert(1, 3)
-
-    >>> si.get(3)
-    [(1, 2, 3), (1, 2, 3, 1, 2, 3)]
-    >>> si.get(1)
-    [(1,), (1, 2, 3, 1)]
-
-    >>> si.is_successor(3, 1)
-    True
-
-Delete the cycle:
-
-    >>> si.delete(1, 3)
-    >>> si.get(3)
-    [(1, 2, 3)]
-    >>> si.get(1)
-    [(1,)]
-
-Adding a ``second way'' (2, 4)  within an existing tree must replicate to all
-childs (node 3):
-
-    >>> si.insert(4, 1)
-    >>> si.get(3)
-    [(1, 2, 3)]
-
-    >>> si.insert(2, 4)
-    >>> si.get(2)
-    [(1, 2), (1, 4, 2)]
-    >>> si.get(3)
-    [(1, 2, 3), (1, 4, 2, 3)]

SVN: r5994 - gocept.objectquery/trunk/src/gocept/objectquery
Sebastian Wehrmann <sw(at)gocept.com>
2008-06-28 13:16:54 [ FULL ]
Author: sweh
Date: Sat Jun 28 13:16:52 2008
New Revision: 5994

Log:
* Class- and Attributeindex now use generators instead of lists to return their
  values
* Added interfaces for Class-, Attribute- and Structureindex
* Cleaned up test cases, better styling




Modified:
   gocept.objectquery/trunk/src/gocept/objectquery/collection.txt
   gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.py
   gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.txt
   gocept.objectquery/trunk/src/gocept/objectquery/interfaces.py

Modified: gocept.objectquery/trunk/src/gocept/objectquery/collection.txt
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/collection.txt	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/collection.txt	Sat Jun 28
13:16:52 2008
(at)(at) -63,12 +63,12 (at)(at)
 
 Verify the indexes:
 
-    >>> result = oc._classindex.get("Telephone")
+    >>> result = list(oc._classindex.get("Telephone"))
     >>> conn.get(result[0])
     <gocept.objectquery.testobjects.Telephone object at 0x...>
     >>> conn.get(result[1])
     <gocept.objectquery.testobjects.Telephone object at 0x...>
-    >>> result = oc._attributeindex.get("name")
+    >>> result = list(oc._attributeindex.get("name"))
     >>> conn.get(result[0])
     <gocept.objectquery.testobjects.Person object at 0x...>
     >>> conn.get(result[1])

Modified: gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.py
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.py	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.py	Sat Jun 28
13:16:52 2008
(at)(at) -46,9 +46,9 (at)(at)
 
     def get(self, key):
         """ Get the IndexItem for a given key. """
-        if key in self.index:
-            return list(self.index[key])
-        return []
+        if self.has_key(key):
+            for item in self.index[key]:
+                yield item
 
     def has_key(self, key):
         """ Return True if key is present, otherwise False. """
(at)(at) -57,19 +57,22 (at)(at)
     def all(self):
         """ Return all objects from the index. """
         allitems = []
-        for indexitem in list(self.index.keys()):
-            for elem in self.get(indexitem):
-                if elem not in allitems:
-                    allitems.append(elem)
-        return allitems
+        for index in self.index.keys():
+            for elem in self.get(index):
+                yield elem
+
 
 class ClassIndex(OOIndex):
     """ Maps strings (classnames) to an IndexItem object. """
-    pass
+
+    zope.interface.implements(gocept.objectquery.interfaces.IAttributeIndex)
+
 
 class AttributeIndex(OOIndex):
     """ Maps strings (attributenames) to an IndexItem object. """
-    pass
+
+    zope.interface.implements(gocept.objectquery.interfaces.IAttributeIndex)
+
 
 class StructureIndex(OOIndex):
     """ Stores information about the relationship between objects. 
(at)(at) -78,20 +81,20 (at)(at)
     objects without having to touch the objects in the ZODB.
     """
 
+    zope.interface.implements(gocept.objectquery.interfaces.IStructureIndex)
+
     def __init__(self, dbroot):
         super(StructureIndex, self).__init__(dbroot)
         self.index['childs'] = OOBTree()    # Childindex, needed for deletion
 
     def insert(self, key, parent=None):
         """ Insert key under parent. """
-        if key == 0:
-            raise ValueError("Key must be > 0.")
         if parent is None:
             parent = 0
         tail = (key, )
         new_path = []
         if self.index.has_key(parent):
-            for elem in self.get(parent)[:]:
+            for elem in self.get(parent):
                 new_path.append(elem + tail)
         else:
             new_path.append(tail)
(at)(at) -146,8 +149,6 (at)(at)
 
     def get(self, key):
         """ Return the path for a given key. """
-        if key == 0:
-            raise ValueError("Key must be > 0.")
         return self.index[key]
 
     def validate(self, key, indexlist):

Modified: gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.txt
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.txt	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/indexsupport.txt	Sat Jun 28
13:16:52 2008
(at)(at) -15,6 +15,7 (at)(at)
     >>> conn = db.open()
     >>> dbroot = conn.root()
 
+
 ClassIndex
 ==========
 
(at)(at) -23,39 +24,54 (at)(at)
     >>> from gocept.objectquery.indexsupport import ClassIndex
     >>> ci = ClassIndex(dbroot)
 
+
 ClassIndex's index is a BTrees.OOBTree object:
 
     >>> ci.index
     <BTrees.OOBTree.OOBTree object at 0x...>
 
+
 ClassIndex holds any kind of values (e.g. OIDs from peristent objects):
 
     >>> ci.insert("Course", 1)
     >>> ci.insert("Student", 2)
     >>> ci.insert("Student", 'bar')
 
-Validate the stored data:
+
+You may check, if a key is inside the index by using has_key():
 
     >>> ci.has_key('Student')
     True
-    >>> ci.get('Student')
-    [2, 'bar']
     >>> ci.has_key('Foo')
     False
-    >>> ci.get('Course')
+
+
+Get returns a generator object for performance reason:
+
+  >>> ci.get('Student')
+  <generator object at 0x...>
+
+
+Validate the stored data:
+
+    >>> list(ci.get('Student'))
+    [2, 'bar']
+    >>> list(ci.get('Course'))
     [1]
     >>> sorted(ci.all())
     [1, 2, 'bar']
 
+
 Delete some items from the index:
 
     >>> ci.delete("Student", 2)
-    >>> ci.get('Student')
+    >>> list(ci.get('Student'))
     ['bar']
     >>> ci.delete("Course", 1)
-    >>> ci.get("Course")
+    >>> list(ci.get("Course"))
     []
 
+
 AttributeIndex
 ==============
 
(at)(at) -65,6 +81,7 (at)(at)
     >>> from gocept.objectquery.indexsupport import AttributeIndex
     >>> ai = AttributeIndex(dbroot)
 
+
 Lets have a look on our dbroot object:
 
     >>> dbroot.has_key('_is_AttributeIndex')
(at)(at) -72,6 +89,7 (at)(at)
     >>> dbroot.has_key('_is_ClassIndex')
     True
 
+
 StructureIndex
 ==============
 
(at)(at) -90,12 +108,6 (at)(at)
     >>> si.insert(5, 1)
     >>> si.insert(4, 5)
 
-The index value must be greater than 0:
-
-    >>> si.insert(0, 4)
-    Traceback (most recent call last):
-    ...
-    ValueError: Key must be > 0.
 
 StructureIndex stores the childs of a key for internal tasks:
 
(at)(at) -119,7 +131,7 (at)(at)
     >>> si.get(0)
     Traceback (most recent call last):
     ...
-    ValueError: Key must be > 0.
+    KeyError: 0
 
 Check the parent-child-relationship:
 

Modified: gocept.objectquery/trunk/src/gocept/objectquery/interfaces.py
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/interfaces.py	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/interfaces.py	Sat Jun 28
13:16:52 2008
(at)(at) -6,46 +6,96 (at)(at)
 
 
 class IQueryParser(Interface):
-    """ Parse an expression and return a queryplan.
-    """
+    """Parse an expression and return a queryplan."""
 
     def parse(expression):
-        """ Parse an expression and return a queryplan.
-        """
+        """Parse an expression and return a queryplan."""
 
 
 class IObjectCollection(Interface):
-    """ Collects Index- and Querysupport for QueryProcessor.
-    """
+    """Collects Index- and Querysupport for QueryProcessor."""
 
     def add(object_oid, parent_oid=None):
-        """ Add object_oid to indices (``under'' parent_oid).
-        """
+        """Add object_oid to indices (``under'' parent_oid)."""
 
     def delete(object_oid, parent_oid=None):
-        """ Delete object_oid from indices (``under'' parent_oid).
-        """
+        """Delete object_oid from indices (``under'' parent_oid)."""
 
     def root():
-        """ Return the root object.
-        """
+        """Return the root object."""
 
     def all():
-        """ Return all objects.
-        """
+        """Return all objects."""
 
     def by_class(classname):
-        """ Return a list of objects with match ``classname''.
-        """
+        """Return a list of objects with match ``classname''."""
 
 
 class IQueryProcessor(Interface):
-    """ Processes a query to the collection and returns the result.
-    """
+    """Processes a query to the collection and returns the result."""
 
     parser = Attribute("The parser which parses the query.")
     collection = Attribute ("The collection handling persistent objects.")
 
     def __call__(expression):
-        """ Parse expression and determine the result.
-        """
+        """Parse expression and determine the result."""
+
+
+class IClassIndex(Interface):
+    """Map classnames to a list of objects of that class."""
+
+    def insert(classname, obj):
+        """Insert obj under classname into the index."""
+
+    def delete(classname, obj):
+        """Delete obj under classname from the index."""
+
+    def get(classname):
+        """Get all objects of the classname class."""
+
+    def has_key(classname):
+        """Return true if classname is in index, otherwise False."""
+
+    def all():
+        """Return all objects of all classes."""
+
+
+class IAttributeIndex(Interface):
+    """Map attribute names to a list of objects with that attribute."""
+
+    def insert(attributename, obj):
+        """Insert obj under attributename into the index."""
+
+    def delete(attributename, obj):
+        """Delete obj under attributename from the index."""
+
+    def get(attributename):
+        """Get all objects with the attribute attributename."""
+
+    def has_key(attributename):
+        """Return true if attributename is in index, otherwise False."""
+
+
+class IStructureIndex(Interface):
+    """Stores information about the relationship betwenn objects."""
+
+    def insert(key, parent=None):
+        """Insert key under parent (under root) into the index."""
+
+    def delete(key, parent=None):
+        """Delete key (under parent) from the index."""
+
+    def is_child(key1, key2):
+        """Check if key1 is direct successor of key2 (key1 child of key2)."""
+
+    def is_successor(key1, key2):
+        """Check is key1 is successor of key2 (key2 is reachable by key1)."""
+
+    def get(key):
+        """Return the paths for a given key."""
+
+    def validate(key, pathlist):
+        """Check if keys path is a part of paths inside pathlist."""
+
+    def root():
+        """Return the root object."""

SVN: r5995 - gocept.objectquery/trunk/src/gocept/objectquery
Sebastian Wehrmann <sw(at)gocept.com>
2008-06-28 15:59:29 [ FULL ]
Author: sweh
Date: Sat Jun 28 15:59:28 2008
New Revision: 5995

Log:
ObjectParser now does not store information about objects
  has now two methods get_attributes and get_descendants
ObjectParser now returns generator objects



Modified:
   gocept.objectquery/trunk/src/gocept/objectquery/collection.py
   gocept.objectquery/trunk/src/gocept/objectquery/collection.txt
   gocept.objectquery/trunk/src/gocept/objectquery/querysupport.py
   gocept.objectquery/trunk/src/gocept/objectquery/querysupport.txt

Modified: gocept.objectquery/trunk/src/gocept/objectquery/collection.py
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/collection.py	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/collection.py	Sat Jun 28
15:59:28 2008
(at)(at) -27,7 +27,6 (at)(at)
         self._attributeindex = AttributeIndex(dbroot)
         self._structureindex = StructureIndex(dbroot)
         # init QuerySupport
-        self._objectparser = ObjectParser()
         self._eejoin = EEJoin(self._structureindex)
         self._eajoin = EAJoin(self.conn) # XXX: ValueIndex instead of conn
         self._kcjoin = KCJoin(self._structureindex)
(at)(at) -43,15 +42,14 (at)(at)
             if not self._structureindex.is_successor(obj._p_oid, parent_oid):
                 self._structureindex.insert(obj._p_oid, parent_oid)
             return
+        op = ObjectParser()
         classname = self._get_classname(obj)
         self._classindex.insert(classname, obj._p_oid)
-        self._objectparser.parse(obj)
-        for attr in self._objectparser.result("attributes"):
+        for attr in op.get_attributes(obj):
             self._attributeindex.insert(attr, obj._p_oid)
         self._structureindex.insert(obj._p_oid, parent_oid)
-        descendants = self._objectparser.result("descendants")[:]
         cycle_prev.append(obj._p_oid)
-        for desc in descendants:
+        for desc in op.get_descendants(obj):
             self.add(desc, obj._p_oid, cycle_prev[:])
 
     def root(self):
(at)(at) -98,13 +96,12 (at)(at)
         """ Main remove method. """
         object = self._get_object(object_oid)
         classname = self._get_classname(object)
+        op = ObjectParser()
         if self._structureindex.has_key(object_oid):
             self._structureindex.delete(object_oid, parent_oid)
         if not self._structureindex.has_key(object_oid):
              self._classindex.delete(classname, object_oid)
-        self._objectparser.parse(object)
-        for attr in self._objectparser.result("attributes"):
+        for attr in op.get_attributes(object):
              self._attributeindex.delete(attr, object_oid)
-        descendants = self._objectparser.result("descendants")[:]
-        for desc in descendants:
+        for desc in op.get_descendants(object):
             self.delete(self._get_oid(desc), object_oid)

Modified: gocept.objectquery/trunk/src/gocept/objectquery/collection.txt
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/collection.txt	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/collection.txt	Sat Jun 28
15:59:28 2008
(at)(at) -155,7 +155,12 (at)(at)
     >>> transaction.commit()
     >>> oc.add(per, add._p_oid)
 
-Adding add unter per will create a cycle, which is possible at all:
+There are now no Telephone objects inside the ObjectCollection:
+
+    >>> len(oc.by_class("Telephone"))
+    0
+
+Adding add under per will create a cycle, which is possible at all:
 
     >>> per.ref.append(add)
     >>> transaction.commit()

Modified: gocept.objectquery/trunk/src/gocept/objectquery/querysupport.py
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/querysupport.py	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/querysupport.py	Sat Jun 28
15:59:28 2008
(at)(at) -7,43 +7,39 (at)(at)
 
 class ObjectParser(object):
 
-    def __init__(self):
-        self.attributes = []     # saves all found attributes to one object
-        self.descendants = []    # saves all found descendands to one object
-
-    def parse(self, object, intern=None):
-        self.__init__()
-        for name in dir(object):
+    def get_attributes(self, obj):
+        for name in dir(obj):
             if name.startswith('_'):
                 continue
             try:
-                value = getattr(object, name)
+                value = getattr(obj, name)
             except Exception:
                 continue
             if callable(value):
                 continue
-            self.attributes.append(name)
-            if self._is_class(value):
-                self.descendants.append(value)
-            self._traverse(value)
-        self._traverse(object)
-
-    def result(self, filter=None):
-        if filter is not None:
-            return getattr(self, filter)
-
-    def _traverse(self, object):
-        if self._is_dict(object):
-            values = object.values()
-        elif self._is_list(object) or self._is_tuple(object):
-            values = object
-        else:
-            return
+            yield name
+
+    def get_descendants(self, obj):
+        for attribute in self.get_attributes(obj):
+            value = getattr(obj, attribute)
+            for elem in self._traverse(value):
+                yield elem
+
+    def _traverse(self, value):
+        values = ()
+        if self._is_dict(value):
+            values = value.values()
+        elif self._is_list(value) or self._is_tuple(value):
+            values = value
+        elif self._is_class(value):
+            yield value
 
         for elem in values:
-            self._traverse(elem)
             if self._is_class(elem):
-                self.descendants.append(elem)
+                yield elem
+            else:
+                for subelem in self._traverse(elem):
+                    yield subelem
 
     def _is_list(self, object):
         if isinstance(object, types.ListType) or\

Modified: gocept.objectquery/trunk/src/gocept/objectquery/querysupport.txt
==============================================================================
--- gocept.objectquery/trunk/src/gocept/objectquery/querysupport.txt	(original)
+++ gocept.objectquery/trunk/src/gocept/objectquery/querysupport.txt	Sat Jun 28
15:59:28 2008
(at)(at) -11,15 +11,20 (at)(at)
 ObjectParser looks inside objects for attributes and following objects. First
 we create such an object:
 
-    >>> class Child(object):
+    >>> class Child1(object):
     ...     pass
+    >>> class Child2(object):
+    ...     pass
+    >>> class Child3(object):
+    ...     pass
+    >>> class Child4(object):
+    ...     misc = Child1()
 
     >>> class ToParse(object):
-    ...     def __init__(self):
-    ...         self.some_var = ["some tupel", (Child(), Child())]
-    ...         self.other_var = {"foo": "bar"}
-    ...         self._private_var = 10
-    ...         self.desc = Child()
+    ...     some_var = ["some tupel", (Child2(), Child3())]
+    ...     other_var = {"foo": "bar"}
+    ...     _private_var = 10
+    ...     desc = Child4()
     ...
     ...     def some_method(self):
     ...         pass
(at)(at) -33,19 +38,25 (at)(at)
     >>> op
     <gocept.objectquery.querysupport.ObjectParser object at 0x...>
 
-To parse an object, use the parse method:
-
-    >>> op.parse(obj)
 
-To get all found attributes, use the result() method:
+To get all found attributes, use the get_attributes() method:
 
-    >>> sorted(op.result("attributes"))
+    >>> attributes = op.get_attributes(obj)
+    >>> attributes
+    <generator object at 0x...>
+    >>> sorted(list(attributes))
     ['desc', 'other_var', 'some_var']
 
-    >>> descendants = op.result("descendants")
+To get all descendants, use the appropriate method. Note, that Child1 is not
+part of the results because its a descendant of Child4:
+
+    >>> descendants = op.get_descendants(obj)
     >>> descendants
-    [<Child object at 0x...>, <Child object at 0x...>]
-    >>> len(descendants)
+    <generator object at 0x...>
+    >>> r = list(descendants)
+    >>> sorted(r)
+    [<Child2 object at 0x...>, <Child3 object at 0x...>,
<Child4 object at 0x...>]
+    >>> len(r)
     3

MailBoxer