5 from xml.dom import minidom
9 class NonExistent(object):
13 class Optional(object):
16 Even you don't have to worry about knowing when to perform None checks
17 When the NULL object pattern just isn't good enough
22 >>> a.get_nothrow("Blacksheep")
27 >>> a.get_nothrow("Blacksheep"), a.get(), a()
28 ('Lamb', 'Lamb', 'Lamb')
32 >>> a.get_nothrow("Blacksheep")
35 >>> b = Optional("Lamb")
39 >>> a.get_nothrow("Blacksheep"), a.get(), a()
40 ('Lamb', 'Lamb', 'Lamb')
44 >>> a.get_nothrow("Blacksheep")
48 def __init__(self, value = NonExistent):
55 self._value = NonExistent
58 return self._value is not NonExistent
60 def get_nothrow(self, default = None):
61 return self._value if self.is_good() else default
64 if not self.is_good():
65 raise ReferenceError("Optional not initialized")
69 # Implemented to imitate weakref
73 return str(self.get_nothrow(""))
76 return "<Optional at %x; to %r>" % (
77 id(self), self.get_nothrow("Nothing")
81 return not self.is_good()
83 def __eq__(self, rhs):
84 return self._value == rhs._value
86 def __ne__(self, rhs):
87 return self._value != rhs._value
89 def __lt__(self, rhs):
90 return self._value < rhs._value
92 def __le__(self, rhs):
93 return self._value <= rhs._value
95 def __gt__(self, rhs):
96 return self._value > rhs._value
98 def __ge__(self, rhs):
99 return self._value >= rhs._value
102 def open_anything(source, alternative=None):
103 """URI, filename, or string --> stream
105 This function lets you define parsers that take any input source
106 (URL, pathname to local or network file, or actual data as a string)
107 and deal with it in a uniform manner. Returned object is guaranteed
108 to have all the basic stdio read methods (read, readline, readlines).
109 Just .close() the object when you're done with it.
111 if hasattr(source, "read"):
117 # try to open with urllib (if source is http, ftp, or file URL)
119 return urllib.urlopen(source)
120 except (IOError, OSError):
122 print "ERROR with URL ("+source+")!\n"
124 # try to open with native open function (if source is pathname)
127 except (IOError, OSError):
129 print "ERROR with file!\n"
131 # treat source as string
132 if alternative == None:
133 print 'LAST RESORT. String is "'+source+'"\n'
134 return StringIO.StringIO(str(source))
136 print 'LAST RESORT. String is "'+alternative+'"\n'
137 return StringIO.StringIO(str(alternative))
140 def load_xml(source, alternative=None):
141 """load XML input source, return parsed XML document
143 - a URL of a remote XML file ("http://diveintopython.org/kant.xml")
144 - a filename of a local XML file ("~/diveintopython/common/py/kant.xml")
145 - standard input ("-")
146 - the actual XML document, as a string
148 sock = open_anything(source, alternative)
150 xmldoc = minidom.parse(sock).documentElement
151 except (IOError, OSError):
152 print "ERROR with data"
154 sock = open_anything('<response method="getProjects"><project projName="ERROR!"/></response>')
155 xmldoc = minidom.parse(sock).documentElement
160 def abbreviate(text, expectedLen):
161 singleLine = " ".join(text.split("\n"))
162 lineLen = len(singleLine)
163 if lineLen <= expectedLen:
168 leftLen = expectedLen // 2 - 1
169 rightLen = max(expectedLen - leftLen - len(abbrev) + 1, 1)
171 abbrevText = singleLine[0:leftLen] + abbrev + singleLine[-rightLen:-1]
172 assert len(abbrevText) <= expectedLen, "Too long: '%s'" % abbrevText
176 def abbreviate_url(url, domainLength, pathLength):
177 urlParts = urlparse.urlparse(url)
179 netloc = urlParts.netloc
182 pathLength += max(domainLength - len(netloc), 0)
183 domainLength += max(pathLength - len(path), 0)
185 netloc = abbreviate(netloc, domainLength)
186 path = abbreviate(path, pathLength)
190 def is_same_year(targetDate, todaysDate = datetime.datetime.today()):
191 return targetDate.year == todaysDate.year
194 def is_same_month(targetDate, todaysDate = datetime.datetime.today()):
195 return targetDate.month == todaysDate.month
198 def is_same_day(targetDate, todaysDate = datetime.datetime.today()):
199 return targetDate.day == todaysDate.day
202 def to_fuzzy_date(targetDate, todaysDate = datetime.datetime.today()):
204 Conert a date/time/datetime object to a fuzzy date
206 >>> todaysDate = datetime.date(2009, 4, 16)
207 >>> to_fuzzy_date(datetime.date(1, 4, 6), todaysDate)
209 >>> to_fuzzy_date(datetime.date(2008, 4, 13), todaysDate)
211 >>> to_fuzzy_date(datetime.date(2009, 4, 13), todaysDate)
213 >>> to_fuzzy_date(datetime.date(2009, 4, 20), todaysDate)
215 >>> to_fuzzy_date(datetime.date(2010, 4, 13), todaysDate)
217 >>> to_fuzzy_date(datetime.date(2012, 12, 12), todaysDate)
220 delta = targetDate - todaysDate
221 days = abs(delta.days)
222 noDifference = datetime.timedelta()
223 isFuture = noDifference < delta
224 directionBy1 = "Next" if isFuture else "Last"
225 directionByN = "Later" if isFuture else "Earlier"
227 yearDelta = abs(targetDate.year - todaysDate.year)
229 directionByInf = "from now" if isFuture else "ago"
230 return "Forever %s" % directionByInf
232 return "%s year" % directionBy1
234 monthDelta = abs(targetDate.month - todaysDate.month)
236 return "%s this year" % directionByN
237 elif 1 == monthDelta:
238 return "%s month" % directionBy1
240 dayDelta = abs(targetDate.day - todaysDate.day)
242 return "%s this month" % directionByN
244 directionInWeek = "This" if isFuture else "Last"
245 days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
246 return "%s %s" % (directionInWeek, days[targetDate.weekday()])
248 return "%s day" % directionBy1