[Testbot] Plone 5.0 - Python 2.7 - Build # 2562 - Still failing! - 1 failure(s)

jenkins at plone.org jenkins at plone.org
Sun Jun 8 11:39:40 UTC 2014


-------------------------------------------------------------------------------
Plone 5.0 - Python 2.7 - Build # 2562 - Still Failing!
-------------------------------------------------------------------------------

http://jenkins.plone.org/job/plone-5.0-python-2.7/2562/


-------------------------------------------------------------------------------
CHANGES
-------------------------------------------------------------------------------

Repository: plone.scale
Branch: refs/heads/master
Date: 2014-03-21T18:56:18+01:00
Author: Maurits van Rees (mauritsvanrees) <maurits at vanrees.org>
Commit: https://github.com/plone/plone.scale/commit/b13faeba6c77ab079ff6565097cc5f058a0afb7c

Make sure deleting items or clearing a complete storage works.

Deleting one item would often delete a linked second item, which
made it hard to remove several items at once.

Files changed:
M docs/changes.rst
M plone/scale/storage.py

diff --git a/docs/changes.rst b/docs/changes.rst
index 46dc3e8..05446d5 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -5,7 +5,10 @@ Changelog
 1.3.4 (unreleased)
 ------------------
 
-- Nothing changed yet.
+- Make sure deleting items or clearing a complete storage works.
+  Deleting one item would often delete a linked second item, which
+  made it hard to remove several items at once.
+  [maurits]
 
 
 1.3.3 (2014-01-27)
diff --git a/plone/scale/storage.py b/plone/scale/storage.py
index ea18cbb..87ab4ad 100644
--- a/plone/scale/storage.py
+++ b/plone/scale/storage.py
@@ -85,7 +85,13 @@ def __setitem__(self, id, scale):
     def __delitem__(self, uid):
         storage = self.storage
         info = storage[uid]
-        del storage[info['key']]
+        key = info['key']
+        try:
+            del storage[key]
+        except KeyError:
+            # This key may easily have been removed already,
+            # especially when clearing the storage in one go.
+            pass
         del storage[uid]
 
     def __iter__(self):
@@ -98,3 +104,8 @@ def has_key(self, uid):
         return self.storage.has_key(uid)
 
     __contains__ = has_key
+
+    def clear(self):
+        storage = self.storage
+        for key in storage.keys():
+            del storage[key]


Repository: plone.scale
Branch: refs/heads/master
Date: 2014-03-21T19:10:44+01:00
Author: Maurits van Rees (mauritsvanrees) <maurits at vanrees.org>
Commit: https://github.com/plone/plone.scale/commit/71e2d4746cf036612a22cb81e621e93caccbf61d

Discard all image scales that are more than a day older than the context.

Do this on the fly when finding any scale that is outdated.

Refs https://dev.plone.org/ticket/13791

Files changed:
M docs/changes.rst
M plone/scale/storage.py

diff --git a/docs/changes.rst b/docs/changes.rst
index 05446d5..3cc641a 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -5,6 +5,11 @@ Changelog
 1.3.4 (unreleased)
 ------------------
 
+- When a scale is outdated, discard all image scales that are more
+  than a day older than the context.
+  Refs https://dev.plone.org/ticket/13791
+  [maurits]
+
 - Make sure deleting items or clearing a complete storage works.
   Deleting one item would often delete a linked second item, which
   made it hard to remove several items at once.
diff --git a/plone/scale/storage.py b/plone/scale/storage.py
index 87ab4ad..a463954 100644
--- a/plone/scale/storage.py
+++ b/plone/scale/storage.py
@@ -5,6 +5,10 @@
 from zope.annotation import IAnnotations
 from UserDict import DictMixin
 
