+ chdir(self.dir)
+ def __exit__(self, *args):
+ chdir(self.olddir)
+
+class Counter(object):
+ """
+ Object for counting different values when you don't know what
+ they are a priori. Supports index access and iteration.
+
+ >>> counter = Counter()
+ >>> counter.count("foo")
+ >>> print counter["foo"]
+ 1
+ """
+ def __init__(self):
+ self.dict = {}
+ def count(self, value):
+ """Increments count for ``value``."""
+ self.dict.setdefault(value, 0)
+ self.dict[value] += 1
+ def __getitem__(self, key):
+ return self.dict[key]
+ def __iter__(self):
+ return self.dict.__iter__()
+ def max(self):
+ """Returns the max counter value seen."""
+ return max(self.dict.values())
+ def sum(self):
+ """Returns the sum of all counter values."""
+ return sum(self.dict.values())
+ def keys(self):
+ """Returns the keys of counters."""
+ return self.dict.keys()
+
+class PipeToLess(object):
+ """
+ Context for printing output to a pager. Use this if output
+ is expected to be long.
+ """
+ def __enter__(self):
+ self.proc = subprocess.Popen("less", stdin=subprocess.PIPE)
+ self.old_stdout = sys.stdout
+ sys.stdout = self.proc.stdin
+ def __exit__(self, *args):
+ if self.proc:
+ self.proc.stdin.close()
+ self.proc.wait()
+ sys.stdout = self.old_stdout
+
+class IgnoreKeyboardInterrupts(object):
+ """
+ Context for temporarily ignoring keyboard interrupts. Use this
+ if aborting would cause more harm than finishing the job.
+ """
+ def __enter__(self):
+ signal.signal(signal.SIGINT,signal.SIG_IGN)
+ def __exit__(self, *args):
+ signal.signal(signal.SIGINT, signal.default_int_handler)
+
+class LockDirectory(object):
+ """
+ Context for locking a directory.
+ """
+ def __init__(self, lockfile):
+ self.lockfile = lockfile
+ def __enter__(self):
+ try:
+ os.open(self.lockfile, os.O_CREAT | os.O_EXCL)
+ except OSError as e:
+ if e.errno == errno.EEXIST:
+ raise DirectoryLockedError(os.getcwd())
+ elif e.errno == errno.EACCES:
+ raise PermissionsError(os.getcwd())
+ raise