1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | #!/usr/bin/python2.5 # Copyright (C) 2007 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from gtfsfactoryuser import GtfsFactoryUser class GtfsObjectBase(GtfsFactoryUser): """Object with arbitrary attributes which may be added to a schedule. This class should be used as the base class for GTFS objects which may be stored in a Schedule. It defines some methods for reading and writing attributes. If self._schedule is None than the object is not in a Schedule. Subclasses must: * define an __init__ method which sets the _schedule member to None or a weakref to a Schedule * Set the _TABLE_NAME class variable to a name such as 'stops', 'agency', ... * define methods to validate objects of that type: * ValidateBeforeAdd, which is called before an object is added to a Schedule. With the default loader the object is added to the Schedule if this function returns True, and is not added if it returns False. * ValidateAfterAdd, which is called after an object is added to a Schedule. With the default Loader the return value, if any, is not used. """ def __getitem__(self, name): """Return a unicode or str representation of name or "" if not set.""" if name in self.__dict__ and self.__dict__[name] is not None: return "%s" % self.__dict__[name] else: return "" def __getattr__(self, name): """Return None or the default value if name is a known attribute. This method is only called when name is not found in __dict__. """ if name in self.__class__._FIELD_NAMES: return None else: raise AttributeError(name) def iteritems(self): """Return a iterable for (name, value) pairs of public attributes.""" for name, value in self.__dict__.iteritems(): if (not name) or name[0] == "_": continue yield name, value def __setattr__(self, name, value): """Set an attribute, adding name to the list of columns as needed.""" object.__setattr__(self, name, value) if name[0] != '_' and self._schedule: self._schedule.AddTableColumn(self.__class__._TABLE_NAME, name) def __eq__(self, other): """Return true iff self and other are equivalent""" if not other: return False if id(self) == id(other): return True for k in self.keys().union(other.keys()): # use __getitem__ which returns "" for missing columns values if self[k] != other[k]: return False return True def __ne__(self, other): return not self.__eq__(other) # TODO(Tom): According to # http://docs.python.org/reference/datamodel.html#object.__hash__ # this class should set '__hash__ = None' because it defines __eq__. This # can't be fixed until the merger is changed to not use a/b_merge_map. def __repr__(self): return "<%s %s>" % (self.__class__.__name__, sorted(self.iteritems())) def keys(self): """Return iterable of columns used by this object.""" columns = set() for name in vars(self): if (not name) or name[0] == "_": continue columns.add(name) return columns def _ColumnNames(self): return self.keys() |