Pulling in some changes from the skeleton
authorEd Page <eopage@byu.net>
Wed, 29 Dec 2010 03:36:28 +0000 (21:36 -0600)
committerEd Page <eopage@byu.net>
Wed, 29 Dec 2010 13:40:43 +0000 (07:40 -0600)
src/util/go_utils.py
src/util/io.py
src/util/linux.py
src/util/time_utils.py [new file with mode: 0644]
src/util/tp_utils.py

index d066542..97d671c 100644 (file)
@@ -191,7 +191,7 @@ class AsyncPool(object):
                                result = func(*args, **kwds)
                                isError = False
                        except Exception, e:
-                               _moduleLogger.error("Error, passing it back to the main thread")
+                               _moduleLogger.exception("Error, passing it back to the main thread")
                                result = e
                                isError = True
                        self.__workQueue.task_done()
@@ -221,7 +221,7 @@ class AsyncLinearExecution(object):
 
        @misc.log_exception(_moduleLogger)
        def on_success(self, result):
-               _moduleLogger.debug("Processing success for: %r", self._func)
+               #_moduleLogger.debug("Processing success for: %r", self._func)
                try:
                        trampoline, args, kwds = self._run.send(result)
                except StopIteration, e:
@@ -237,7 +237,7 @@ class AsyncLinearExecution(object):
 
        @misc.log_exception(_moduleLogger)
        def on_error(self, error):
-               _moduleLogger.debug("Processing error for: %r", self._func)
+               #_moduleLogger.debug("Processing error for: %r", self._func)
                try:
                        trampoline, args, kwds = self._run.throw(error)
                except StopIteration, e:
index aece2dd..aac896d 100644 (file)
@@ -7,7 +7,12 @@ import os
 import pickle
 import contextlib
 import itertools
-import functools
+import codecs
+import csv
+try:
+       import cStringIO as StringIO
+except ImportError:
+       import StringIO
 
 
 @contextlib.contextmanager
@@ -127,3 +132,78 @@ def relpath(p1, p2):
                return os.path.join(*relParts)
        else:
                return "."+os.sep
+
+
+class UTF8Recoder(object):
+       """
+       Iterator that reads an encoded stream and reencodes the input to UTF-8
+       """
+       def __init__(self, f, encoding):
+               self.reader = codecs.getreader(encoding)(f)
+
+       def __iter__(self):
+               return self
+
+       def next(self):
+               return self.reader.next().encode("utf-8")
+
+
+class UnicodeReader(object):
+       """
+       A CSV reader which will iterate over lines in the CSV file "f",
+       which is encoded in the given encoding.
+       """
+
+       def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
+               f = UTF8Recoder(f, encoding)
+               self.reader = csv.reader(f, dialect=dialect, **kwds)
+
+       def next(self):
+               row = self.reader.next()
+               return [unicode(s, "utf-8") for s in row]
+
+       def __iter__(self):
+               return self
+
+class UnicodeWriter(object):
+       """
+       A CSV writer which will write rows to CSV file "f",
+       which is encoded in the given encoding.
+       """
+
+       def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
+               # Redirect output to a queue
+               self.queue = StringIO.StringIO()
+               self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
+               self.stream = f
+               self.encoder = codecs.getincrementalencoder(encoding)()
+
+       def writerow(self, row):
+               self.writer.writerow([s.encode("utf-8") for s in row])
+               # Fetch UTF-8 output from the queue ...
+               data = self.queue.getvalue()
+               data = data.decode("utf-8")
+               # ... and reencode it into the target encoding
+               data = self.encoder.encode(data)
+               # write to the target stream
+               self.stream.write(data)
+               # empty queue
+               self.queue.truncate(0)
+
+       def writerows(self, rows):
+               for row in rows:
+                       self.writerow(row)
+
+
+def unicode_csv_reader(unicode_csv_data, dialect=csv.excel, **kwargs):
+       # csv.py doesn't do Unicode; encode temporarily as UTF-8:
+       csv_reader = csv.reader(utf_8_encoder(unicode_csv_data),
+                                                       dialect=dialect, **kwargs)
+       for row in csv_reader:
+               # decode UTF-8 back to Unicode, cell by cell:
+               yield [unicode(cell, 'utf-8') for cell in row]
+
+
+def utf_8_encoder(unicode_csv_data):
+       for line in unicode_csv_data:
+               yield line.encode('utf-8')
index 4837f2a..4e77445 100644 (file)
@@ -1,13 +1,79 @@
 #!/usr/bin/env python
 
 
