import sys
import StringIO
import urllib
+import urlparse
from xml.dom import minidom
import datetime
+class NonExistent(object):
+ pass
+
+
+class Optional(object):
+ """
+ Taglines:
+ Even you don't have to worry about knowing when to perform None checks
+ When the NULL object pattern just isn't good enough
+
+ >>> a = Optional()
+ >>> a.is_good()
+ False
+ >>> a.get_nothrow("Blacksheep")
+ 'Blacksheep'
+ >>> a.set("Lamb")
+ >>> a.is_good()
+ True
+ >>> a.get_nothrow("Blacksheep"), a.get(), a()
+ ('Lamb', 'Lamb', 'Lamb')
+ >>> a.clear()
+ >>> a.is_good()
+ False
+ >>> a.get_nothrow("Blacksheep")
+ 'Blacksheep'
+ >>>
+ >>> b = Optional("Lamb")
+ >>> a.set("Lamb")
+ >>> a.is_good()
+ True
+ >>> a.get_nothrow("Blacksheep"), a.get(), a()
+ ('Lamb', 'Lamb', 'Lamb')
+ >>> a.clear()
+ >>> a.is_good()
+ False
+ >>> a.get_nothrow("Blacksheep")
+ 'Blacksheep'
+ """
+
+ def __init__(self, value = NonExistent):
+ self._value = value
+
+ def set(self, value):
+ self._value = value
+
+ def clear(self):
+ self._value = NonExistent
+
+ def is_good(self):
+ return self._value is not NonExistent
+
+ def get_nothrow(self, default = None):
+ return self._value if self.is_good() else default
+
+ def get(self):
+ if not self.is_good():
+ raise ReferenceError("Optional not initialized")
+ return self._value
+
+ def __call__(self):
+ # Implemented to imitate weakref
+ return self.get()
+
+ def __str__(self):
+ return str(self.get_nothrow(""))
+
+ def __repr__(self):
+ return "<Optional at %x; to %r>" % (
+ id(self), self.get_nothrow("Nothing")
+ )
+
+ def __not__(self):
+ return not self.is_good()
+
+ def __eq__(self, rhs):
+ return self._value == rhs._value
+
+ def __ne__(self, rhs):
+ return self._value != rhs._value
+
+ def __lt__(self, rhs):
+ return self._value < rhs._value
+
+ def __le__(self, rhs):
+ return self._value <= rhs._value
+
+ def __gt__(self, rhs):
+ return self._value > rhs._value
+
+ def __ge__(self, rhs):
+ return self._value >= rhs._value
+
+
def open_anything(source, alternative=None):
"""URI, filename, or string --> stream
and deal with it in a uniform manner. Returned object is guaranteed
to have all the basic stdio read methods (read, readline, readlines).
Just .close() the object when you're done with it.
-
- Examples:
- >>> from xml.dom import minidom
- >>> sock = openAnything("http://localhost/kant.xml")
- >>> doc = minidom.parse(sock)
- >>> sock.close()
- >>> sock = openAnything("c:\\inetpub\\wwwroot\\kant.xml")
- >>> doc = minidom.parse(sock)
- >>> sock.close()
- >>> sock = openAnything("<ref id='conjunction'><text>and</text><text>or</text></ref>")
- >>> doc = minidom.parse(sock)
- >>> sock.close()
"""
if hasattr(source, "read"):
return source
return xmldoc
+def abbreviate(text, expectedLen):
+ singleLine = " ".join(text.split("\n"))
+ lineLen = len(singleLine)
+ if lineLen <= expectedLen:
+ return singleLine
+
+ abbrev = "..."
+
+ leftLen = expectedLen // 2 - 1
+ rightLen = max(expectedLen - leftLen - len(abbrev) + 1, 1)
+
+ abbrevText = singleLine[0:leftLen] + abbrev + singleLine[-rightLen:-1]
+ assert len(abbrevText) <= expectedLen, "Too long: '%s'" % abbrevText
+ return abbrevText
+
+
+def abbreviate_url(url, domainLength, pathLength):
+ urlParts = urlparse.urlparse(url)
+
+ netloc = urlParts.netloc
+ path = urlParts.path
+
+ pathLength += max(domainLength - len(netloc), 0)
+ domainLength += max(pathLength - len(path), 0)
+
+ netloc = abbreviate(netloc, domainLength)
+ path = abbreviate(path, pathLength)
+ return netloc + path
+
+
+def is_same_year(targetDate, todaysDate = datetime.datetime.today()):
+ return targetDate.year == todaysDate.year
+
+
+def is_same_month(targetDate, todaysDate = datetime.datetime.today()):
+ return targetDate.month == todaysDate.month
+
+
+def is_same_day(targetDate, todaysDate = datetime.datetime.today()):
+ return targetDate.day == todaysDate.day
+
+
def to_fuzzy_date(targetDate, todaysDate = datetime.datetime.today()):
"""
Conert a date/time/datetime object to a fuzzy date
- @bug Not perfect, but good enough for now
+ >>> todaysDate = datetime.date(2009, 4, 16)
+ >>> to_fuzzy_date(datetime.date(1, 4, 6), todaysDate)
+ 'Forever ago'
+ >>> to_fuzzy_date(datetime.date(2008, 4, 13), todaysDate)
+ 'Last year'
+ >>> to_fuzzy_date(datetime.date(2009, 4, 13), todaysDate)
+ 'Last Monday'
+ >>> to_fuzzy_date(datetime.date(2009, 4, 20), todaysDate)
+ 'This Monday'
+ >>> to_fuzzy_date(datetime.date(2010, 4, 13), todaysDate)
+ 'Next year'
+ >>> to_fuzzy_date(datetime.date(2012, 12, 12), todaysDate)
+ 'Forever from now'
"""
delta = targetDate - todaysDate
days = abs(delta.days)
- directionBy1 = "Next" if 0 < delta.days else "Last"
- directionByN = "Later" if 0 < delta.days else "Earlier"
- directionByInf = "from now" if 0 < delta.days else "ago"
- if 2*365 < days:
+ noDifference = datetime.timedelta()
+ isFuture = noDifference < delta
+ directionBy1 = "Next" if isFuture else "Last"
+ directionByN = "Later" if isFuture else "Earlier"
+
+ yearDelta = abs(targetDate.year - todaysDate.year)
+ if 1 < yearDelta:
+ directionByInf = "from now" if isFuture else "ago"
return "Forever %s" % directionByInf
- elif 365 < days:
+ elif 1 == yearDelta:
return "%s year" % directionBy1
- elif 2*30 < days:
+
+ monthDelta = abs(targetDate.month - todaysDate.month)
+ if 1 < monthDelta:
return "%s this year" % directionByN
- elif 30 < days:
+ elif 1 == monthDelta:
return "%s month" % directionBy1
- elif 14 < days:
+
+ dayDelta = abs(targetDate.day - todaysDate.day)
+ if 14 < dayDelta:
return "%s this month" % directionByN
- elif 7 < days:
- return "%s week" % directionBy1
- elif 2 < days:
- return "%s this week" % directionByN
- elif 1 < days:
- return "%s day" % directionByN
+ elif 1 < dayDelta:
+ directionInWeek = "This" if isFuture else "Last"
+ days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
+ return "%s %s" % (directionInWeek, days[targetDate.weekday()])
+ elif 1 == dayDelta:
+ return "%s day" % directionBy1
else:
return "Today"