[Zope3-checkins] SVN: Zope3/branches/srichter-twisted-integration/
First attempt at a twisted-based scheduler. It seems to work
well. :-)
Stephan Richter
srichter at cosmos.phy.tufts.edu
Thu Apr 28 13:53:55 EDT 2005
Log message for revision 30213:
First attempt at a twisted-based scheduler. It seems to work well. :-)
Changed:
A Zope3/branches/srichter-twisted-integration/package-includes/scheduler-configure.zcml
A Zope3/branches/srichter-twisted-integration/src/scheduler/
A Zope3/branches/srichter-twisted-integration/src/scheduler/README.txt
A Zope3/branches/srichter-twisted-integration/src/scheduler/__init__.py
A Zope3/branches/srichter-twisted-integration/src/scheduler/configure.zcml
A Zope3/branches/srichter-twisted-integration/src/scheduler/cron.py
A Zope3/branches/srichter-twisted-integration/src/scheduler/interfaces.py
A Zope3/branches/srichter-twisted-integration/src/scheduler/loop.py
A Zope3/branches/srichter-twisted-integration/src/scheduler/manager.py
A Zope3/branches/srichter-twisted-integration/src/scheduler/scheduler-configure.zcml
A Zope3/branches/srichter-twisted-integration/src/scheduler/task.py
A Zope3/branches/srichter-twisted-integration/src/scheduler/tests.py
-=-
Added: Zope3/branches/srichter-twisted-integration/package-includes/scheduler-configure.zcml
===================================================================
--- Zope3/branches/srichter-twisted-integration/package-includes/scheduler-configure.zcml 2005-04-28 17:53:11 UTC (rev 30212)
+++ Zope3/branches/srichter-twisted-integration/package-includes/scheduler-configure.zcml 2005-04-28 17:53:55 UTC (rev 30213)
@@ -0,0 +1 @@
+<include package="scheduler" />
\ No newline at end of file
Property changes on: Zope3/branches/srichter-twisted-integration/package-includes/scheduler-configure.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/branches/srichter-twisted-integration/src/scheduler/README.txt
===================================================================
--- Zope3/branches/srichter-twisted-integration/src/scheduler/README.txt 2005-04-28 17:53:11 UTC (rev 30212)
+++ Zope3/branches/srichter-twisted-integration/src/scheduler/README.txt 2005-04-28 17:53:55 UTC (rev 30213)
@@ -0,0 +1,169 @@
+==================
+The Task Scheduler
+==================
+
+
+ >>> def callable(*args, **kw):
+ ... print 'I have been called.'
+
+
+The API
+-------
+
+From a high-level point of view, the developer starts out by developing their
+own or us an existing task component:
+
+ >>> from scheduler import task
+ >>> from twisted.internet import reactor
+
+ >>> class MyTask(task.Task):
+ ...
+ ... def computeDelayToNextCall(self):
+ ... return 88
+
+ >>> mytask = MyTask(callable, ('arg1', 'arg2'), {'kw1': 1, 'kw2': 2})
+
+As you can see, you only need to implement the ``computeDelayToNextCall()``
+method that used by the rescheduling mechism to determine the next time of
+execution. It is up to the developer to compute the delay, which is specified
+in seconds. Based on the system you are running on, a float for the delay
+allows you to specify sub-second intervals.
+
+So, now we have a task, but it has not been started:
+
+ >>> mytask.running
+ False
+ >>> mytask.count
+
+Now that you have a task component, we register it as a utility providing
+``ITask``.
+
+ >>> from zope.app.testing import ztapi
+ >>> from scheduler import interfaces
+ >>> ztapi.provideUtility(interfaces.ITask, mytask, 'MyTask')
+
+When Zope is started, an event listener will start all tasks.
+
+ >>> from scheduler import manager
+ >>> manager.startAllTasks(None)
+
+ >>> mytask.running
+ True
+ >>> mytask.count
+ 0
+
+At this time the first task execution should also be scheduled:
+
+ >>> from twisted.internet import reactor
+ >>> delayedCall = reactor.getDelayedCalls()[-1]
+
+ >>> delayedCall.func
+ MyTask(callable, *('arg1', 'arg2'), **{'kw1': 1, 'kw2': 2})
+
+After the time passes (we just do not have time to wait 88 seconds ;-), the
+task will be executed:
+
+ >>> mytask()
+ I have been called.
+
+If you want to stop a task, then you simply call ``stop()``:
+
+ >>> mytask.stop()
+ >>> mytask.running
+ False
+
+For more documentation and information on a task's features, see Twisted's
+``LoopingCall`` class, which is used as a base class for ``Task``.
+
+
+Loop Task
+---------
+
+A looping task is a task that gets executed in evenly-spaced time
+intervals. The interval can be specified in the final argument of the
+constructor:
+
+ >>> from scheduler import loop
+ >>> looptask = loop.LoopTask(callable, interval=30)
+
+The interval is specified in seconds, so in our case it is 30 seconds. The
+time interval is publically available
+
+ >>> looptask.timeInterval
+ 30
+
+And when the delay is calculated, it should simply return the time interval:
+
+ >>> looptask.computeDelayToNextCall()
+ 30
+
+
+Cron Task
+---------
+
+The cron-based task allows descriptions of scheduled times via a crontab-like
+format, where one can specify lists of minutes, hours, days, weekdays and
+months. To properly test the calculation of the delay, we have to overridde
+the time-module's ``time()`` function to return a constant time (in seconds).
+
+ >>> import time
+ >>> orig_time = time.time
+ >>> time.time = lambda : time.mktime((2005, 1, 1, 0, 0, 0, 5, 1, 0))
+
+We can now create a task.
+
+ >>> from scheduler import cron
+ >>> crontask = cron.CronTask(callable, (), {})
+
+This corresponds to the crontab entry::
+
+ * * * * * *
+
+so that
+
+ >>> time.localtime(crontask.computeDelayToNextCall())
+ (2005, 1, 1, 0, 1, 0, 5, 1, 0)
+
+Here are a couple more examples:
+
+ # run five minutes after midnight, every day
+ # 5 0 * * *
+ >>> crontask = cron.CronTask(callable, (), {}, minute=(5,), hour=(0,))
+ >>> time.localtime(crontask.computeDelayToNextCall())
+ (2005, 1, 1, 0, 5, 0, 5, 1, 0)
+
+ # run at 2:15pm on the first of every month
+ # 15 14 1 * *
+ >>> crontask = cron.CronTask(
+ ... callable, (), {},
+ ... minute=(5,), hour=(0,), dayOfMonth=(1,))
+ >>> time.localtime(crontask.computeDelayToNextCall())
+ (2005, 1, 1, 0, 5, 0, 5, 1, 0)
+
+ # run at 10 pm on weekdays
+ 0 22 * * 1-5
+ >>> crontask = cron.CronTask(
+ ... callable, (), {},
+ ... minute=(0,), hour=(22,), dayOfWeek=(1, 2, 3, 4, 5))
+ >>> time.localtime(crontask.computeDelayToNextCall())
+ (2005, 1, 1, 22, 0, 0, 5, 1, 0)
+
+ # run 23 minutes after midn, 2am, 4am ..., everyday
+ # 23 0-23/2 * * *
+ >>> crontask = cron.CronTask(
+ ... callable, (), {}, minute=(23,), hour=xrange(0, 24, 2))
+ >>> time.localtime(crontask.computeDelayToNextCall())
+ (2005, 1, 1, 0, 23, 0, 5, 1, 0)
+
+ # run at 5 after 4 every sunday
+ 5 4 * * sun
+ >>> crontask = cron.CronTask(
+ ... callable, (), {},
+ ... minute=(5,), hour=(4,), dayOfWeek=(0,))
+ >>> time.localtime(crontask.computeDelayToNextCall())
+ (2005, 1, 3, 4, 5, 0, 0, 3, 0)
+
+
+Finally, we need to cleanup after ourselves.
+
+ >>> time.time = orig_time
\ No newline at end of file
Property changes on: Zope3/branches/srichter-twisted-integration/src/scheduler/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/branches/srichter-twisted-integration/src/scheduler/__init__.py
===================================================================
--- Zope3/branches/srichter-twisted-integration/src/scheduler/__init__.py 2005-04-28 17:53:11 UTC (rev 30212)
+++ Zope3/branches/srichter-twisted-integration/src/scheduler/__init__.py 2005-04-28 17:53:55 UTC (rev 30213)
@@ -0,0 +1 @@
+# Make a package
Property changes on: Zope3/branches/srichter-twisted-integration/src/scheduler/__init__.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/branches/srichter-twisted-integration/src/scheduler/configure.zcml
===================================================================
--- Zope3/branches/srichter-twisted-integration/src/scheduler/configure.zcml 2005-04-28 17:53:11 UTC (rev 30212)
+++ Zope3/branches/srichter-twisted-integration/src/scheduler/configure.zcml 2005-04-28 17:53:55 UTC (rev 30213)
@@ -0,0 +1,25 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:apidoc="http://namespaces.zope.org/apidoc"
+ xmlns:zcml="http://namespaces.zope.org/zcml"
+ i18n_domain="zope"
+ >
+
+ <!-- Register event listener for -->
+ <subscriber
+ handler=".manager.startAllTasks"
+ for="zope.app.appsetup.interfaces.IProcessStartingEvent"
+ />
+
+ <!-- Register scheduler package with API Doc Tool -->
+ <apidoc:rootModule module="scheduler" zcml:condition="have apidoc" />
+
+ <!-- Register the documentation as a chapter in the API doc book -->
+ <apidoc:bookchapter
+ id="scheduler"
+ title="The Task Scheduler"
+ doc_path="README.txt"
+ zcml:condition="have apidoc"
+ />
+
+</configure>
Property changes on: Zope3/branches/srichter-twisted-integration/src/scheduler/configure.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/branches/srichter-twisted-integration/src/scheduler/cron.py
===================================================================
--- Zope3/branches/srichter-twisted-integration/src/scheduler/cron.py 2005-04-28 17:53:11 UTC (rev 30212)
+++ Zope3/branches/srichter-twisted-integration/src/scheduler/cron.py 2005-04-28 17:53:55 UTC (rev 30213)
@@ -0,0 +1,61 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Cron-like Scheduler Task
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+import time
+import zope.interface
+from twisted.internet import reactor
+from scheduler import interfaces, task
+
+class CronTask(task.Task):
+
+ zope.interface.implements(interfaces.ICronTask)
+
+ # Set a four year timeout to find the next scheduled time
+ timeout = 4*60*60*24*365
+
+ def __init__(self, callable, arguments=(), keywords={},
+ minute=(), hour=(), dayOfMonth=(), month=(), dayOfWeek=()):
+ super(CronTask, self).__init__(callable, arguments, keywords)
+
+ # See scheduler.interfaces.ICronTask
+ self.minute = minute
+ self.hour = hour
+ self.dayOfMonth = dayOfMonth
+ self.month = month
+ self.dayOfWeek = dayOfWeek
+
+
+ def computeDelayToNextCall(self):
+ """See scheduler.interfaces.ITask"""
+ now = next = time.time()
+ while next <= now+self.timeout:
+ next += 60
+ fields = time.localtime(next)
+
+ if ((self.month and fields[1] not in self.month) or
+ (self.dayOfMonth and fields[2] not in self.dayOfMonth) or
+ (self.dayOfWeek and fields[6] % 7 not in self.dayOfWeek) or
+ (self.hour and fields[3] not in self.hour) or
+ (self.minute and fields[4] not in self.minute)):
+
+ continue
+
+ return next
+
+ raise SomeError
Property changes on: Zope3/branches/srichter-twisted-integration/src/scheduler/cron.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/branches/srichter-twisted-integration/src/scheduler/interfaces.py
===================================================================
--- Zope3/branches/srichter-twisted-integration/src/scheduler/interfaces.py 2005-04-28 17:53:11 UTC (rev 30212)
+++ Zope3/branches/srichter-twisted-integration/src/scheduler/interfaces.py 2005-04-28 17:53:55 UTC (rev 30213)
@@ -0,0 +1,116 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Task Scheduler Interfaces
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+import zope.schema
+from zope.interface import Interface, Attribute
+
+
+class ITask(Interface):
+ """A task that is executed at a particular time."""
+
+ # These names were chosen to match Twisted's LoopingCall class.
+ f = Attribute("The callable that is executes at the scheduled time.")
+
+ a = zope.schema.Tuple(
+ title=u"Arguments",
+ description=u"Arguments (tuple) for the callable.")
+
+ kw = zope.schema.Dict(
+ title=u"Keywords",
+ description=u"Keywords (dict) for the callable.")
+
+ starttime = zope.schema.Float(
+ title=u"Start Time",
+ description=u"Time in seconds at which the task will be first "
+ u"scheduled.")
+
+ running = zope.schema.Bool(
+ title=u"Is Running",
+ description=u"Tells you whether a task is running or not.",
+ default=False)
+
+ def start():
+ """Start to schedule the task."""
+
+ def stop():
+ """Stop running the task."""
+
+ def computeDelayToNextCall():
+ """Calculate the delay to the next execution of this task.
+
+ The returned value should be a float or integer that specifies the
+ time in seconds. Note that not all operating systems support floating
+ points.
+ """
+
+ def __call__():
+ """Execute the task and reschedule it."""
+
+
+class ITaskStatistic(Interface):
+ """Keeps track of statistical information about the task."""
+
+ count = zope.schema.Int(
+ title=u"Execution Counter",
+ description=u"Specifies how many times the callable has been executed,"
+ u"since the task was started.",
+ default=0)
+
+
+class ILoopTask(ITask):
+ """A task that is executed at a particular interval."""
+
+ timeInterval = zope.schema.Int(
+ title=u"Interval",
+ description=u"Interval between calls in seconds",
+ default=60)
+
+
+class ICronTask(ITask):
+ """A special task that schedules the job based on cron-like information."""
+
+ minute = zope.schema.Tuple(
+ title=u"Minute",
+ description=u"The minute (list) to run the task.",
+ value_type=zope.schema.Int(min=0, max=59)
+ )
+
+ hour = zope.schema.Tuple(
+ title=u"Hour",
+ description=u"The hour (list) to run the task.",
+ value_type=zope.schema.Int(min=0, max=23)
+ )
+
+ dayOfMonth = zope.schema.Tuple(
+ title=u"Day of Month",
+ description=u"The day of month (list) to run the task.",
+ value_type=zope.schema.Int(min=1, max=31)
+ )
+
+ month = zope.schema.Tuple(
+ title=u"Month",
+ description=u"The month (list) to run the task.",
+ value_type=zope.schema.Int(min=1, max=12)
+ )
+
+ dayOfWeek = zope.schema.Tuple(
+ title=u"Day of Week",
+ description=u"The day of week (list) to run the task.",
+ value_type=zope.schema.Int(min=0, max=7)
+ )
Property changes on: Zope3/branches/srichter-twisted-integration/src/scheduler/interfaces.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/branches/srichter-twisted-integration/src/scheduler/loop.py
===================================================================
--- Zope3/branches/srichter-twisted-integration/src/scheduler/loop.py 2005-04-28 17:53:11 UTC (rev 30212)
+++ Zope3/branches/srichter-twisted-integration/src/scheduler/loop.py 2005-04-28 17:53:55 UTC (rev 30213)
@@ -0,0 +1,35 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Simple Loop Scheduler Task
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+import zope.interface
+from scheduler import interfaces, task
+
+class LoopTask(task.Task):
+
+ zope.interface.implements(interfaces.ILoopTask)
+
+ def __init__(self, callable, arguments=(), keywords={}, interval=60):
+ super(LoopTask, self).__init__(callable, arguments, keywords)
+
+ # See scheduler.interfaces.ILoopTask
+ self.timeInterval = interval
+
+ def computeDelayToNextCall(self):
+ """See scheduler.interfaces.ITask"""
+ return self.timeInterval
Property changes on: Zope3/branches/srichter-twisted-integration/src/scheduler/loop.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/branches/srichter-twisted-integration/src/scheduler/manager.py
===================================================================
--- Zope3/branches/srichter-twisted-integration/src/scheduler/manager.py 2005-04-28 17:53:11 UTC (rev 30212)
+++ Zope3/branches/srichter-twisted-integration/src/scheduler/manager.py 2005-04-28 17:53:55 UTC (rev 30213)
@@ -0,0 +1,30 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Task Management objects for Zope 3
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+from zope.app import zapi
+from scheduler import interfaces
+
+def startAllTasks(event):
+ for name, task in zapi.getUtilitiesFor(interfaces.ITask):
+ task.start()
+
+def stopAllTasks(event):
+ for name, task in zapi.getUtilitiesFor(interfaces.ITask):
+ task.stop()
+
Property changes on: Zope3/branches/srichter-twisted-integration/src/scheduler/manager.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/branches/srichter-twisted-integration/src/scheduler/scheduler-configure.zcml
===================================================================
--- Zope3/branches/srichter-twisted-integration/src/scheduler/scheduler-configure.zcml 2005-04-28 17:53:11 UTC (rev 30212)
+++ Zope3/branches/srichter-twisted-integration/src/scheduler/scheduler-configure.zcml 2005-04-28 17:53:55 UTC (rev 30213)
@@ -0,0 +1 @@
+<include package="scheduler" />
\ No newline at end of file
Property changes on: Zope3/branches/srichter-twisted-integration/src/scheduler/scheduler-configure.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/branches/srichter-twisted-integration/src/scheduler/task.py
===================================================================
--- Zope3/branches/srichter-twisted-integration/src/scheduler/task.py 2005-04-28 17:53:11 UTC (rev 30212)
+++ Zope3/branches/srichter-twisted-integration/src/scheduler/task.py 2005-04-28 17:53:55 UTC (rev 30213)
@@ -0,0 +1,66 @@
+##############################################################################
+#
+# Copyright (c) 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Scheduler Task
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+import time
+import zope.interface
+from twisted.internet import defer, task, reactor
+from twisted.python import reflect
+
+from scheduler import interfaces
+
+class Task(task.LoopingCall):
+
+ zope.interface.implements(interfaces.ITask, interfaces.ITaskStatistic)
+
+ def __init__(self, callable, arguments=(), keywords={}):
+ task.LoopingCall.__init__(self, callable, *arguments, **keywords)
+
+
+ def start(self, now=False):
+ """See scheduler.interfaces.ITask"""
+ # The LoopingCall implementation sucks, so we make it better. :) The
+ # interval can be anything, since we ignore it anyways.
+ task.LoopingCall.start(self, 0, now)
+
+ def computeDelayToNextCall(self):
+ """See scheduler.interfaces.ITask"""
+ raise NotImplemented, \
+ 'Please implement `computeDelayToNextCall()` in a sub-class.'
+
+
+ def _reschedule(self):
+ """Schedule the next task execution."""
+ delay = self.computeDelayToNextCall()
+
+ if delay == 0:
+ self.call = reactor.callLater(0, self)
+ else:
+ self.call = reactor.callLater(delay, self)
+
+ def __repr__(self):
+ if hasattr(self.f, 'func_name'):
+ func = self.f.func_name
+ if hasattr(self.f, 'im_class'):
+ func = self.f.im_class.__name__ + '.' + func
+ else:
+ func = reflect.safe_repr(self.f)
+
+ return '%s(%s, *%s, **%s)' % (
+ self.__class__.__name__, func, reflect.safe_repr(self.a),
+ reflect.safe_repr(self.kw))
Property changes on: Zope3/branches/srichter-twisted-integration/src/scheduler/task.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/branches/srichter-twisted-integration/src/scheduler/tests.py
===================================================================
--- Zope3/branches/srichter-twisted-integration/src/scheduler/tests.py 2005-04-28 17:53:11 UTC (rev 30212)
+++ Zope3/branches/srichter-twisted-integration/src/scheduler/tests.py 2005-04-28 17:53:55 UTC (rev 30213)
@@ -0,0 +1,48 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Tests for the Preferences System
+
+$Id: tests.py 29143 2005-02-14 22:43:16Z srichter $
+"""
+import unittest
+from zope.testing import doctest, doctestunit
+from zope.app.testing import placelesssetup
+
+def isSameTime(time1, time2, error=1):
+ """Check whether the time is the same within a range +/- error."""
+ if time1-error < time2 and time1+error > time2:
+ return True
+ return False
+
+def setUp(test):
+ placelesssetup.setUp(test)
+
+def tearDown(test):
+ placelesssetup.tearDown(test)
+ # Let's remove all those delayed calls from the reactor
+ from twisted.internet import reactor
+ reactor._newTimedCalls = []
+
+
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocFileSuite('README.txt',
+ setUp=setUp, tearDown=tearDown,
+ globs={'pprint': doctestunit.pprint,
+ 'isSameTime': isSameTime},
+ optionflags=doctest.NORMALIZE_WHITESPACE),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(default='test_suite')
Property changes on: Zope3/branches/srichter-twisted-integration/src/scheduler/tests.py
___________________________________________________________________
Name: svn:eol-style
+ native
More information about the Zope3-Checkins
mailing list