Source code for vivialconnect.common.util

"""
.. module:: util
   :synopsis: Various utility functions shipped with Vivial Connect
              Python API.

"""
# Inspired by https://github.com/Shopify/pyactiveresource

import re
import json

import six
from six.moves.urllib.parse import urlencode


# Patterns blatantly stolen from Rails' Inflector
PLURALIZE_PATTERNS = [
    (r"(quiz)$", r"\1zes"),
    (r"^(ox)$", r"\1en"),
    (r"([m|l])ouse$", r"\1ice"),
    (r"(matr|vert|ind)(?:ix|ex)$", r"\1ices"),
    (r"(x|ch|ss|sh)$", r"\1es"),
    (r"([^aeiouy]|qu)y$", r"\1ies"),
    (r"(hive)$", r"1s"),
    (r"(?:([^f])fe|([lr])f)$", r"\1\2ves"),
    (r"sis$", r"ses"),
    (r"([ti])um$", r"\1a"),
    (r"(buffal|tomat)o$", r"\1oes"),
    (r"(bu)s$", r"\1ses"),
    (r"(alias|status)$", r"\1es"),
    (r"(octop|vir)us$", r"\1i"),
    (r"(ax|test)is$", r"\1es"),
    (r"s$", "s"),
    (r"$", "s"),
]

SINGULARIZE_PATTERNS = [
    (r"(quiz)zes$", r"\1"),
    (r"(matr)ices$", r"\1ix"),
    (r"(vert|ind)ices$", r"\1ex"),
    (r"^(ox)en", r"\1"),
    (r"(alias|status)es$", r"\1"),
    (r"(octop|vir)i$", r"\1us"),
    (r"(cris|ax|test)es$", r"\1is"),
    (r"(shoe)s$", r"\1"),
    (r"(o)es$", r"\1"),
    (r"(bus)es$", r"\1"),
    (r"([m|l])ice$", r"\1ouse"),
    (r"(x|ch|ss|sh)es$", r"\1"),
    (r"(m)ovies$", r"\1ovie"),
    (r"(s)eries$", r"\1eries"),
    (r"([^aeiouy]|qu)ies$", r"\1y"),
    (r"([lr])ves$", r"\1f"),
    (r"(tive)s$", r"\1"),
    (r"(hive)s$", r"\1"),
    (r"([^f])ves$", r"\1fe"),
    (r"(^analy)ses$", r"\1sis"),
    (r"((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", r"\1\2sis"),
    (r"([ti])a$", r"\1um"),
    (r"(n)ews$", r"\1ews"),
    (r"s$", r""),
]

IRREGULAR = [
    ("person", "people"),
    ("man", "men"),
    ("child", "children"),
    ("sex", "sexes"),
    ("move", "moves"),
    # ('cow', 'kine') WTF?
]

UNCOUNTABLES = [
    "equipment",
    "information",
    "rice",
    "money",
    "species",
    "series",
    "fish",
    "sheep",
    "billing",
]


[docs]class Util(object): """Various utility functions shipped with Vivial Connect Python API. """ @staticmethod
[docs] def pluralize(singular): """Convert singular word to its plural form. :param singular: A word in its singular form. :type singular: `str`. :returns: `str` -- the word in its plural form. """ if singular in UNCOUNTABLES: return singular for i in IRREGULAR: if i[0] == singular: return i[1] for i in PLURALIZE_PATTERNS: if re.search(i[0], singular): return re.sub(i[0], i[1], singular)
@staticmethod
[docs] def singularize(plural): """Convert plural word to its singular form. :param plural: A word in its plural form. :type plural: `str`. :returns: `str` -- the word in its singular form. """ if plural in UNCOUNTABLES: return plural for i in IRREGULAR: if i[1] == plural: return i[0] for i in SINGULARIZE_PATTERNS: if re.search(i[0], plural): return re.sub(i[0], i[1], plural) return plural
@staticmethod
[docs] def camelize(word): """Convert a word from lower_with_underscores to CamelCase. :param word: The string to convert. :type word: `str`. :returns: `str` -- the modified string. """ return "".join( w[0].upper() + w[1:] for w in re.sub("[^A-Z^a-z^0-9^:]+", " ", word).split(" ") )
@staticmethod
[docs] def underscore(word): """Convert a word from CamelCase to lower_with_underscores. :param word: The string to convert. :type word: `str`. :returns: `str` -- the modified string. """ return re.sub(r"\B((?<=[a-z])[A-Z]|[A-Z](?=[a-z]))", r"_\1", word).lower()
@staticmethod
[docs] def to_query(query_params): """Convert a dictionary to url query parameters. :param query_params: A dictionary of arguments. :type query_params: `dict`. :returns: `str` -- a string of query parameters. """ def annotate_params(params): annotated = {} for key, value in six.iteritems(params): if isinstance(value, list): key = "%s[]" % key elif isinstance(value, dict): dict_options = {} for dk, dv in six.iteritems(value): dict_options["%s[%s]" % (key, dk)] = dv annotated.update(annotate_params(dict_options)) continue elif isinstance(value, six.text_type): value = value.encode("utf-8") else: value = str(value) annotated[key] = value return annotated annotated = annotate_params(query_params) return urlencode(annotated, True)
@staticmethod
[docs] def to_json(obj, root="object"): """Convert a dictionary or list to an JSON string. :param obj: The object to serialize. :returns: `str` -- a JSON string. """ if root: obj = {root: obj} return json.dumps(obj, separators=(",", ":"))
@staticmethod
[docs] def json_to_dict(jsonstr): """Parse the json into a dictionary of attributes. :param jsonstr: A JSON formatted string. :type jsonstr: `str`. :returns: `str` -- the deserialized object. """ return json.loads(jsonstr)
@staticmethod
[docs] def remove_root(data): """Removes root key from dictionary. :param data: A dict to remove root key from. :type data: `dict`. :returns: `dict` -- a new dictionary without root key. """ if isinstance(data, dict) and len(data) == 1: return list(data.values())[0] return data