+# Keep old scales around for this amount of milliseconds.
+# This is one day:
+KEEP_SCALE_MILLIS = 24 * 60 * 60 * 1000
+
 
 class IImageScaleStorage(Interface):
     """ This is an adapter for image content which can store, retrieve and
@@ -62,7 +66,11 @@ def scale(self, factory=None, **parameters):
         info = storage.get(key)
         modified = self.modified and self.modified()
         if info is not None and modified > info['modified']:
-            del storage[info['uid']]
+            # This is a good moment to clear out the cache and remove
+            # all scales older than one day.
+            for hash, value in storage.items():
+                if value['modified'] < modified - KEEP_SCALE_MILLIS:
+                    del storage[hash]
             info = None     # invalidate when the image was updated
         if info is None and factory:
             result = factory(**parameters)


Repository: plone.scale
Branch: refs/heads/master
Date: 2014-03-21T19:41:13+01:00
Author: Maurits van Rees (mauritsvanrees) <maurits at vanrees.org>
Commit: https://github.com/plone/plone.scale/commit/28273b0e99bb9cb865645d4ccdf100c511c1b4d4

Undo change to __delitem__.

It does not really help.

Files changed:
M plone/scale/storage.py

diff --git a/plone/scale/storage.py b/plone/scale/storage.py
index a463954..e54e3d7 100644
--- a/plone/scale/storage.py
+++ b/plone/scale/storage.py
@@ -94,12 +94,7 @@ def __delitem__(self, uid):
         storage = self.storage
         info = storage[uid]
         key = info['key']
-        try:
-            del storage[key]
-        except KeyError:
-            # This key may easily have been removed already,
-            # especially when clearing the storage in one go.
-            pass
+        del storage[key]
         del storage[uid]
 
     def __iter__(self):


Repository: plone.scale
Branch: refs/heads/master
Date: 2014-03-21T19:41:17+01:00
Author: Maurits van Rees (mauritsvanrees) <maurits at vanrees.org>
Commit: https://github.com/plone/plone.scale/commit/7901b829626a11c9457d5030535c799f458f1cfc

Test the 'clear' method.

Files changed:
M plone/scale/tests/test_storage.py

diff --git a/plone/scale/tests/test_storage.py b/plone/scale/tests/test_storage.py
index ece76cd..71b4a6c 100644
--- a/plone/scale/tests/test_storage.py
+++ b/plone/scale/tests/test_storage.py
@@ -117,6 +117,13 @@ def testCleanUpOldItems(self):
         del storage[scale_new['uid']]
         self.assertEqual(len(storage), 0)
 
+    def testClear(self):
+        storage = self.storage
+        storage.scale(factory=self.factory, foo=23, bar=42)
+        self.assertEqual(len(storage), 2)
+        storage.clear()
+        self.assertEqual(len(storage), 0)
+
 
 def test_suite():
     from unittest import defaultTestLoader


Repository: plone.scale
Branch: refs/heads/master
Date: 2014-03-21T19:41:17+01:00
Author: Maurits van Rees (mauritsvanrees) <maurits at vanrees.org>
Commit: https://github.com/plone/plone.scale/commit/b345cd64a1adf352a1e614aa92dff9982ac2b0a0

Test newer way of cleaning up old items.

Files changed:
M plone/scale/tests/test_storage.py

diff --git a/plone/scale/tests/test_storage.py b/plone/scale/tests/test_storage.py
index 71b4a6c..fd3943d 100644
--- a/plone/scale/tests/test_storage.py
+++ b/plone/scale/tests/test_storage.py
@@ -111,10 +111,20 @@ def testCleanUpOldItems(self):
         next_modified = storage.modified() + 1
         storage.modified = lambda: next_modified
         scale_new = storage.scale(factory=self.factory, foo=23, bar=42)
-        self.assertEqual(len(storage), 2)
+        self.assertEqual(len(storage), 3)
         self.assertEqual(scale_new['uid'] in storage, True)
+        self.assertEqual(scale_old['uid'] in storage, True)
+
+        # When modification time is older than a day, too old scales
+        # get purged.
+        next_modified = storage.modified() + 24 * 60 * 60 * 1000 + 1
+        storage.modified = lambda: next_modified
+        scale_newer = storage.scale(factory=self.factory, foo=23, bar=42)
+
+        self.assertEqual(scale_newer['uid'] in storage, True)
+        self.assertEqual(scale_new['uid'] in storage, False)
         self.assertEqual(scale_old['uid'] in storage, False)
-        del storage[scale_new['uid']]
+        del storage[scale_newer['uid']]
         self.assertEqual(len(storage), 0)
 
     def testClear(self):


Repository: plone.scale
Branch: refs/heads/master
Date: 2014-06-08T12:49:56+02:00
Author: Johannes Raggam (thet) <raggam-nl at adm.at>
Commit: https://github.com/plone/plone.scale/commit/8cd378ad2d27d255cc43d88915b7558b28ca1b12

autopep8

Files changed:
M plone/scale/scale.py
M plone/scale/storage.py
M plone/scale/tests/__init__.py
M plone/scale/tests/test_scale.py
M plone/scale/tests/test_storage.py
M setup.py

diff --git a/plone/scale/scale.py b/plone/scale/scale.py
index 3116701..2ff5d87 100644
--- a/plone/scale/scale.py
+++ b/plone/scale/scale.py
@@ -9,7 +9,7 @@
 
 
 def scaleImage(image, width=None, height=None, direction="down",
-        quality=88, result=None):
+               quality=88, result=None):
     """Scale the given image data to another size and return the result
     as a string or optionally write in to the file-like `result` object.
 
