[CalendarServer-changes] [8967] CalendarServer/trunk/twext/web2
source_changes at macosforge.org
source_changes at macosforge.org
Mon Apr 2 17:48:11 PDT 2012
Revision: 8967
http://trac.macosforge.org/projects/calendarserver/changeset/8967
Author: wsanchez at apple.com
Date: 2012-04-02 17:48:11 -0700 (Mon, 02 Apr 2012)
Log Message:
-----------
Move web2.dav.stream.MD5StreamWrapper to web2.stream.MD5Stream.
Modified Paths:
--------------
CalendarServer/trunk/twext/web2/dav/method/put_common.py
CalendarServer/trunk/twext/web2/dav/test/test_stream.py
CalendarServer/trunk/twext/web2/stream.py
CalendarServer/trunk/twext/web2/test/test_stream.py
Removed Paths:
-------------
CalendarServer/trunk/twext/web2/dav/stream.py
Modified: CalendarServer/trunk/twext/web2/dav/method/put_common.py
===================================================================
--- CalendarServer/trunk/twext/web2/dav/method/put_common.py 2012-04-03 00:31:50 UTC (rev 8966)
+++ CalendarServer/trunk/twext/web2/dav/method/put_common.py 2012-04-03 00:48:11 UTC (rev 8967)
@@ -33,7 +33,7 @@
from twext.web2.dav.fileop import copy, delete, put
from twext.web2.dav.http import ErrorResponse
from twext.web2.dav.resource import TwistedGETContentMD5
-from twext.web2.dav.stream import MD5StreamWrapper
+from twext.web2.stream import MD5Stream
from twext.web2.http import HTTPError
from twext.web2.http_headers import generateContentType
from twext.web2.iweb import IResponse
@@ -198,7 +198,7 @@
datastream = request.stream
if data is not None:
datastream = MemoryStream(data)
- md5 = MD5StreamWrapper(datastream)
+ md5 = MD5Stream(datastream)
response = maybeDeferred(put, md5, destination.fp)
response = waitForDeferred(response)
Deleted: CalendarServer/trunk/twext/web2/dav/stream.py
===================================================================
--- CalendarServer/trunk/twext/web2/dav/stream.py 2012-04-03 00:31:50 UTC (rev 8966)
+++ CalendarServer/trunk/twext/web2/dav/stream.py 2012-04-03 00:48:11 UTC (rev 8967)
@@ -1,106 +0,0 @@
-# Copyright (c) 2009 Twisted Matrix Laboratories.
-# See LICENSE for details.
-
-##
-# Copyright (c) 2005-2007 Apple Inc. All rights reserved.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-#
-##
-
-"""
-Class that implements a stream that calculates the MD5 hash of the data
-as the data is read.
-"""
-
-__all__ = ["MD5StreamWrapper"]
-
-from twisted.python.hashlib import md5
-from twisted.internet.defer import Deferred
-from twext.web2.stream import SimpleStream
-
-
-class MD5StreamWrapper(SimpleStream):
- """
- An L{IByteStream} wrapper which computes the MD5 hash of the data read from
- the wrapped stream.
-
- @ivar _stream: The stream which is wrapped.
- @ivar _md5: The object used to compute the running md5 hash.
- @ivar _md5value: The hex encoded md5 hash, only set after C{close}.
- """
-
- def __init__(self, wrap):
- if wrap is None:
- raise ValueError("Stream to wrap must be provided")
- self._stream = wrap
- self._md5 = md5()
-
-
- def _update(self, value):
- """
- Update the MD5 hash object.
-
- @param value: L{None} or a L{str} with which to update the MD5 hash
- object.
-
- @return: C{value}
- """
- if value is not None:
- self._md5.update(value)
- return value
-
-
- def read(self):
- """
- Read from the wrapped stream and update the MD5 hash object.
- """
- if self._stream is None:
- raise RuntimeError("Cannot read after stream is closed")
- b = self._stream.read()
-
- if isinstance(b, Deferred):
- b.addCallback(self._update)
- else:
- if b is not None:
- self._md5.update(b)
- return b
-
-
- def close(self):
- """
- Compute the final hex digest of the contents of the wrapped stream.
- """
- SimpleStream.close(self)
- self._md5value = self._md5.hexdigest()
- self._stream = None
- self._md5 = None
-
-
- def getMD5(self):
- """
- Return the hex encoded MD5 digest of the contents of the wrapped
- stream. This may only be called after C{close}.
-
- @rtype: C{str}
- @raise RuntimeError: If C{close} has not yet been called.
- """
- if self._md5 is not None:
- raise RuntimeError("Cannot get MD5 value until stream is closed")
- return self._md5value
Modified: CalendarServer/trunk/twext/web2/dav/test/test_stream.py
===================================================================
--- CalendarServer/trunk/twext/web2/dav/test/test_stream.py 2012-04-03 00:31:50 UTC (rev 8966)
+++ CalendarServer/trunk/twext/web2/dav/test/test_stream.py 2012-04-03 00:48:11 UTC (rev 8967)
@@ -23,11 +23,8 @@
# SOFTWARE.
##
-from twisted.python.hashlib import md5
from twisted.internet.defer import Deferred
from twisted.trial.unittest import TestCase
-from twext.web2.stream import MemoryStream
-from twext.web2.dav.stream import MD5StreamWrapper
class AsynchronousDummyStream(object):
@@ -47,83 +44,3 @@
def _write(self, bytes):
self._readResults.pop(0).callback(bytes)
-
-
-
-class MD5StreamWrapperTests(TestCase):
- """
- Tests for L{MD5StreamWrapper}.
- """
- data = "I am sorry Dave, I can't do that.\n--HAL 9000"
- digest = md5(data).hexdigest()
-
- def test_synchronous(self):
- """
- L{MD5StreamWrapper} computes the MD5 hash of the contents of the stream
- around which it is wrapped. It supports L{IByteStream} providers which
- return C{str} from their C{read} method.
- """
- dataStream = MemoryStream(self.data)
- md5Stream = MD5StreamWrapper(dataStream)
-
- self.assertEquals(str(md5Stream.read()), self.data)
- self.assertIdentical(md5Stream.read(), None)
- md5Stream.close()
-
- self.assertEquals(self.digest, md5Stream.getMD5())
-
-
- def test_asynchronous(self):
- """
- L{MD5StreamWrapper} also supports L{IByteStream} providers which return
- L{Deferreds} from their C{read} method.
- """
- dataStream = AsynchronousDummyStream()
- md5Stream = MD5StreamWrapper(dataStream)
-
- result = md5Stream.read()
- dataStream._write(self.data)
- result.addCallback(self.assertEquals, self.data)
-
- def cbRead(ignored):
- result = md5Stream.read()
- dataStream._write(None)
- result.addCallback(self.assertIdentical, None)
- return result
- result.addCallback(cbRead)
-
- def cbClosed(ignored):
- md5Stream.close()
- self.assertEquals(md5Stream.getMD5(), self.digest)
- result.addCallback(cbClosed)
-
- return result
-
-
- def test_getMD5FailsBeforeClose(self):
- """
- L{MD5StreamWrapper.getMD5} raises L{RuntimeError} if called before
- L{MD5StreamWrapper.close}.
- """
- dataStream = MemoryStream(self.data)
- md5Stream = MD5StreamWrapper(dataStream)
- self.assertRaises(RuntimeError, md5Stream.getMD5)
-
-
- def test_initializationFailsWithoutStream(self):
- """
- L{MD5StreamWrapper.__init__} raises L{ValueError} if passed C{None} as
- the stream to wrap.
- """
- self.assertRaises(ValueError, MD5StreamWrapper, None)
-
-
- def test_readAfterClose(self):
- """
- L{MD5StreamWrapper.read} raises L{RuntimeError} if called after
- L{MD5StreamWrapper.close}.
- """
- dataStream = MemoryStream(self.data)
- md5Stream = MD5StreamWrapper(dataStream)
- md5Stream.close()
- self.assertRaises(RuntimeError, md5Stream.read)
Modified: CalendarServer/trunk/twext/web2/stream.py
===================================================================
--- CalendarServer/trunk/twext/web2/stream.py 2012-04-03 00:31:50 UTC (rev 8966)
+++ CalendarServer/trunk/twext/web2/stream.py 2012-04-03 00:48:11 UTC (rev 8967)
@@ -61,6 +61,7 @@
from twisted.internet import interfaces as ti_interfaces, defer, reactor, protocol, error as ti_error
from twisted.python import components, log
from twisted.python.failure import Failure
+from twisted.python.hashlib import md5
# Python 2.4.2 (only) has a broken mmap that leaks a fd every time you call it.
if sys.version_info[0:3] != (2,4,2):
@@ -1090,6 +1091,75 @@
return pre, post
+#########################
+#### MD5Stream ####
+#########################
+
+class MD5Stream(SimpleStream):
+ """
+ An wrapper which computes the MD5 hash of the data read from the
+ wrapped stream.
+ """
+
+ def __init__(self, wrap):
+ if wrap is None:
+ raise ValueError("Stream to wrap must be provided")
+ self._stream = wrap
+ self._md5 = md5()
+
+
+ def _update(self, value):
+ """
+ Update the MD5 hash object.
+
+ @param value: L{None} or a L{str} with which to update the MD5 hash
+ object.
+
+ @return: C{value}
+ """
+ if value is not None:
+ self._md5.update(value)
+ return value
+
+
+ def read(self):
+ """
+ Read from the wrapped stream and update the MD5 hash object.
+ """
+ if self._stream is None:
+ raise RuntimeError("Cannot read after stream is closed")
+ b = self._stream.read()
+
+ if isinstance(b, Deferred):
+ b.addCallback(self._update)
+ else:
+ self._update(b)
+ return b
+
+
+ def close(self):
+ """
+ Compute the final hex digest of the contents of the wrapped stream.
+ """
+ SimpleStream.close(self)
+ self._md5value = self._md5.hexdigest()
+ self._stream = None
+ self._md5 = None
+
+
+ def getMD5(self):
+ """
+ Return the hex encoded MD5 digest of the contents of the wrapped
+ stream. This may only be called after C{close}.
+
+ @rtype: C{str}
+ @raise RuntimeError: If C{close} has not yet been called.
+ """
+ if self._md5 is not None:
+ raise RuntimeError("Cannot get MD5 value until stream is closed")
+ return self._md5value
+
+
def substream(stream, start, end):
if start > end:
raise ValueError("start position must be less than end position %r"
@@ -1101,6 +1171,5 @@
__all__ = ['IStream', 'IByteStream', 'FileStream', 'MemoryStream', 'CompoundStream',
'readAndDiscard', 'fallbackSplit', 'ProducerStream', 'StreamProducer',
- 'BufferedStream', 'readStream', 'ProcessStreamer', 'readIntoFile',
+ 'BufferedStream', 'MD5Stream', 'readStream', 'ProcessStreamer', 'readIntoFile',
'generatorToStream']
-
Modified: CalendarServer/trunk/twext/web2/test/test_stream.py
===================================================================
--- CalendarServer/trunk/twext/web2/test/test_stream.py 2012-04-03 00:31:50 UTC (rev 8966)
+++ CalendarServer/trunk/twext/web2/test/test_stream.py 2012-04-03 00:48:11 UTC (rev 8967)
@@ -11,6 +11,7 @@
from twisted.python.util import sibpath
sibpath # sibpath is *not* unused - the doctests use it.
+from twisted.python.hashlib import md5
from twisted.internet import reactor, defer, interfaces
from twisted.trial import unittest
from twext.web2 import stream
@@ -615,6 +616,99 @@
"""
+class AsynchronousDummyStream(object):
+ """
+ An L{IByteStream} implementation which always returns a
+ L{defer.Deferred} from C{read} and lets an external driver fire
+ them.
+ """
+ def __init__(self):
+ self._readResults = []
+
+ def read(self):
+ result = defer.Deferred()
+ self._readResults.append(result)
+ return result
+
+ def _write(self, bytes):
+ self._readResults.pop(0).callback(bytes)
+
+class MD5StreamTest(unittest.TestCase):
+ """
+ Tests for L{stream.MD5Stream}.
+ """
+ data = "I am sorry Dave, I can't do that.\n--HAL 9000"
+ digest = md5(data).hexdigest()
+
+ def test_synchronous(self):
+ """
+ L{stream.MD5Stream} computes the MD5 hash of the contents of the stream
+ around which it is wrapped. It supports L{IByteStream} providers which
+ return C{str} from their C{read} method.
+ """
+ dataStream = stream.MemoryStream(self.data)
+ md5Stream = stream.MD5Stream(dataStream)
+
+ self.assertEquals(str(md5Stream.read()), self.data)
+ self.assertIdentical(md5Stream.read(), None)
+ md5Stream.close()
+
+ self.assertEquals(self.digest, md5Stream.getMD5())
+
+ def test_asynchronous(self):
+ """
+ L{stream.MD5Stream} also supports L{IByteStream} providers which return
+ L{Deferreds} from their C{read} method.
+ """
+ dataStream = AsynchronousDummyStream()
+ md5Stream = stream.MD5Stream(dataStream)
+
+ result = md5Stream.read()
+ dataStream._write(self.data)
+ result.addCallback(self.assertEquals, self.data)
+
+ def cbRead(ignored):
+ result = md5Stream.read()
+ dataStream._write(None)
+ result.addCallback(self.assertIdentical, None)
+ return result
+ result.addCallback(cbRead)
+
+ def cbClosed(ignored):
+ md5Stream.close()
+ self.assertEquals(md5Stream.getMD5(), self.digest)
+ result.addCallback(cbClosed)
+
+ return result
+
+ def test_getMD5FailsBeforeClose(self):
+ """
+ L{stream.MD5Stream.getMD5} raises L{RuntimeError} if called before
+ L{stream.MD5Stream.close}.
+ """
+ dataStream = stream.MemoryStream(self.data)
+ md5Stream = stream.MD5Stream(dataStream)
+ self.assertRaises(RuntimeError, md5Stream.getMD5)
+
+ def test_initializationFailsWithoutStream(self):
+ """
+ L{stream.MD5Stream.__init__} raises L{ValueError} if passed C{None} as
+ the stream to wrap.
+ """
+ self.assertRaises(ValueError, stream.MD5Stream, None)
+
+ def test_readAfterClose(self):
+ """
+ L{stream.MD5Stream.read} raises L{RuntimeError} if called after
+ L{stream.MD5Stream.close}.
+ """
+ dataStream = stream.MemoryStream(self.data)
+ md5Stream = stream.MD5Stream(dataStream)
+ md5Stream.close()
+ self.assertRaises(RuntimeError, md5Stream.read)
+
+
+
__doctests__ = ['twext.web2.test.test_stream', 'twext.web2.stream']
# TODO:
# CompoundStreamTest
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120402/6035245d/attachment-0001.html>
More information about the calendarserver-changes
mailing list