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)
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)