Mercurial > treepkg > treepkg
view treepkg/status.py @ 39:17756cdce844
Make defining a status class easier with a meta class
author | Bernhard Herzog <bh@intevation.de> |
---|---|
date | Thu, 15 Mar 2007 13:00:01 +0100 |
parents | dd88230dd762 |
children | c544903eeced |
line wrap: on
line source
# Copyright (C) 2007 by Intevation GmbH # Authors: # Bernhard Herzog <bh@intevation.de> # # 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() class FieldDesc(object): def __init__(self, default=nodefault): self.default = default def has_default(self): return self.default is not nodefault def serialize(self, value): raise NotImplementedError def deserialize(self, string): raise NotImplementedError class StringFieldDesc(FieldDesc): def serialize(self, value): return str(value) def deserialize(self, value): return value.strip() class DateFieldDesc(FieldDesc): date_format = "%Y-%m-%d %H:%M:%S" def serialize(self, value): return value.strftime(self.date_format) def deserialize(self, string): return datetime.datetime(*time.strptime(string.strip(), self.date_format)[:6]) class StatusMetaClass(type): def __new__(cls, name, bases, clsdict): # Generate the _fields class variable from the field descriptors # in clsdict. fields = dict() for key, value in clsdict.items(): if isinstance(value, FieldDesc): fields[key] = value del clsdict[key] clsdict["_fields"] = fields return type.__new__(cls, name, bases, clsdict) class Status(object): __metaclass__ = StatusMetaClass # Overwrite in derived classes with a different magic string _magic = "Status 0.0\n" # Derived classes may extend a copy of this set with more instance # variables. _attrs = set(["_filename", "_values"]) 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) class RevisionStatus(Status): _magic = "TreePackagerStatus 0.0\n" status = StringFieldDesc(default="unknown") start = DateFieldDesc(default=None) stop = DateFieldDesc(default=None)