# Copyright (c) 2013 Mirantis, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import re import string import types import uuid import six from django.core import validators _LOCALIZABLE_KEYS = set(['label', 'help_text', 'error_messages']) class ObjectID(object): def __init__(self): self.object_id = str(uuid.uuid4()) def is_localizable(keys): return set(keys).intersection(_LOCALIZABLE_KEYS) def camelize(name): """Turns snake_case name into SnakeCase.""" return ''.join([bit.capitalize() for bit in name.split('_')]) def decamelize(name): """Turns CamelCase/camelCase name into camel_case.""" pat = re.compile(r'([A-Z]*[^A-Z]*)(.*)') bits = [] while True: head, tail = re.match(pat, name).groups() bits.append(head) if tail: name = tail else: break return '_'.join([bit.lower() for bit in bits]) def explode(_string): """Explodes a string into a list of one-character strings.""" if not _string or not isinstance(_string, six.string_types): return _string else: return list(_string) def prepare_regexp(regexp): """Converts regular expression string pattern into RegexValidator object. Also /regexp/flags syntax is allowed, where flags is a string of one-character flags that will be appended to the compiled regexp. """ if regexp.startswith('/'): groups = re.match(r'^/(.*)/([A-Za-z]*)$', regexp).groups() regexp, flags_str = groups flags = 0 for flag in explode(flags_str): flag = flag.upper() if hasattr(re, flag): flags |= getattr(re, flag) return validators.RegexValidator(re.compile(regexp, flags)) else: return validators.RegexValidator(re.compile(regexp)) def recursive_apply(predicate, transformer, value, *args): def rec(val): if predicate(val, *args): return rec(transformer(val, *args)) elif isinstance(val, dict): return dict((rec(k), rec(v)) for (k, v) in six.iteritems(val)) elif isinstance(val, list): return [rec(v) for v in val] elif isinstance(val, tuple): return tuple([rec(v) for v in val]) elif isinstance(val, types.GeneratorType): return rec(val) else: return val return rec(value) def evaluate(value, context): return recursive_apply( lambda v, _ctx: hasattr(v, 'evaluate'), lambda v, _ctx: v.evaluate(context=_ctx), value, context) def insert_hidden_ids(application): def wrap(k, v): if k == '?' and isinstance(v, dict) and not isinstance( v.get('id'), ObjectID): v['id'] = str(uuid.uuid4()) return k, v return rec(k), rec(v) def rec(val): if isinstance(val, dict): return dict(wrap(k, v) for k, v in six.iteritems(val)) elif isinstance(val, list): return [rec(v) for v in val] elif isinstance(val, ObjectID): return val.object_id else: return val return rec(application) def int2base(x, base): """Converts decimal integers to another number base from base-2 to base-36 :param x: decimal integer :param base: number base, max value is 36 :return: integer converted to the specified base """ digs = string.digits + string.ascii_lowercase if x < 0: sign = -1 elif x == 0: return '0' else: sign = 1 x *= sign digits = [] while x: digits.append(digs[x % base]) x //= base if sign < 0: digits.append('-') digits.reverse() return ''.join(digits) def to_str(text): if not isinstance(text, str): # unicode in python2 if isinstance(text, six.text_type): text = text.encode('utf-8') # bytes in python3 elif isinstance(text, six.binary_type): text = text.decode('utf-8') return text