diff options
author | Tomás Touceda <chiiph@leap.se> | 2014-02-17 12:45:19 -0300 |
---|---|---|
committer | Tomás Touceda <chiiph@leap.se> | 2014-02-17 12:45:19 -0300 |
commit | 32e3c5ddaa5df30a573762e273f3a12f7eb3c255 (patch) | |
tree | 0924be918d990628e73eb2059fb6eb1200748b7c /src/leap/mail/utils.py | |
parent | 7828c517ae162de4676a71e05f77339598acd6f7 (diff) | |
parent | 985ff0a78a8df0eafb7789383f711b9e5ceb1cb6 (diff) |
Merge remote-tracking branch 'refs/remotes/kali/bug/separate_deferreds_threads' into develop
Diffstat (limited to 'src/leap/mail/utils.py')
-rw-r--r-- | src/leap/mail/utils.py | 104 |
1 files changed, 102 insertions, 2 deletions
diff --git a/src/leap/mail/utils.py b/src/leap/mail/utils.py index 942acfb..fed24b3 100644 --- a/src/leap/mail/utils.py +++ b/src/leap/mail/utils.py @@ -17,10 +17,10 @@ """ Mail utilities. """ -import copy import json import re import traceback +import Queue from leap.soledad.common.document import SoledadDocument @@ -49,7 +49,7 @@ def empty(thing): thing = thing.content try: return len(thing) == 0 - except ReferenceError: + except (ReferenceError, TypeError): return True @@ -94,6 +94,7 @@ def lowerdict(_dict): PART_MAP = "part_map" +PHASH = "phash" def _str_dict(d, k): @@ -130,6 +131,103 @@ def stringify_parts_map(d): return d +def phash_iter(d): + """ + A recursive generator that extracts all the payload-hashes + from an arbitrary nested parts-map dictionary. + + :param d: the dictionary to walk + :type d: dictionary + :return: a list of all the phashes found + :rtype: list + """ + if PHASH in d: + yield d[PHASH] + if PART_MAP in d: + for key in d[PART_MAP]: + for phash in phash_iter(d[PART_MAP][key]): + yield phash + + +def accumulator(fun, lim): + """ + A simple accumulator that uses a closure and a mutable + object to collect items. + When the count of items is greater than `lim`, the + collection is flushed after invoking a map of the function `fun` + over it. + + The returned accumulator can also be flushed at any moment + by passing a boolean as a second parameter. + + :param fun: the function to call over the collection + when its size is greater than `lim` + :type fun: callable + :param lim: the turning point for the collection + :type lim: int + :rtype: function + + >>> from pprint import pprint + >>> acc = accumulator(pprint, 2) + >>> acc(1) + >>> acc(2) + [1, 2] + >>> acc(3) + >>> acc(4) + [3, 4] + >>> acc = accumulator(pprint, 5) + >>> acc(1) + >>> acc(2) + >>> acc(3) + >>> acc(None, flush=True) + [1,2,3] + """ + KEY = "items" + _o = {KEY: []} + + def _accumulator(item, flush=False): + collection = _o[KEY] + collection.append(item) + if len(collection) >= lim or flush: + map(fun, filter(None, collection)) + _o[KEY] = [] + + return _accumulator + + +def accumulator_queue(fun, lim): + """ + A version of the accumulator that uses a queue. + + When the count of items is greater than `lim`, the + queue is flushed after invoking the function `fun` + over its items. + + The returned accumulator can also be flushed at any moment + by passing a boolean as a second parameter. + + :param fun: the function to call over the collection + when its size is greater than `lim` + :type fun: callable + :param lim: the turning point for the collection + :type lim: int + :rtype: function + """ + _q = Queue.Queue() + + def _accumulator(item, flush=False): + _q.put(item) + if _q.qsize() >= lim or flush: + collection = [_q.get() for i in range(_q.qsize())] + map(fun, filter(None, collection)) + + return _accumulator + + +# +# String manipulation +# + class CustomJsonScanner(object): """ This class is a context manager definition used to monkey patch the default @@ -169,6 +267,8 @@ class CustomJsonScanner(object): if not monkey_patched: return self._orig_scanstring(s, idx, *args, **kwargs) + # TODO profile to see if a compiled regex can get us some + # benefit here. found = False end = s.find("\"", idx) while not found: |