@@ -39,11 +39,21 @@ def scaleImage(image, width=None, height=None, direction="down",
     image = scalePILImage(image, width, height, direction)
 
     if result is None:
-        result=StringIO()
-        image.save(result, format, quality=quality, optimize=True, progressive=True)
-        result=result.getvalue()
+        result = StringIO()
+        image.save(
+            result,
+            format,
+            quality=quality,
+            optimize=True,
+            progressive=True)
+        result = result.getvalue()
     else:
-        image.save(result, format, quality=quality, optimize=True, progressive=True)
+        image.save(
+            result,
+            format,
+            quality=quality,
+            optimize=True,
+            progressive=True)
         result.seek(0)
 
     return result, format, image.size
@@ -57,7 +67,7 @@ def scalePILImage(image, width=None, height=None, direction="down"):
     not lost, which JPEG does not support.
 
     Three different scaling options are supported:
-    
+
     * `up` scaling scales the smallest dimension up to the required size
       and scrops the other dimension if needed.
     * `down` scaling starts by scaling the largest dimension to the required
@@ -72,75 +82,79 @@ def scalePILImage(image, width=None, height=None, direction="down"):
     The return value the scaled image in the form of another instance of
     `PIL.Image`.
     """
-    if direction=="keep":
-        direction="thumbnail"
+    if direction == "keep":
+        direction = "thumbnail"
 
-    if direction=="thumbnail" and not (width and height):
-        raise ValueError("Thumbnailing requires both width and height to be specified")
+    if direction == "thumbnail" and not (width and height):
+        raise ValueError(
+            "Thumbnailing requires both width and height to be specified")
     elif width is None and height is None:
         raise ValueError("Either width or height need to be given")
 
-    if image.mode=="1":
+    if image.mode == "1":
         # Convert black&white to grayscale
-        image=image.convert("L")
-    elif image.mode=="P":
+        image = image.convert("L")
+    elif image.mode == "P":
         # Convert palette based images to 3x8bit+alpha
-        image=image.convert("RGBA")
-    elif image.mode=="CMYK":
+        image = image.convert("RGBA")
+    elif image.mode == "CMYK":
         # Convert CMYK to RGB, allowing for web previews of print images
-        image=image.convert("RGB")
+        image = image.convert("RGB")
 
-    current_size=image.size
+    current_size = image.size
     # Determine scale factor needed to get the right height
     if height is None:
-        scale_height=None
+        scale_height = None
     else:
-        scale_height=(float(height)/float(current_size[1]))
+        scale_height = (float(height) / float(current_size[1]))
     if width is None:
-        scale_width=None
+        scale_width = None
     else:
-        scale_width=(float(width)/float(current_size[0]))
+        scale_width = (float(width) / float(current_size[0]))
 
-    if scale_height==scale_width or direction=="thumbnail":
+    if scale_height == scale_width or direction == "thumbnail":
         # The original already has the right aspect ratio, so we only need
         # to scale.
         image.thumbnail((width, height), PIL.Image.ANTIALIAS)
     else:
-        if direction=="down":
-            if scale_height is None or (scale_width is not None and scale_width>scale_height):
+        if direction == "down":
+            if scale_height is None or (
+                    scale_width is not None and scale_width > scale_height):
                 # Width is the smallest dimension (relatively), so scale up
                 # to the desired width
-                new_width=width
-                new_height=int(round(current_size[1]*scale_width))
+                new_width = width
+                new_height = int(round(current_size[1] * scale_width))
             else:
-                new_height=height
-                new_width=int(round(current_size[0]*scale_height))
+                new_height = height
+                new_width = int(round(current_size[0] * scale_height))
         else:
-            if scale_height is None or (scale_width is not None and scale_width<scale_height):
+            if scale_height is None or (
+                    scale_width is not None and scale_width < scale_height):
                 # Width is the largest dimension (relatively), so scale up
                 # to the desired width
-                new_width=width
-                new_height=int(round(current_size[1]*scale_width))
+                new_width = width
+                new_height = int(round(current_size[1] * scale_width))
             else:
-                new_height=height
-                new_width=int(round(current_size[0]*scale_height))
+                new_height = height
+                new_width = int(round(current_size[0] * scale_height))
 
         image.draft(image.mode, (new_width, new_height))
-        image=image.resize((new_width, new_height), PIL.Image.ANTIALIAS)
+        image = image.resize((new_width, new_height), PIL.Image.ANTIALIAS)
 
-        if (width is not None and new_width>width) or (height is not None and new_height>height):
+        if (width is not None and new_width > width) or (
+                height is not None and new_height > height):
             if width is None:
-                left=0
-                right=new_width
+                left = 0
+                right = new_width
             else:
-                left=int((new_width-width)/2.0)
-                right=left+width
+                left = int((new_width - width) / 2.0)
+                right = left + width
             if height is None:
-                top=0
-                bottom=new_height
+                top = 0
+                bottom = new_height
             else:
-                top=int((new_height-height)/2.0)
-                bottom=top+height
-            image=image.crop((left, top, right, bottom))
+                top = int((new_height - height) / 2.0)
+                bottom = top + height
+            image = image.crop((left, top, right, bottom))
 
     return image
diff --git a/plone/scale/storage.py b/plone/scale/storage.py
index e54e3d7..dc88de6 100644
--- a/plone/scale/storage.py
+++ b/plone/scale/storage.py
@@ -50,12 +50,12 @@ def __repr__(self):
         name = self.__class__.__name__
         return '<%s context=%r>' % (name, self.context)
 
-    __str__=__repr__
+    __str__ = __repr__
 
     @property
     def storage(self):
         return IAnnotations(self.context).setdefault('plone.scale',
-            PersistentDict())
+                                                     PersistentDict())
 
     def hash(self, **parameters):
         return tuple(sorted(parameters.items()))
@@ -79,8 +79,8 @@ def scale(self, factory=None, **parameters):
                 width, height = dimensions
                 uid = str(uuid4())
                 info = dict(uid=uid, data=data, width=width, height=height,
-                    mimetype='image/%s' % format.lower(), key=key,
-                    modified=modified)
+                            mimetype='image/%s' % format.lower(), key=key,
+                            modified=modified)
                 storage[key] = storage[uid] = info
         return info
 
@@ -104,7 +104,7 @@ def keys(self):
         return self.storage.keys()
 
     def has_key(self, uid):
-        return self.storage.has_key(uid)
+        return uid in self.storage
 
     __contains__ = has_key
 
diff --git a/plone/scale/tests/__init__.py b/plone/scale/tests/__init__.py
index db5f359..d2fbd0e 100644
--- a/plone/scale/tests/__init__.py
+++ b/plone/scale/tests/__init__.py
@@ -1,4 +1,3 @@
 import os.path
 
 TEST_DATA_LOCATION = os.path.join(os.path.dirname(__file__), "data")
-
diff --git a/plone/scale/tests/test_scale.py b/plone/scale/tests/test_scale.py
index ab8e8ba..9e3f585 100644
--- a/plone/scale/tests/test_scale.py
+++ b/plone/scale/tests/test_scale.py
@@ -1,69 +1,69 @@
 from cStringIO import StringIO
-import os.path
-from unittest import TestCase
 from plone.scale.scale import scaleImage
 from plone.scale.tests import TEST_DATA_LOCATION
+from unittest import TestCase
 import PIL.Image
+import os.path
 
 PNG = open(os.path.join(TEST_DATA_LOCATION, "logo.png")).read()
 GIF = open(os.path.join(TEST_DATA_LOCATION, "logo.gif")).read()
 CMYK = open(os.path.join(TEST_DATA_LOCATION, "cmyk.jpg")).read()
 
+
 class ScalingTests(TestCase):
+
     def testNewSizeReturned(self):
-        (imagedata, format, size)=scaleImage(PNG, 42, 51, "down")
-        input=StringIO(imagedata)
-        image=PIL.Image.open(input)
+        (imagedata, format, size) = scaleImage(PNG, 42, 51, "down")
+        input = StringIO(imagedata)
+        image = PIL.Image.open(input)
         self.assertEqual(image.size, size)
 
     def testScaledImageIsJpeg(self):
-        self.assertEqual(scaleImage(GIF, 84, 103, "down")[1] , "JPEG")
+        self.assertEqual(scaleImage(GIF, 84, 103, "down")[1], "JPEG")
 
     def testScaledCMYKIsRGB(self):
-        (imagedata, format, size)=scaleImage(CMYK, 42, 51, "down")
-        input=StringIO(imagedata)
-        image=PIL.Image.open(input)
+        (imagedata, format, size) = scaleImage(CMYK, 42, 51, "down")
+        input = StringIO(imagedata)
+        image = PIL.Image.open(input)
         self.assertEqual(image.mode, "RGB")
 
     def XtestScaledPngImageIsPng(self):
         # This test failes because the sample input file has a format of
         # None according to PIL..
-        self.assertEqual(scaleImage(PNG, 84, 103, "down")[1] , "PNG")
-
+        self.assertEqual(scaleImage(PNG, 84, 103, "down")[1], "PNG")
 
     def testSameSizeDownScale(self):
-        self.assertEqual(scaleImage(PNG,  84, 103, "down")[2], (84, 103))
+        self.assertEqual(scaleImage(PNG, 84, 103, "down")[2], (84, 103))
 
     def testHalfSizeDownScale(self):
-        self.assertEqual(scaleImage(PNG,  42, 51, "down")[2], (42, 51))
+        self.assertEqual(scaleImage(PNG, 42, 51, "down")[2], (42, 51))
 
     def testScaleWithCropDownScale(self):
-        self.assertEqual(scaleImage(PNG,  20, 51, "down")[2], (20, 51))
+        self.assertEqual(scaleImage(PNG, 20, 51, "down")[2], (20, 51))
 
     def testNoStretchingDownScale(self):
-        self.assertEqual(scaleImage(PNG,  200, 103, "down")[2], (200, 103))
+        self.assertEqual(scaleImage(PNG, 200, 103, "down")[2], (200, 103))
 
     def testRestrictWidthOnlyDownScale(self):
-        self.assertEqual(scaleImage(PNG,  42, None, "down")[2], (42, 52))
+        self.assertEqual(scaleImage(PNG, 42, None, "down")[2], (42, 52))
 
     def testRestrictHeightOnlyDownScale(self):
-        self.assertEqual(scaleImage(PNG,  None, 51, "down")[2], (42, 51))
-
+        self.assertEqual(scaleImage(PNG, None, 51, "down")[2], (42, 51))
 
     def testSameSizeUpScale(self):
-        self.assertEqual(scaleImage(PNG,  84, 103, "up")[2], (84, 103))
+        self.assertEqual(scaleImage(PNG, 84, 103, "up")[2], (84, 103))
 
     def testHalfSizeUpScale(self):
-        self.assertEqual(scaleImage(PNG,  42, 51, "up")[2], (42, 51))
+        self.assertEqual(scaleImage(PNG, 42, 51, "up")[2], (42, 51))
 
     def testNoStretchingUpScale(self):
-        self.assertEqual(scaleImage(PNG,  200, 103, "up")[2], (84, 103))
+        self.assertEqual(scaleImage(PNG, 200, 103, "up")[2], (84, 103))
 
     def testRestrictWidthOnlyUpScale(self):
-        self.assertEqual(scaleImage(PNG,  42, None, "up")[2], (42, 52))
+        self.assertEqual(scaleImage(PNG, 42, None, "up")[2], (42, 52))
 
     def testRestrictHeightOnlyUpScale(self):
-        self.assertEqual(scaleImage(PNG,  None, 51, "up")[2], (42, 51))
+        self.assertEqual(scaleImage(PNG, None, 51, "up")[2], (42, 51))
 
     def testNoRestrictions(self):
         self.assertRaises(ValueError, scaleImage, PNG, None, None)
@@ -71,7 +71,6 @@ def testNoRestrictions(self):
     def testKeepAspectRatio(self):
         self.assertEqual(scaleImage(PNG, 80, 80, "keep")[2], (65, 80))
 
-
     def testQuality(self):
         img1 = scaleImage(CMYK, 84, 103)[0]
         img2 = scaleImage(CMYK, 84, 103, quality=50)[0]
diff --git a/plone/scale/tests/test_storage.py b/plone/scale/tests/test_storage.py
index fd3943d..adc53cc 100644
--- a/plone/scale/tests/test_storage.py
+++ b/plone/scale/tests/test_storage.py
@@ -1,5 +1,5 @@
-from unittest import TestCase
 from operator import itemgetter, setitem, delitem
+from unittest import TestCase
 
 
 class AnnotationStorageTests(TestCase):
@@ -87,12 +87,12 @@ def testKeys(self):
 
     def testNegativeHasKey(self):
         storage = self.storage
-        self.assertEqual(storage.has_key('one'), False)
+        self.assertEqual('one' in storage, False)
 
     def testPositiveHasKey(self):
         storage = self.storage
         storage.storage.update(one=None)
-        self.assertEqual(storage.has_key('one'), True)
+        self.assertEqual('one' in storage, True)
 
     def testDeleteNonExistingItem(self):
         storage = self.storage
diff --git a/setup.py b/setup.py
index b7126da..bfcf0c5 100644
--- a/setup.py
+++ b/setup.py
@@ -28,37 +28,38 @@
     # uuid is only required before Python 2.5
     STORAGE_REQUIREMENTS.append("uuid")
 
-setup(name="plone.scale",
-      version=version,
-      description="Image scaling",
-      long_description=readme + "\n" + changes,
-      classifiers=[
-          "Development Status :: 5 - Production/Stable",
-          "Environment :: Web Environment",
-          "Framework :: Plone",
-          "Framework :: Zope2",
-          "License :: OSI Approved :: BSD License",
-          "Operating System :: OS Independent",
-          "Programming Language :: Python",
-        ],
-      keywords="image scaling",
-      author='Plone Foundation',
-      author_email='plone-developers at lists.sourceforge.net',
-      url='http://pypi.python.org/pypi/plone.scale',
-      license="BSD",
-      packages=find_packages(exclude=["ez_setup"]),
-      namespace_packages=["plone"],
-      include_package_data=True,
-      zip_safe=True,
-      test_suite="plone.scale",
-      install_requires=[
-          # We can't actually depend on PIL because not everyone can install it
-          # as an egg.
-          #"PIL",
-          "setuptools",
-          ],
-      extras_require = dict(
-          storage = STORAGE_REQUIREMENTS,
-          sphinx = STORAGE_REQUIREMENTS + SPHINX_REQUIREMENTS,
-          ),
-      )
+setup(
+    name="plone.scale",
+    version=version,
+    description="Image scaling",
+    long_description=readme + "\n" + changes,
+    classifiers=[
+        "Development Status :: 5 - Production/Stable",
+        "Environment :: Web Environment",
+        "Framework :: Plone",
+        "Framework :: Zope2",
+        "License :: OSI Approved :: BSD License",
+        "Operating System :: OS Independent",
+        "Programming Language :: Python",
+    ],
+    keywords="image scaling",
+    author='Plone Foundation',
+    author_email='plone-developers at lists.sourceforge.net',
+    url='http://pypi.python.org/pypi/plone.scale',
+    license="BSD",
+    packages=find_packages(exclude=["ez_setup"]),
+    namespace_packages=["plone"],
+    include_package_data=True,
+    zip_safe=True,
+    test_suite="plone.scale",
+    install_requires=[
+        # We can't actually depend on PIL because not everyone can install it
+        # as an egg.
+        # "PIL",
+        "setuptools",
+    ],
+    extras_require=dict(
+        storage=STORAGE_REQUIREMENTS,
+        sphinx=STORAGE_REQUIREMENTS + SPHINX_REQUIREMENTS,
+    ),
+)




-------------------------------------------------------------------------------
-------------- next part --------------
A non-text attachment was scrubbed...
Name: CHANGES.log
Type: application/octet-stream
Size: 24024 bytes
Desc: not available
URL: <http://lists.plone.org/pipermail/plone-testbot/attachments/20140608/04fafee9/attachment-0002.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: build.log
Type: application/octet-stream
Size: 145642 bytes
Desc: not available
URL: <http://lists.plone.org/pipermail/plone-testbot/attachments/20140608/04fafee9/attachment-0003.obj>


More information about the Testbot mailing list