OpenSlides/server/openslides/utils/utils.py

139 lines
3.9 KiB
Python
Raw Normal View History

2019-05-06 13:00:40 +02:00
import random
import re
2019-05-06 13:00:40 +02:00
import string
2019-10-18 14:18:49 +02:00
from typing import Any, Dict, Generator, Optional, Tuple, Type, Union
2011-09-02 20:46:24 +02:00
import roman
from django.apps import apps
from django.db.models import Model
2012-02-09 02:29:38 +01:00
2019-01-06 16:22:33 +01:00
CAMEL_CASE_TO_PSEUDO_SNAKE_CASE_CONVERSION_REGEX_1 = re.compile("(.)([A-Z][a-z]+)")
CAMEL_CASE_TO_PSEUDO_SNAKE_CASE_CONVERSION_REGEX_2 = re.compile("([a-z0-9])([A-Z])")
2017-08-24 12:26:55 +02:00
def convert_camel_case_to_pseudo_snake_case(text: str) -> str:
"""
Converts camel case to pseudo snake case using hyphen instead of
underscore.
E. g. ThisText is converted to this-text.
Credits: epost (http://stackoverflow.com/a/1176023)
"""
2019-01-06 16:22:33 +01:00
s1 = CAMEL_CASE_TO_PSEUDO_SNAKE_CASE_CONVERSION_REGEX_1.sub(r"\1-\2", text)
return CAMEL_CASE_TO_PSEUDO_SNAKE_CASE_CONVERSION_REGEX_2.sub(r"\1-\2", s1).lower()
2017-08-24 12:26:55 +02:00
def to_roman(number: int) -> str:
2014-04-27 21:01:23 +02:00
"""
2015-09-16 00:55:27 +02:00
Converts an arabic number within range from 1 to 4999 to the
2017-08-24 12:26:55 +02:00
corresponding roman number. Returns the input converted as string on error
conditions or higher numbers.
2014-04-27 21:01:23 +02:00
"""
try:
return roman.toRoman(number)
except (roman.NotIntegerError, roman.OutOfRangeError):
2017-08-24 12:26:55 +02:00
return str(number)
def get_element_id(collection_string: str, id: int) -> str:
"""
Returns a combined string from the collection_string and an id.
"""
2019-01-12 23:01:42 +01:00
return f"{collection_string}:{id}"
def split_element_id(element_id: Union[str, bytes]) -> Tuple[str, int]:
"""
Splits a combined element_id into the collection_string and the id.
"""
if isinstance(element_id, bytes):
element_id = element_id.decode()
collection_str, id = element_id.rsplit(":", 1)
return (collection_str, int(id))
def str_dict_to_bytes(str_dict: Dict[str, str]) -> Dict[bytes, bytes]:
"""
Converts the key and the value of a dict from str to bytes.
"""
out = {}
for key, value in str_dict.items():
out[key.encode()] = value.encode()
return out
2019-10-18 14:18:49 +02:00
def is_int(obj: Any) -> bool:
try:
int(obj)
return True
except (ValueError, TypeError):
return False
def is_iterable(obj: Any) -> bool:
"""
Do not rely on `isinstance(obj, Iterable` with `Iterable` being imperted
from typing. This breaks at proxyobjects, like SimpleLazyObjects from Django.
Instead try to get the iterable from the object. THis fails on non-iterable
proxyobjects.
"""
try:
iter(obj)
return True
except TypeError:
return False
_models_to_collection_string: Dict[str, Type[Model]] = {}
def get_model_from_collection_string(collection_string: str) -> Type[Model]:
"""
Returns a model class which belongs to the argument collection_string.
"""
2019-01-06 16:22:33 +01:00
def model_generator() -> Generator[Type[Model], None, None]:
"""
Yields all models of all apps.
"""
for app_config in apps.get_app_configs():
for model in app_config.get_models():
yield model
# On the first run, generate the dict. It can not change at runtime.
if not _models_to_collection_string:
for model in model_generator():
try:
get_collection_string = model.get_collection_string
except AttributeError:
# Skip models which do not have the method get_collection_string.
pass
else:
_models_to_collection_string[get_collection_string()] = model
try:
model = _models_to_collection_string[collection_string]
except KeyError:
2019-01-06 16:22:33 +01:00
raise ValueError(
2019-01-12 23:01:42 +01:00
f"Invalid message. A valid collection_string is missing. Got {collection_string}"
2019-01-06 16:22:33 +01:00
)
return model
2019-05-06 13:00:40 +02:00
_worker_id: Optional[str] = None
"""
The worker id. Accessable via `get_worker_id()`.
"""
def get_worker_id() -> str:
"""
Returns a random string of length 4 that identifies this
instance of this worker
"""
global _worker_id
if _worker_id is None:
_worker_id = "".join(random.sample(string.ascii_letters, 4))
return _worker_id