summaryrefslogtreecommitdiffstats
path: root/module/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'module/plugins')
-rw-r--r--module/plugins/internal/misc.py747
-rw-r--r--module/plugins/internal/utils.py482
2 files changed, 747 insertions, 482 deletions
diff --git a/module/plugins/internal/misc.py b/module/plugins/internal/misc.py
new file mode 100644
index 000000000..de6b37163
--- /dev/null
+++ b/module/plugins/internal/misc.py
@@ -0,0 +1,747 @@
+# -*- coding: utf-8 -*-
+#
+#@TODO: Move to utils directory 0.4.10
+
+from __future__ import with_statement
+
+# import HTMLParser #@TODO: Use in 0.4.10
+import datetime
+import hashlib
+import htmlentitydefs
+import itertools
+import os
+import re
+import shutil
+import string
+import sys
+import time
+import traceback
+import urllib
+import urlparse
+import xml.sax.saxutils #@TODO: Remove in 0.4.10
+import zlib
+
+try:
+ import simplejson as json
+
+except ImportError:
+ import json
+
+
+#@TODO: Remove in 0.4.10
+class misc(object):
+ __name__ = "misc"
+ __type__ = "plugin"
+ __version__ = "0.09"
+ __status__ = "stable"
+
+ __pattern__ = r'^unmatchable$'
+ __config__ = []
+
+ __description__ = """Dummy utils class"""
+ __license__ = "GPLv3"
+ __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
+
+
+class SimpleQueue(object):
+
+ def __init__(self, plugin, storage="queue"):
+ self.plugin = plugin
+ self.storage = storage
+
+
+ def get(self):
+ return self.plugin.db.retrieve(self.storage, default=[])
+
+
+ def set(self, value):
+ return self.plugin.db.store(self.storage, value)
+
+
+ def delete(self):
+ return self.plugin.db.delete(self.storage)
+
+
+ def add(self, item):
+ queue = self.get()
+ if item not in queue:
+ return self.set(queue + [item])
+ else:
+ return True
+
+
+ def remove(self, item):
+ queue = self.get()
+ try:
+ queue.remove(item)
+
+ except ValueError:
+ pass
+
+ if isinstance(queue, list):
+ return self.delete()
+
+ return self.set(queue)
+
+
+class Expose(object):
+ """
+ Used for decoration to declare rpc services
+ """
+ def __new__(cls, f, *args, **kwargs):
+ hookManager.addRPC(f.__module__, f.func_name, f.func_doc)
+ return f
+
+
+def threaded(fn):
+ def run(*args, **kwargs):
+ hookManager.startThread(fn, *args, **kwargs)
+
+ return run
+
+
+def lock(fn):
+ def new(*args):
+ args[0].lock.acquire()
+ try:
+ return fn(*args)
+
+ finally:
+ args[0].lock.release()
+
+ return new
+
+
+def format_time(value):
+ dt = datetime.datetime(1, 1, 1) + datetime.timedelta(seconds=abs(int(value)))
+ days = ("%d days and " % (dt.day - 1)) if dt.day > 1 else ""
+ return days + ", ".join("%d %ss" % (getattr(dt, attr), attr)
+ for attr in ("hour", "minute", "second")
+ if getattr(dt, attr))
+
+
+def format_size(value):
+ for unit in ('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'):
+ if abs(value) < 1024.0:
+ return "%3.2f %s" % (value, unit)
+ else:
+ value /= 1024.0
+
+ return "%.2f %s" % (value, 'EiB')
+
+
+def compare_time(start, end):
+ start = map(int, start)
+ end = map(int, end)
+
+ if start == end:
+ return True
+
+ now = list(time.localtime()[3:5])
+
+ if start < end:
+ if now < end:
+ return True
+
+ elif now > start or now < end:
+ return True
+
+ return False
+
+
+def free_space(folder):
+ if os.name is "nt":
+ import ctypes
+
+ free_bytes = ctypes.c_ulonglong(0)
+ ctypes.windll.kernel32.GetDiskFreeSpaceExW(ctypes.c_wchar_p(folder),
+ None,
+ None,
+ ctypes.pointer(free_bytes))
+ return free_bytes.value
+
+ else:
+ s = os.statvfs(folder)
+ return s.f_frsize * s.f_bavail
+
+
+def fsbsize(path):
+ """
+ Get optimal file system buffer size (in bytes) for I/O calls
+ """
+ path = encode(path)
+
+ if os.name is "nt":
+ import ctypes
+
+ drive = "%s\\" % os.path.splitdrive(path)[0]
+ cluster_sectors, sector_size = ctypes.c_longlong(0)
+
+ ctypes.windll.kernel32.GetDiskFreeSpaceW(ctypes.c_wchar_p(drive),
+ ctypes.pointer(cluster_sectors),
+ ctypes.pointer(sector_size),
+ None,
+ None)
+ return cluster_sectors * sector_size
+
+ else:
+ return os.statvfs(path).f_frsize
+
+
+def uniqify(seq):
+ """
+ Remove duplicates from list preserving order
+ Originally by Dave Kirby
+ """
+ seen = set()
+ seen_add = seen.add
+ return [x for x in seq if x not in seen and not seen_add(x)]
+
+
+def has_method(obj, name):
+ """
+ Check if name was defined in obj (return false if inhereted)
+ """
+ return hasattr(obj, '__dict__') and name in obj.__dict__
+
+
+def html_unescape(text):
+ """
+ Removes HTML or XML character references and entities from a text string
+ """
+ return xml.sax.saxutils.unescape(text)
+ #@TODO: Replace in 0.4.10 with:
+ # h = HTMLParser.HTMLParser()
+ # return h.unescape(text)
+
+
+def isiterable(obj):
+ """
+ Check if object is iterable (string excluded)
+ """
+ return hasattr(obj, "__iter__")
+
+
+def get_console_encoding(enc):
+ if os.name is "nt":
+ if enc is "cp65001": #: aka UTF-8
+ enc = "cp850"
+ # print "WARNING: Windows codepage 65001 (UTF-8) is not supported, used `%s` instead" % enc
+ else:
+ enc = "utf8"
+
+ return enc
+
+
+#@NOTE: Revert to `decode` in Python 3
+def decode(value, encoding=None):
+ """
+ Encoded string (default to UTF-8) -> unicode string
+ """
+ if type(value) is str:
+ try:
+ # res = value.decode(encoding or 'utf-8')
+ res = unicode(value, encoding or 'utf-8')
+
+ except UnicodeDecodeError, e:
+ if encoding:
+ raise UnicodeDecodeError(e)
+
+ encoding = get_console_encoding(sys.stdout.encoding)
+ # res = value.decode(encoding)
+ res = unicode(value, encoding)
+
+ elif type(value) is unicode:
+ res = value
+
+ else:
+ res = unicode(value)
+
+ return res
+
+
+def encode(value, encoding=None, decoding=None):
+ """
+ Unicode or decoded string -> encoded string (default to UTF-8)
+ """
+ if type(value) is unicode:
+ res = value.encode(encoding or "utf-8")
+
+ # elif type(value) is str:
+ # res = encode(decode(value, decoding), encoding)
+
+ else:
+ res = str(value)
+
+ return res
+
+
+def exists(path):
+ path = encode(path)
+
+ if os.path.exists(path):
+ if os.name is "nt":
+ dir, name = os.path.split(path.rstrip(os.sep))
+ return name in os.listdir(dir)
+ else:
+ return True
+ else:
+ return False
+
+
+def remove_chars(value, repl):
+ """
+ Remove all chars in repl from string
+ """
+ if type(repl) is unicode:
+ for badc in list(repl):
+ value = value.replace(badc, "")
+ return value
+
+ elif type(value) is unicode:
+ return value.translate(dict((ord(s), None) for s in repl))
+
+ elif type(value) is str:
+ return value.translate(string.maketrans("", ""), repl)
+
+
+def fixurl(url, unquote=None):
+ old = url
+ url = urllib.unquote(url)
+
+ if unquote is None:
+ unquote = url is old
+
+ url = html_unescape(decode(url).decode('unicode-escape'))
+ url = re.sub(r'(?<!:)/{2,}', '/', url).strip().lstrip('.')
+
+ if not unquote:
+ url = urllib.quote(url)
+
+ return url
+
+
+def fsjoin(*args):
+ """
+ Like os.path.join, but encoding aware
+ (for safe-joining see `safejoin`)
+ """
+ return encode(os.path.join(args))
+
+
+def truncate(name, length):
+ max_trunc = len(name) / 2
+ if length > max_trunc:
+ raise OSError("File name too long")
+
+ trunc = int((len(name) - length) / 3)
+ return "%s~%s" % (name[:trunc * 2], name[-trunc:])
+
+
+#@TODO: Recheck in 0.4.10
+def safepath(value):
+ """
+ Remove invalid characters and truncate the path if needed
+ """
+ drive, filename = os.path.splitdrive(value)
+ filename = os.path.join(*map(safename, filename.split(os.sep)))
+ path = os.path.abspath(drive + filename)
+
+ try:
+ if os.name is not "nt":
+ return
+
+ length = len(path) - 259
+ if length < 1:
+ return
+
+ dirname, basename = os.path.split(filename)
+ name, ext = os.path.splitext(basename)
+ path = drive + dirname + truncate(name, length) + ext
+
+ finally:
+ return path
+
+
+def safejoin(*args):
+ """
+ os.path.join + safepath
+ """
+ return safepath(os.path.join(*args))
+
+
+def safename(value):
+ """
+ Remove invalid characters
+ """
+ repl = '<>:"/\\|?*' if os.name is "nt" else '\0/\\"'
+ name = remove_chars(value, repl)
+ return name
+
+
+def parse_name(value, safechar=True):
+ path = fixurl(decode(value), unquote=False)
+ url_p = urlparse.urlparse(path.rstrip('/'))
+ name = (url_p.path.split('/')[-1] or
+ url_p.query.split('=', 1)[::-1][0].split('&', 1)[0] or
+ url_p.netloc.split('.', 1)[0])
+
+ name = urllib.unquote(name)
+ return safename(name) if safechar else name
+
+
+def parse_size(value, unit=""): #: returns bytes
+ m = re.match(r"([\d.,]+)\s*([\w^_]*)", str(value).lower())
+
+ if m is None:
+ return 0
+
+ size = float(m.group(1).replace(',', '.'))
+ unit = (unit.strip().lower() or m.group(2) or "byte")[0]
+
+ if unit is "b":
+ return int(size)
+
+ sizeunits = ['b', 'k', 'm', 'g', 't', 'p', 'e']
+ sizemap = dict((u, i * 10) for i, u in enumerate(sizeunits))
+ magnitude = sizemap[unit]
+
+ i, d = divmod(size, 1)
+ integer = int(i) << magnitude
+ decimal = int(d * (1024 ** (magnitude / 10)))
+
+ return integer + decimal
+
+
+def str2int(value):
+ try:
+ return int(value)
+ except:
+ pass
+
+ ones = ("zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
+ "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
+ "sixteen", "seventeen", "eighteen", "nineteen")
+ tens = ("", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy",
+ "eighty", "ninety")
+
+ o_tuple = [(w, i) for i, w in enumerate(ones)]
+ t_tuple = [(w, i * 10) for i, w in enumerate(tens)]
+
+ numwords = dict(o_tuple + t_tuple)
+ tokens = re.split(r"[\s\-]+", value.lower())
+
+ try:
+ return sum(numwords[word] for word in tokens)
+ except:
+ return 0
+
+
+def parse_time(value):
+ if re.search("da(il)?y|today", value):
+ seconds = seconds_to_midnight()
+
+ else:
+ regex = re.compile(r'(\d+| (?:this|an?) )\s*(hr|hour|min|sec|)', re.I)
+ seconds = sum((int(v) if v.strip() not in ("this", "a", "an") else 1) *
+ {'hr': 3600, 'hour': 3600, 'min': 60, 'sec': 1, '': 1}[u.lower()]
+ for v, u in regex.findall(value))
+ return seconds
+
+
+def timestamp():
+ return int(time.time() * 1000)
+
+
+def check_module(module):
+ try:
+ __import__(module)
+
+ except Exception:
+ return False
+
+ else:
+ return True
+
+
+def check_prog(command):
+ pipe = subprocess.PIPE
+ try:
+ subprocess.call(command, stdout=pipe, stderr=pipe)
+
+ except Exception:
+ return False
+
+ else:
+ return True
+
+
+def isexecutable(filename):
+ file = encode(filename)
+ return os.path.isfile(file) and os.access(file, os.X_OK)
+
+
+def which(filename):
+ """
+ Works exactly like the unix command which
+ Courtesy of http://stackoverflow.com/a/377028/675646
+ """
+ dirname, basename = os.path.split(filename)
+
+ if dirname:
+ return filename if isexecutable(filename) else None
+
+ else:
+ for path in os.environ['PATH'].split(os.pathsep):
+ filename = os.path.join(path.strip('"'), program)
+ if isexecutable(filename):
+ return filename
+
+
+def format_exc(frame=None):
+ """
+ Format call-stack and display exception information (if availible)
+ """
+ exc_info = sys.exc_info()
+ exc_desc = ""
+
+ callstack = traceback.extract_stack(frame)
+ callstack = callstack[:-1]
+
+ if exc_info[0] is not None:
+ exception_callstack = traceback.extract_tb(exc_info[2])
+
+ if callstack[-1][0] == exception_callstack[0][0]: #@NOTE: Does this exception belongs to us?
+ callstack = callstack[:-1]
+ callstack.extend(exception_callstack)
+ exc_desc = "".join(traceback.format_exception_only(exc_info[0], exc_info[1]))
+
+ msg = "Traceback (most recent call last):\n"
+ msg += "".join(traceback.format_list(callstack))
+ msg += exc_desc
+
+ return msg
+
+
+def seconds_to_nexthour(strict=False):
+ now = datetime.datetime.today()
+ nexthour = now.replace(minute=0 if strict else 1, second=0, microsecond=0) + datetime.timedelta(hours=1)
+ return (nexthour - now).seconds
+
+
+def seconds_to_midnight(utc=None, strict=False):
+ if utc is None:
+ now = datetime.datetime.today()
+ else:
+ now = datetime.datetime.utcnow() + datetime.timedelta(hours=utc)
+
+ midnight = now.replace(hour=0, minute=0 if strict else 1, second=0, microsecond=0) + datetime.timedelta(days=1)
+
+ return (midnight - now).seconds
+
+
+def replace_patterns(value, rules):
+ for r in rules:
+ try:
+ pattern, repl, flags = r
+
+ except ValueError:
+ pattern, repl = r
+ flags = 0
+
+ value = re.sub(pattern, repl, value, flags)
+
+ return value
+
+
+#@TODO: Remove in 0.4.10 and fix exp in CookieJar.setCookie
+def set_cookie(cj, domain, name, value, path='/', exp=time.time() + 180 * 24 * 3600):
+ return cj.setCookie(encode(domain), encode(name), encode(value), encode(path), int(exp))
+
+
+def set_cookies(cj, cookies):
+ for cookie in cookies:
+ if not isinstance(cookie, tuple):
+ continue
+
+ if len(cookie) is not 3:
+ continue
+
+ set_cookie(cj, *cookie)
+
+
+def parse_html_tag_attr_value(attr_name, tag):
+ m = re.search(r"%s\s*=\s*([\"']?)((?<=\")[^\"]+|(?<=')[^']+|[^>\s\"'][^>\s]*)\1" % attr_name, tag, re.I)
+ return m.group(2) if m else None
+
+
+def parse_html_form(attr_str, html, input_names={}):
+ for form in re.finditer(r"(?P<TAG><form[^>]*%s[^>]*>)(?P<CONTENT>.*?)</?(form|body|html)[^>]*>" % attr_str,
+ html, re.I | re.S):
+ inputs = {}
+ action = parse_html_tag_attr_value("action", form.group('TAG'))
+
+ for inputtag in re.finditer(r'(<(input|textarea)[^>]*>)([^<]*(?=</\2)|)', form.group('CONTENT'), re.I | re.S):
+ name = parse_html_tag_attr_value("name", inputtag.group(1))
+ if name:
+ value = parse_html_tag_attr_value("value", inputtag.group(1))
+ if not value:
+ inputs[name] = inputtag.group(3) or ""
+ else:
+ inputs[name] = value
+
+ if not input_names:
+ #: No attribute check
+ return action, inputs
+ else:
+ #: Check input attributes
+ for key, val in input_names.items():
+ if key in inputs:
+ if isinstance(val, basestring) and inputs[key] is val:
+ continue
+ elif isinstance(val, tuple) and inputs[key] in val:
+ continue
+ elif hasattr(val, "search") and re.match(val, inputs[key]):
+ continue
+ else:
+ break #: Attibute value does not match
+ else:
+ break #: Attibute name does not match
+ else:
+ return action, inputs #: Passed attribute check
+
+ return {}, None #: No matching form found
+
+
+def chunks(iterable, size):
+ it = iter(iterable)
+ item = list(itertools.islice(it, size))
+ while item:
+ yield item
+ item = list(itertools.islice(it, size))
+
+
+def renice(pid, value):
+ if not value or os.name is "nt":
+ return
+
+ try:
+ subprocess.Popen(["renice", str(value), str(pid)],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ bufsize=-1)
+ except Exception:
+ pass
+
+
+def forward(source, destination):
+ try:
+ bufsize = 1024
+ bufdata = source.recv(bufsize)
+ while bufdata:
+ destination.sendall(bufdata)
+ bufdata = source.recv(bufsize)
+ finally:
+ destination.shutdown(socket.SHUT_WR)
+
+
+def compute_checksum(filename, hashtype):
+ file = encode(filename)
+
+ if not exists(file):
+ return None
+
+ buf = fsbsize()
+
+ if hashtype in ("adler32", "crc32"):
+ hf = getattr(zlib, hashtype)
+ last = 0
+
+ with open(file, "rb") as f:
+ for chunk in iter(lambda: f.read(buf), b''):
+ last = hf(chunk, last)
+
+ return "%x" % last
+
+ elif hashtype in hashlib.algorithms_available:
+ h = hashlib.new(hashtype)
+
+ with open(file, "rb") as f:
+ for chunk in iter(lambda: f.read(buf * h.block_size), b''):
+ h.update(chunk)
+
+ return h.hexdigest()
+
+ else:
+ return None
+
+
+def copy_tree(src, dst, overwrite=False, preserve_metadata=False):
+ pmode = preserve_metadata or overwrite is None
+ mtime = os.path.getmtime
+ copy = shutil.copy2 if pmode else shutil.copy
+
+ if preserve_metadata and not exists(dst):
+ return shutil.copytree(src, dst)
+
+ for src_dir, dirs, files in os.walk(src, topdown=False):
+ dst_dir = src_dir.replace(src, dst, 1)
+
+ if not exists(dst_dir):
+ os.makedirs(dst_dir)
+ if pmode:
+ shutil.copystat(src_dir, dst_dir)
+
+ elif pmode:
+ if overwrite or overwrite is None and mtime(src_dir) > mtime(dst_dir):
+ shutil.copystat(src_dir, dst_dir)
+
+ for filename in files:
+ src_file = fsjoin(src_dir, filename)
+ dst_file = fsjoin(dst_dir, filename)
+
+ if exists(dst_file):
+ if overwrite or overwrite is None and mtime(src_file) > mtime(dst_file):
+ os.remove(dst_file)
+ else:
+ continue
+
+ copy(src_file, dst_dir)
+
+
+def move_tree(src, dst, overwrite=False):
+ mtime = os.path.getmtime
+
+ for src_dir, dirs, files in os.walk(src, topdown=False):
+ dst_dir = src_dir.replace(src, dst, 1)
+ del_dir = True
+
+ if not exists(dst_dir):
+ os.makedirs(dst_dir)
+ shutil.copystat(src_dir, dst_dir)
+
+ elif overwrite or overwrite is None and mtime(src_dir) > mtime(dst_dir):
+ shutil.copystat(src_dir, dst_dir)
+
+ else:
+ del_dir = False
+
+ for filename in files:
+ src_file = fsjoin(src_dir, filename)
+ dst_file = fsjoin(dst_dir, filename)
+
+ if exists(dst_file):
+ if overwrite or overwrite is None and mtime(src_file) > mtime(dst_file):
+ os.remove(dst_file)
+ else:
+ continue
+
+ shutil.move(src_file, dst_dir)
+
+ if not del_dir:
+ continue
+
+ try:
+ os.rmdir(src_dir)
+ except OSError:
+ pass
diff --git a/module/plugins/internal/utils.py b/module/plugins/internal/utils.py
deleted file mode 100644
index 02077cffd..000000000
--- a/module/plugins/internal/utils.py
+++ /dev/null
@@ -1,482 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-#@TODO: Move to utils directory 0.4.10
-
-import datetime
-import htmlentitydefs
-import itertools
-import os
-import re
-import string
-import sys
-import time
-import traceback
-import urllib
-import urlparse
-
-try:
- import HTMLParser
-
-except ImportError: #@TODO: Remove in 0.4.10
- import xml.sax.saxutils
-
-try:
- import simplejson as json
-
-except ImportError:
- import json
-
-
-class utils(object):
- __name__ = "utils"
- __type__ = "plugin"
- __version__ = "0.09"
- __status__ = "stable"
-
- __pattern__ = r'^unmatchable$'
- __config__ = []
-
- __description__ = """Dummy utils class"""
- __license__ = "GPLv3"
- __authors__ = [("Walter Purcaro", "vuolter@gmail.com")]
-
-
-def lock(fn):
- def new(*args):
- # print "Handler: %s args: %s" % (fn, args[1:])
- args[0].lock.acquire()
- try:
- return fn(*args)
-
- finally:
- args[0].lock.release()
-
- return new
-
-
-def format_time(value):
- dt = datetime.datetime(1, 1, 1) + datetime.timedelta(seconds=abs(int(value)))
- days = ("%d days and " % (dt.day - 1)) if dt.day > 1 else ""
- return days + ", ".join("%d %ss" % (getattr(dt, attr), attr) for attr in ("hour", "minute", "second")
- if getattr(dt, attr))
-
-
-def format_size(value):
- size = int(value)
- steps = 0
- sizes = ('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB')
- while size > 1000:
- size /= 1024.0
- steps += 1
- return "%.2f %s" % (size, sizes[steps])
-
-
-def safe_format(value, unsafe):
- """
- Returns the content of value omitting sensitive information
-
- Args:
- value: value to format
- unsafe: string or list: sensitive word(s) to remove
- """
- if isinstance(value, basestring):
- if isinstance(unsafe, basestring):
- return "'%s'" % ("**********" if value == unsafe else value)
-
- elif isinstance(unsafe, list):
- return "'%s'" % ("**********" if value in unsafe else value)
-
- elif isinstance(value, dict):
- return "{%s}" % ", ".join("'%s': %s" % (k, safe_format(v, unsafe)) for k, v in value.iteritems())
-
- elif isinstance(value, list):
- return "[%s]" % ", ".join("%s" % safe_format(v, unsafe) for v in value)
-
- elif isinstance(value, tuple):
- return "(%s)" % ", ".join("%s" % safe_format(v, unsafe) for v in value)
-
- elif isinstance(value, set):
- return "set([%s])" % ", ".join("%s" % safe_format(v, unsafe) for v in value)
-
- return repr(value)
-
-
-def compare_time(start, end):
- start = map(int, start)
- end = map(int, end)
-
- if start == end:
- return True
-
- now = list(time.localtime()[3:5])
-
- if start < end:
- if now < end:
- return True
-
- elif now > start or now < end:
- return True
-
- return False
-
-
-def uniqify(seq):
- """
- Remove duplicates from list preserving order
- Originally by Dave Kirby
- """
- seen = set()
- seen_add = seen.add
- return [x for x in seq if x not in seen and not seen_add(x)]
-
-
-def has_method(obj, name):
- """
- Check if name was defined in obj (return false if inhereted)
- """
- return hasattr(obj, '__dict__') and name in obj.__dict__
-
-
-def html_unescape(text):
- """
- Removes HTML or XML character references and entities from a text string
- """
- try:
- h = HTMLParser.HTMLParser()
- return h.unescape(text)
-
- except NameError: #@TODO: Remove in 0.4.10
- return xml.sax.saxutils.unescape(text)
-
-
-def isiterable(obj):
- return hasattr(obj, "__iter__")
-
-
-def get_console_encoding(enc):
- if os.name is "nt":
- if enc is "cp65001": #: aka UTF-8
- enc = "cp850"
- print "WARNING: Windows codepage 65001 (UTF-8) is not supported, used `%s` instead" % enc
- else:
- enc = "utf8"
-
- return enc
-
-
-#@NOTE: Revert to `decode` in Python 3
-def decode(value, encoding=None):
- """
- Encoded string (default to UTF-8) -> unicode string
- """
- if type(value) is str:
- try:
- # res = value.decode(encoding or 'utf-8')
- res = unicode(value, encoding or 'utf-8')
-
- except UnicodeDecodeError, e:
- if encoding:
- raise UnicodeDecodeError(e)
-
- encoding = get_console_encoding(sys.stdout.encoding)
- # res = value.decode(encoding)
- res = unicode(value, encoding)
-
- elif type(value) is unicode:
- res = value
-
- else:
- res = unicode(value)
-
- return res
-
-
-def encode(value, encoding=None, decoding=None):
- """
- Unicode or decoded string -> encoded string (default to UTF-8)
- """
- if type(value) is unicode:
- res = value.encode(encoding or "utf-8")
-
- # elif type(value) is str:
- # res = encode(decode(value, decoding), encoding)
-
- else:
- res = str(value)
-
- return res
-
-
-def fs_join(*args):
- """
- Like os.path.join, but encoding aware
- """
- return os.path.join(*map(encode, args))
-
-
-def exists(path):
- if os.path.exists(path):
- if os.name is "nt":
- dir, name = os.path.split(path.rstrip(os.sep))
- return name in os.listdir(dir)
- else:
- return True
- else:
- return False
-
-
-def remove_chars(value, repl):
- """
- Remove all chars in repl from string
- """
- if type(repl) is unicode:
- for badc in list(repl):
- value = value.replace(badc, "")
- return value
-
- elif type(value) is unicode:
- return value.translate(dict((ord(s), None) for s in repl))
-
- elif type(value) is str:
- return value.translate(string.maketrans("", ""), repl)
-
-
-def fixurl(url, unquote=None):
- old = url
- url = urllib.unquote(url)
-
- if unquote is None:
- unquote = url is old
-
- url = html_unescape(decode(url).decode('unicode-escape'))
- url = re.sub(r'(?<!:)/{2,}', '/', url).strip().lstrip('.')
-
- if not unquote:
- url = urllib.quote(url)
-
- return url
-
-
-def fixname(value):
- repl = '<>:"/\\|?*' if os.name is "nt" else '\0/\\"'
- return remove_chars(value, repl)
-
-
-def parse_name(value, safechar=True):
- path = fixurl(decode(value), unquote=False)
- url_p = urlparse.urlparse(path.rstrip('/'))
- name = (url_p.path.split('/')[-1] or
- url_p.query.split('=', 1)[::-1][0].split('&', 1)[0] or
- url_p.netloc.split('.', 1)[0])
-
- name = urllib.unquote(name)
- return fixname(name) if safechar else name
-
-
-def parse_size(value, unit=""): #: returns bytes
- m = re.match(r"([\d.,]+)\s*([\w^_]*)", str(value).lower())
-
- if m is None:
- return 0
-
- traffic = float(m.group(1).replace(',', '.'))
- unit = (unit.strip().lower() or m.group(2) or "byte")[0]
-
- if unit is "b":
- return int(traffic)
-
- sizes = ['b', 'k', 'm', 'g', 't', 'p', 'e']
- sizemap = dict((u, i * 10) for i, u in enumerate(sizes))
-
- increment = sizemap[unit]
- integer, decimal = map(int, ("%.3f" % traffic).split('.'))
-
- return (integer << increment) + (decimal << increment - 10)
-
-
-def str2int(value):
- try:
- return int(value)
- except:
- pass
-
- ones = ("zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
- "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
- "sixteen", "seventeen", "eighteen", "nineteen")
- tens = ("", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy",
- "eighty", "ninety")
-
- o_tuple = [(w, i) for i, w in enumerate(ones)]
- t_tuple = [(w, i * 10) for i, w in enumerate(tens)]
-
- numwords = dict(o_tuple + t_tuple)
- tokens = re.split(r"[\s\-]+", value.lower())
-
- try:
- return sum(numwords[word] for word in tokens)
- except:
- return 0
-
-
-def parse_time(value):
- if re.search("da(il)?y|today", value):
- seconds = seconds_to_midnight()
-
- else:
- regex = re.compile(r'(\d+| (?:this|an?) )\s*(hr|hour|min|sec|)', re.I)
- seconds = sum((int(v) if v.strip() not in ("this", "a", "an") else 1) *
- {'hr': 3600, 'hour': 3600, 'min': 60, 'sec': 1, '': 1}[u.lower()]
- for v, u in regex.findall(value))
- return seconds
-
-
-def timestamp():
- return int(time.time() * 1000)
-
-
-def which(program):
- """
- Works exactly like the unix command which
- Courtesy of http://stackoverflow.com/a/377028/675646
- """
- isExe = lambda x: os.path.isfile(x) and os.access(x, os.X_OK)
-
- fpath, fname = os.path.split(program)
-
- if fpath:
- if isExe(program):
- return program
- else:
- for path in os.environ['PATH'].split(os.pathsep):
- exe_file = os.path.join(path.strip('"'), program)
- if isExe(exe_file):
- return exe_file
-
-
-def format_exc(frame=None):
- """
- Format call-stack and display exception information (if availible)
- """
- exception_info = sys.exc_info()
- callstack_list = traceback.extract_stack(frame)
- callstack_list = callstack_list[:-1]
-
- exception_desc = ""
- if exception_info[0] is not None:
- exception_callstack_list = traceback.extract_tb(exception_info[2])
- if callstack_list[-1][0] == exception_callstack_list[0][0]: #Does this exception belongs to us?
- callstack_list = callstack_list[:-1]
- callstack_list.extend(exception_callstack_list)
- exception_desc = "".join(traceback.format_exception_only(exception_info[0], exception_info[1]))
-
- traceback_str = "Traceback (most recent call last):\n"
- traceback_str += "".join(traceback.format_list(callstack_list))
- traceback_str += exception_desc
-
- return traceback_str
-
-
-def seconds_to_nexthour(strict=False):
- now = datetime.datetime.today()
- nexthour = now.replace(minute=0 if strict else 1, second=0, microsecond=0) + datetime.timedelta(hours=1)
- return (nexthour - now).seconds
-
-
-def seconds_to_midnight(utc=None, strict=False):
- if utc is None:
- now = datetime.datetime.today()
- else:
- now = datetime.datetime.utcnow() + datetime.timedelta(hours=utc)
-
- midnight = now.replace(hour=0, minute=0 if strict else 1, second=0, microsecond=0) + datetime.timedelta(days=1)
-
- return (midnight - now).seconds
-
-
-def replace_patterns(value, rules):
- for r in rules:
- try:
- pattern, repl, flags = r
-
- except ValueError:
- pattern, repl = r
- flags = 0
-
- value = re.sub(pattern, repl, value, flags)
-
- return value
-
-
-#@TODO: Remove in 0.4.10 and fix exp in CookieJar.setCookie
-def set_cookie(cj, domain, name, value, path='/', exp=time.time() + 180 * 24 * 3600):
- return cj.setCookie(encode(domain), encode(name), encode(value), encode(path), int(exp))
-
-
-def set_cookies(cj, cookies):
- for cookie in cookies:
- if isinstance(cookie, tuple) and len(cookie) == 3:
- set_cookie(cj, *cookie)
-
-
-def parse_html_tag_attr_value(attr_name, tag):
- m = re.search(r"%s\s*=\s*([\"']?)((?<=\")[^\"]+|(?<=')[^']+|[^>\s\"'][^>\s]*)\1" % attr_name, tag, re.I)
- return m.group(2) if m else None
-
-
-def parse_html_form(attr_str, html, input_names={}):
- for form in re.finditer(r"(?P<TAG><form[^>]*%s[^>]*>)(?P<CONTENT>.*?)</?(form|body|html)[^>]*>" % attr_str,
- html, re.I | re.S):
- inputs = {}
- action = parse_html_tag_attr_value("action", form.group('TAG'))
-
- for inputtag in re.finditer(r'(<(input|textarea)[^>]*>)([^<]*(?=</\2)|)', form.group('CONTENT'), re.I | re.S):
- name = parse_html_tag_attr_value("name", inputtag.group(1))
- if name:
- value = parse_html_tag_attr_value("value", inputtag.group(1))
- if not value:
- inputs[name] = inputtag.group(3) or ""
- else:
- inputs[name] = value
-
- if not input_names:
- #: No attribute check
- return action, inputs
- else:
- #: Check input attributes
- for key, val in input_names.items():
- if key in inputs:
- if isinstance(val, basestring) and inputs[key] is val:
- continue
- elif isinstance(val, tuple) and inputs[key] in val:
- continue
- elif hasattr(val, "search") and re.match(val, inputs[key]):
- continue
- else:
- break #: Attibute value does not match
- else:
- break #: Attibute name does not match
- else:
- return action, inputs #: Passed attribute check
-
- return {}, None #: No matching form found
-
-
-def chunks(iterable, size):
- it = iter(iterable)
- item = list(itertools.islice(it, size))
- while item:
- yield item
- item = list(itertools.islice(it, size))
-
-
-def renice(pid, value):
- if not value or os.name is "nt":
- return
-
- try:
- subprocess.Popen(["renice", str(value), str(pid)],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- bufsize=-1)
- except Exception:
- pass