[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