# HG changeset patch # User Bernhard Herzog # Date 1173460989 -3600 # Node ID f9f15ee39ed7e02abab1b4a17aaddb8901343d0b # Parent 6efe0bd3d8c114f24f2a747f37a70cd098c10c48 New Status class that handles several fields diff -r 6efe0bd3d8c1 -r f9f15ee39ed7 test/runtests.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtests.py Fri Mar 09 18:23:09 2007 +0100 @@ -0,0 +1,72 @@ +# Copyright (C) 2007 by Intevation GmbH +# Authors: +# Bernhard Herzog +# +# This program is free software under the GPL (>=v2) +# Read the file COPYING coming with the software for details. + +""" +Main entry point for the test suite. + +Just run this file as a python script to execute all tests +""" + +import os +import sys +import unittest +import optparse + +test_dir = os.path.dirname(__file__) +sys.path.append(os.path.join(test_dir, os.pardir)) + +def find_test_modules(dirname, package = None): + """Return a list the names of the test modules in the directory dirname + + The return value is a list of names that can be passed to + unittest.defaultTestLoader.loadTestsFromNames. Each name of the + list is the name of a pure python module, one for each file in + dirname whose name starts with 'test' and ends with '.py'. + + The optional parameter package should be the name of the python + package whose directory is dirname. If package is given all names + in the returned list will be prefixed with package and a dot. + """ + if package: + prefix = package + "." + else: + prefix = "" + + suffix = ".py" + return [prefix + name[:-len(suffix)] + for name in os.listdir(dirname) + if name.startswith("test") and name.endswith(suffix)] + + +def main(): + """Run all the tests in the test suite""" + + parser = optparse.OptionParser() + parser.set_defaults(verbosity=1) + parser.add_option("-v", "--verbose", action="store_const", const=2, + dest="verbosity") + opts, rest = parser.parse_args() + + # Build the list of test names. If names were given on the command + # line, run exactly those. Othwerwise build a default list of + # names. + if rest: + names = rest + else: + # All Python files starting with 'test' in the current directory + # and some directories in Extensions contain test cases. + # FIXME: It should be possible to run runtests.py even when not in + # the test directory + names = find_test_modules(test_dir) + suite = unittest.defaultTestLoader.loadTestsFromNames(names) + runner = unittest.TextTestRunner(verbosity=opts.verbosity) + result = runner.run(suite) + sys.exit(not result.wasSuccessful()) + + +if __name__ == "__main__": + main() diff -r 6efe0bd3d8c1 -r f9f15ee39ed7 test/test_status.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/test_status.py Fri Mar 09 18:23:09 2007 +0100 @@ -0,0 +1,62 @@ +# Copyright (C) 2007 by Intevation GmbH +# Authors: +# Bernhard Herzog +# +# This program is free software under the GPL (>=v2) +# Read the file COPYING coming with the software for details. + +"""Tests for the Status class""" + +import os +import unittest +from datetime import datetime + +from treepkg.status import Status +from treepkg.util import ensure_directory, writefile + + + +class TestStatus(unittest.TestCase): + + def tempfilename(self): + tempdir = os.path.join(os.path.dirname(__file__), "temp") + ensure_directory(tempdir) + return os.path.join(tempdir, self.id()) + + def setUp(self): + self.filename = self.tempfilename() + if os.path.exists(self.filename): + os.remove(self.filename) + + def test_status(self): + status = Status(self.filename) + status.status = "testing" + + otherstatus = Status(self.filename) + self.assertEquals(otherstatus.status, "testing") + + def test_getting_unknown_fields(self): + status = Status(self.filename) + self.assertRaises(AttributeError, getattr, status, "unknown_field") + + def test_setting_unknown_fields(self): + status = Status(self.filename) + self.assertRaises(AttributeError, + setattr, status, "unknown_field", "some value") + + def test_default_value(self): + status = Status(self.filename) + self.assertEquals(status.start, None) + + def test_date(self): + timestamp = datetime(2007, 3, 9, 17, 32, 55) + status = Status(self.filename) + status.start = timestamp + + otherstatus = Status(self.filename) + self.assertEquals(otherstatus.start, timestamp) + + def test_magic(self): + writefile(self.filename, + "Some other magic\nstart: 2007-03-09 17:32:55\n") + self.assertRaises(ValueError, Status, self.filename) diff -r 6efe0bd3d8c1 -r f9f15ee39ed7 treepkg/status.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/treepkg/status.py Fri Mar 09 18:23:09 2007 +0100 @@ -0,0 +1,103 @@ +# Copyright (C) 2007 by Intevation GmbH +# Authors: +# Bernhard Herzog +# +# This program is free software under the GPL (>=v2) +# Read the file COPYING coming with the software for details. + +import os +import datetime +import time + +import util + + +# special object to indicate no default value +nodefault = object() + +def serialize_datetime(d): + return d.strftime("%Y-%m-%d %H:%M:%S") + +def deserialize_datetime(s): + return datetime.datetime(*time.strptime(s.strip(), "%Y-%m-%d %H:%M:%S")[:6]) + + +class FieldDesc(object): + + def __init__(self, serialize, deserialize, default=nodefault): + self.serialize = serialize + self.deserialize = deserialize + self.default = default + + def has_default(self): + return self.default is not nodefault + +class StringFieldDesc(FieldDesc): + + def __init__(self, **kw): + super(StringFieldDesc, self).__init__(str, lambda s: s.strip(), **kw) + +class DateFieldDesc(FieldDesc): + + def __init__(self, **kw): + super(DateFieldDesc, self).__init__(serialize_datetime, + deserialize_datetime, **kw) + + +class Status(object): + + fields = dict(status=StringFieldDesc(), + start=DateFieldDesc(default=None)) + + attrs = set(["filename", "values"]) + + magic = "TreePackagerStatus 0.0\n" + + def __init__(self, filename): + assert os.path.isabs(filename) + self.filename = filename + self.read() + + def _init_values(self): + self.values = {} + + def read(self): + self._init_values() + if not os.path.exists(self.filename): + return + f = open(self.filename) + try: + magic = f.next() + if magic != self.magic: + raise ValueError("File %r has wrong magic" % self.filename) + for line in f: + field, value = line.split(":", 1) + self.values[field] = self.fields[field].deserialize(value) + finally: + f.close() + + def write(self): + lines = [self.magic] + for field, desc in self.fields.items(): + if field in self.values: + lines.append("%s: %s\n" + % (field, desc.serialize(self.values[field]))) + util.writefile(self.filename, "".join(lines)) + + def __getattr__(self, attr): + desc = self.fields.get(attr) + if desc is not None: + if attr in self.values: + return self.values[attr] + elif desc.has_default(): + return desc.default + raise AttributeError(attr) + + def __setattr__(self, attr, value): + if attr in self.fields: + self.values[attr] = value + self.write() + elif attr in self.attrs: + self.__dict__[attr] = value + else: + raise AttributeError(attr)