+import os
 import logging
 
+try:
+       from xdg import BaseDirectory as _BaseDirectory
+       BaseDirectory = _BaseDirectory
+except ImportError:
+       BaseDirectory = None
+
+
+_moduleLogger = logging.getLogger(__name__)
+
+
+_libc = None
+
 
 def set_process_name(name):
        try: # change process name for killall
-               import ctypes
-               libc = ctypes.CDLL('libc.so.6')
-               libc.prctl(15, name, 0, 0, 0)
+               global _libc
+               if _libc is None:
+                       import ctypes
+                       _libc = ctypes.CDLL('libc.so.6')
+               _libc.prctl(15, name, 0, 0, 0)
        except Exception, e:
-               logging.warning('Unable to set processName: %s" % e')
+               _moduleLogger.warning('Unable to set processName: %s" % e')
+
+
+def get_new_resource(resourceType, resource, name):
+       if BaseDirectory is not None:
+               if resourceType == "data":
+                       base = BaseDirectory.xdg_data_home
+                       if base == "/usr/share/mime":
+                               # Ugly hack because somehow Maemo 4.1 seems to be set to this
+                               base = os.path.join(os.path.expanduser("~"), ".%s" % resource)
+               elif resourceType == "config":
+                       base = BaseDirectory.xdg_config_home
+               elif resourceType == "cache":
+                       base = BaseDirectory.xdg_cache_home
+               else:
+                       raise RuntimeError("Unknown type: "+resourceType)
+       else:
+               base = os.path.join(os.path.expanduser("~"), ".%s" % resource)
+
+       filePath = os.path.join(base, resource, name)
+       dirPath = os.path.dirname(filePath)
+       if not os.path.exists(dirPath):
+               # Looking before I leap to not mask errors
+               os.makedirs(dirPath)
+
+       return filePath
+
+
+def get_existing_resource(resourceType, resource, name):
+       if BaseDirectory is not None:
+               if resourceType == "data":
+                       base = BaseDirectory.xdg_data_home
+               elif resourceType == "config":
+                       base = BaseDirectory.xdg_config_home
+               elif resourceType == "cache":
+                       base = BaseDirectory.xdg_cache_home
+               else:
+                       raise RuntimeError("Unknown type: "+resourceType)
+       else:
+               base = None
+
+       if base is not None:
+               finalPath = os.path.join(base, name)
+               if os.path.exists(finalPath):
+                       return finalPath
+
+       altBase = os.path.join(os.path.expanduser("~"), ".%s" % resource)
+       finalPath = os.path.join(altBase, name)
+       if os.path.exists(finalPath):
+               return finalPath
+       else:
+               raise RuntimeError("Resource not found: %r" % ((resourceType, resource, name), ))
diff --git a/src/util/time_utils.py b/src/util/time_utils.py
new file mode 100644 (file)
index 0000000..90ec84d
--- /dev/null
@@ -0,0 +1,94 @@
+from datetime import tzinfo, timedelta, datetime
+
+ZERO = timedelta(0)
+HOUR = timedelta(hours=1)
+
+
+def first_sunday_on_or_after(dt):
+       days_to_go = 6 - dt.weekday()
+       if days_to_go:
+               dt += timedelta(days_to_go)
+       return dt
+
+
+# US DST Rules
+#
+# This is a simplified (i.e., wrong for a few cases) set of rules for US
+# DST start and end times. For a complete and up-to-date set of DST rules
+# and timezone definitions, visit the Olson Database (or try pytz):
+# http://www.twinsun.com/tz/tz-link.htm
+# http://sourceforge.net/projects/pytz/ (might not be up-to-date)
+#
+# In the US, since 2007, DST starts at 2am (standard time) on the second
+# Sunday in March, which is the first Sunday on or after Mar 8.
+DSTSTART_2007 = datetime(1, 3, 8, 2)
+# and ends at 2am (DST time; 1am standard time) on the first Sunday of Nov.
+DSTEND_2007 = datetime(1, 11, 1, 1)
+# From 1987 to 2006, DST used to start at 2am (standard time) on the first
+# Sunday in April and to end at 2am (DST time; 1am standard time) on the last
+# Sunday of October, which is the first Sunday on or after Oct 25.
+DSTSTART_1987_2006 = datetime(1, 4, 1, 2)
+DSTEND_1987_2006 = datetime(1, 10, 25, 1)
+# From 1967 to 1986, DST used to start at 2am (standard time) on the last
+# Sunday in April (the one on or after April 24) and to end at 2am (DST time;
+# 1am standard time) on the last Sunday of October, which is the first Sunday
+# on or after Oct 25.
+DSTSTART_1967_1986 = datetime(1, 4, 24, 2)
+DSTEND_1967_1986 = DSTEND_1987_2006
+
+
+class USTimeZone(tzinfo):
+
+       def __init__(self, hours, reprname, stdname, dstname):
+               self.stdoffset = timedelta(hours=hours)
+               self.reprname = reprname
+               self.stdname = stdname
+               self.dstname = dstname
+
+       def __repr__(self):
+               return self.reprname
+
+       def tzname(self, dt):
+               if self.dst(dt):
+                       return self.dstname
+               else:
+                       return self.stdname
+
+       def utcoffset(self, dt):
+               return self.stdoffset + self.dst(dt)
+
+       def dst(self, dt):
+               if dt is None or dt.tzinfo is None:
+                       # An exception may be sensible here, in one or both cases.
+                       # It depends on how you want to treat them.  The default
+                       # fromutc() implementation (called by the default astimezone()
+                       # implementation) passes a datetime with dt.tzinfo is self.
+                       return ZERO
+               assert dt.tzinfo is self
+
+               # Find start and end times for US DST. For years before 1967, return
+               # ZERO for no DST.
+               if 2006 < dt.year:
+                       dststart, dstend = DSTSTART_2007, DSTEND_2007
+               elif 1986 < dt.year < 2007:
+                       dststart, dstend = DSTSTART_1987_2006, DSTEND_1987_2006
+               elif 1966 < dt.year < 1987:
+                       dststart, dstend = DSTSTART_1967_1986, DSTEND_1967_1986
+               else:
+                       return ZERO
+
+               start = first_sunday_on_or_after(dststart.replace(year=dt.year))
+               end = first_sunday_on_or_after(dstend.replace(year=dt.year))
+
+               # Can't compare naive to aware objects, so strip the timezone from
+               # dt first.
+               if start <= dt.replace(tzinfo=None) < end:
+                       return HOUR
+               else:
+                       return ZERO
+
+
+Eastern  = USTimeZone(-5, "Eastern",  "EST", "EDT")
+Central  = USTimeZone(-6, "Central",  "CST", "CDT")
+Mountain = USTimeZone(-7, "Mountain", "MST", "MDT")
+Pacific  = USTimeZone(-8, "Pacific",  "PST", "PDT")
index 1c6cbc8..30d7629 100644 (file)
@@ -25,7 +25,7 @@ class WasMissedCall(object):
                self._didReport = False
 
                self._onTimeout = gobject_utils.Timeout(self._on_timeout)
-               self._onTimeout.start(seconds=10)
+               self._onTimeout.start(seconds=60)
 
                chan[telepathy.interfaces.CHANNEL_INTERFACE_GROUP].connect_to_signal(
                        "MembersChanged",