You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
3.7 KiB
140 lines
3.7 KiB
from collections import OrderedDict
|
|
from collections.abc import MutableMapping, Mapping
|
|
import uuid
|
|
|
|
lower_alp = 'abcdefghijklmnopqrstuvwxyz'
|
|
upper_alp = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
|
nums = '0123456789'
|
|
base62alp = nums + lower_alp + upper_alp
|
|
|
|
reserved_monet = ['month']
|
|
|
|
|
|
class CaseInsensitiveDict(MutableMapping):
|
|
def __init__(self, data=None, **kwargs):
|
|
self._store = OrderedDict()
|
|
if data is None:
|
|
data = {}
|
|
self.update(data, **kwargs)
|
|
|
|
def __setitem__(self, key, value):
|
|
# Use the lowercased key for lookups, but store the actual
|
|
# key alongside the value.
|
|
self._store[key.lower()] = (key, value)
|
|
|
|
def __getitem__(self, key):
|
|
return self._store[key.lower()][1]
|
|
|
|
def __delitem__(self, key):
|
|
del self._store[key.lower()]
|
|
|
|
def __iter__(self):
|
|
return (casedkey for casedkey, mappedvalue in self._store.values())
|
|
|
|
def __len__(self):
|
|
return len(self._store)
|
|
|
|
def lower_items(self):
|
|
"""Like iteritems(), but with all lowercase keys."""
|
|
return ((lowerkey, keyval[1]) for (lowerkey, keyval) in self._store.items())
|
|
|
|
def __eq__(self, other):
|
|
if isinstance(other, Mapping):
|
|
other = CaseInsensitiveDict(other)
|
|
else:
|
|
return NotImplemented
|
|
# Compare insensitively
|
|
return dict(self.lower_items()) == dict(other.lower_items())
|
|
|
|
# Copy is required
|
|
def copy(self):
|
|
return CaseInsensitiveDict(self._store.values())
|
|
|
|
def __repr__(self):
|
|
return str(dict(self.items()))
|
|
|
|
def base62uuid(crop=8):
|
|
_id = uuid.uuid4().int
|
|
ret = ''
|
|
|
|
while _id:
|
|
ret = base62alp[_id % 62] + ret
|
|
_id //= 62
|
|
|
|
return ret[:crop] if len(ret) else '0'
|
|
|
|
def get_legal_name(name, lower = True):
|
|
if name is not None:
|
|
if lower:
|
|
name = name.lower()
|
|
name = ''.join([n for n in name if n in base62alp or n == '_'])
|
|
|
|
if name is None or len(name) == 0 or set(name) == set('_'):
|
|
name = base62uuid(8)
|
|
if(name[0] in nums):
|
|
name = '_' + name
|
|
|
|
return name
|
|
|
|
def check_legal_name(name):
|
|
all_underscores = True
|
|
for c in name:
|
|
if c not in base62alp and c != '_':
|
|
return False
|
|
if c != '_':
|
|
all_underscores = False
|
|
if all_underscores:
|
|
return False
|
|
if name[0] in nums:
|
|
return False
|
|
|
|
return True
|
|
|
|
def enlist(l):
|
|
return l if type(l) is list else [l]
|
|
|
|
def seps(s, i, l):
|
|
return s if i < len(l) - 1 else ''
|
|
|
|
def has_other(a, b):
|
|
for ai in a:
|
|
if ai not in b:
|
|
return True
|
|
return False
|
|
|
|
def defval(val, default):
|
|
return default if val is None else val
|
|
|
|
# escape must be readonly
|
|
from typing import Mapping, Set
|
|
def remove_last(pattern : str, string : str, escape : Set[str] = set()) -> str:
|
|
idx = string.rfind(pattern)
|
|
if idx == -1:
|
|
return string
|
|
else:
|
|
if set(string[idx:]).difference(escape):
|
|
return string
|
|
else:
|
|
return string[:idx] + string[idx+1:]
|
|
|
|
class _Counter:
|
|
def __init__(self, cnt):
|
|
self.cnt = cnt
|
|
def inc(self, cnt = 1):
|
|
self.cnt += cnt
|
|
cnt = self.cnt - cnt
|
|
return cnt
|
|
|
|
import re
|
|
ws = re.compile(r'\s+')
|
|
import os
|
|
|
|
def add_dll_dir(dll: str):
|
|
import sys
|
|
if sys.version_info.major >= 3 and sys.version_info.minor >7 and os.name == 'nt':
|
|
os.add_dll_directory(dll)
|
|
else:
|
|
os.environ['PATH'] = os.path.abspath(dll) + os.pathsep + os.environ['PATH']
|
|
|
|
nullstream = open(os.devnull, 'w')
|