python3 - 2to3 + miscell obvious tweaks
[sfa.git] / sfa / storage / record.py
1
2
3 from sfa.util.sfatime import utcparse, datetime_to_string
4 from datetime import datetime
5 from sfa.util.xml import XML
6 from sfa.trust.gid import GID
7
8 from sfa.util.sfalogging import logger
9 from sfa.util.py23 import StringType
10
11
12 class Record:
13
14     def __init__(self, dict=None, xml_str=None):
15         if dict:
16             self.load_from_dict(dict)
17         elif xml_str:
18             xml = XML(xml_str)
19             xml_dict = xml.todict()
20             self.load_from_dict(xml_dict)
21
22     def get_field(self, field):
23         return self.__dict__.get(field, None)
24
25     # xxx fixme
26     # turns out the date_created field is received by the client as a 'created' int
27     # (and 'last_updated' does not make it at all)
28     # let's be flexible
29     def date_repr(self, fields):
30         if not isinstance(fields, list):
31             fields = [fields]
32         for field in fields:
33             value = getattr(self, field, None)
34             if isinstance(value, datetime):
35                 return datetime_to_string(value)
36             elif isinstance(value, (int, float)):
37                 return datetime_to_string(utcparse(value))
38         # fallback
39         return "** undef_datetime **"
40
41     #
42     # need to filter out results, esp. wrt relationships
43     # exclude_types must be a tuple so we can use isinstance
44     #
45     def record_to_dict(self, exclude_types=None):
46         if exclude_types is None:
47             exclude_types = ()
48         d = self.__dict__
49
50         def exclude(k, v):
51             return k.startswith('_') or isinstance(v, exclude_types)
52         keys = [k for k, v in list(d.items()) if not exclude(k, v)]
53         return {k: d[k] for k in keys}
54
55     def toxml(self):
56         return self.save_as_xml()
57
58     def load_from_dict(self, d):
59         for (k, v) in d.items():
60             # experimental
61             if isinstance(v, StringType) and v.lower() in ['true']:
62                 v = True
63             if isinstance(v, StringType) and v.lower() in ['false']:
64                 v = False
65             setattr(self, k, v)
66
67     # in addition we provide convenience for converting to and from xml records
68     # for this purpose only, we need the subclasses to define 'fields' as either
69     # a list or a dictionary
70     def fields(self):
71         fields = list(self.__dict__.keys())
72         return fields
73
74     def save_as_xml(self):
75         # xxx not sure about the scope here
76         input_dict = dict([(key, getattr(self, key))
77                            for key in self.fields() if getattr(self, key, None)])
78         xml_record = XML("<record />")
79         xml_record.parse_dict(input_dict)
80         return xml_record.toxml()
81
82     def dump(self, format=None, dump_parents=False, sort=False):
83         if not format:
84             format = 'text'
85         else:
86             format = format.lower()
87         if format == 'text':
88             self.dump_text(dump_parents, sort=sort)
89         elif format == 'xml':
90             print(self.save_as_xml())
91         elif format == 'simple':
92             print(self.dump_simple())
93         else:
94             raise Exception("Invalid format %s" % format)
95
96     def dump_text(self, dump_parents=False, sort=False):
97         print(40 * '=')
98         print("RECORD")
99         # print remaining fields
100         fields = self.fields()
101         if sort:
102             fields.sort()
103         for attrib_name in fields:
104             attrib = getattr(self, attrib_name)
105             # skip internals
106             if attrib_name.startswith('_'):
107                 continue
108             # skip callables
109             if callable(attrib):
110                 continue
111             # handle gid
112             if attrib_name == 'gid':
113                 print("    gid:")
114                 print(GID(string=attrib).dump_string(8, dump_parents))
115             elif attrib_name in ['date created', 'last updated']:
116                 print("    %s: %s" % (attrib_name, self.date_repr(attrib_name)))
117             else:
118                 print("    %s: %s" % (attrib_name, attrib))
119
120     def dump_simple(self):
121         return "%s" % self