240 lines
5.4 KiB
Python
240 lines
5.4 KiB
Python
import importlib
|
|
import inspect
|
|
import pkgutil
|
|
|
|
from core.tokenizer import TokenKind
|
|
|
|
|
|
def sysarg_to_string(argv):
|
|
"""
|
|
Transform a list of strings into a single string
|
|
Add quotes if needed
|
|
:return:
|
|
"""
|
|
if argv is None or not argv:
|
|
return ""
|
|
|
|
result = ""
|
|
first = True
|
|
for s in argv:
|
|
if not first:
|
|
result += " "
|
|
|
|
result += '"' + s + '"' if " " in s else s
|
|
first = False
|
|
|
|
if result[0] in ('"', "'"):
|
|
result = result[1:-1] # strip quotes
|
|
return result
|
|
|
|
|
|
def get_class(qname):
|
|
"""
|
|
Loads a class from its full qualified name
|
|
:param qname:
|
|
:return:
|
|
"""
|
|
parts = qname.split('.')
|
|
module = ".".join(parts[:-1])
|
|
m = __import__(module)
|
|
for comp in parts[1:]:
|
|
m = getattr(m, comp)
|
|
return m
|
|
|
|
|
|
def get_module(qname):
|
|
"""
|
|
Loads a module from its full qualified name
|
|
:param qname:
|
|
:return:
|
|
"""
|
|
parts = qname.split('.')
|
|
m = __import__(qname)
|
|
for comp in parts[1:]:
|
|
m = getattr(m, comp)
|
|
return m
|
|
|
|
|
|
def new_object(kls, *args, **kwargs):
|
|
"""
|
|
New instance of an object
|
|
:param kls:
|
|
:param args:
|
|
:param kwargs:
|
|
:return:
|
|
"""
|
|
obj_type = get_class(kls)
|
|
return obj_type(*args, **kwargs)
|
|
|
|
|
|
def get_full_qualified_name(obj):
|
|
"""
|
|
Returns the full qualified name of a class (including its module name )
|
|
:param obj:
|
|
:return:
|
|
"""
|
|
if obj.__class__ == type:
|
|
module = obj.__module__
|
|
if module is None or module == str.__class__.__module__:
|
|
return obj.__name__ # Avoid reporting __builtin__
|
|
else:
|
|
return module + '.' + obj.__name__
|
|
else:
|
|
module = obj.__class__.__module__
|
|
if module is None or module == str.__class__.__module__:
|
|
return obj.__class__.__name__ # Avoid reporting __builtin__
|
|
else:
|
|
return module + '.' + obj.__class__.__name__
|
|
|
|
|
|
def get_classes(module_name):
|
|
"""
|
|
Gets all classes, for a given module_name
|
|
:param module_name: name of the module
|
|
:return:
|
|
"""
|
|
mod = get_module(module_name)
|
|
for name in dir(mod):
|
|
obj = getattr(mod, name)
|
|
if inspect.isclass(obj):
|
|
yield obj
|
|
|
|
|
|
def get_classes_from_package(package_name):
|
|
"""
|
|
Gets all classes, for a given package
|
|
:param package_name: name of the package
|
|
:return:
|
|
"""
|
|
pkg = __import__(package_name)
|
|
prefix = pkg.__name__ + "."
|
|
for importer, modname, ispkg in pkgutil.iter_modules(pkg.__path__, prefix):
|
|
for c in get_classes(modname):
|
|
yield c
|
|
|
|
|
|
def init_package_import(package_name):
|
|
pkg = __import__(package_name)
|
|
prefix = pkg.__name__ + "."
|
|
for (module_loader, name, ispkg) in pkgutil.iter_modules(pkg.__path__, prefix):
|
|
importlib.import_module(name)
|
|
|
|
|
|
def get_sub_classes(package_name, base_class):
|
|
base_class = get_class(base_class) if isinstance(base_class, str) else base_class
|
|
all_class = set(base_class.__subclasses__()).union(
|
|
[s for c in base_class.__subclasses__() for s in get_sub_classes(package_name, c)])
|
|
|
|
# limit to the classes of the package
|
|
return [c for c in all_class if c.__module__.startswith(package_name)]
|
|
|
|
|
|
def remove_from_list(lst, to_remove_predicate):
|
|
"""
|
|
Removes elements from a list if they exist
|
|
:param lst:
|
|
:param to_remove_predicate:
|
|
:return:
|
|
"""
|
|
|
|
flagged = []
|
|
for item in lst:
|
|
if to_remove_predicate(item):
|
|
flagged.append(item)
|
|
|
|
for item in flagged:
|
|
lst.remove(item)
|
|
|
|
return lst
|
|
|
|
|
|
def remove_list_from_list(lst, to_remove):
|
|
# https://stackoverflow.com/questions/2514961/remove-all-values-within-one-list-from-another-list/30353802
|
|
# explains that list comprehension is not the best approach
|
|
for item in to_remove:
|
|
try:
|
|
lst.remove(item)
|
|
except ValueError:
|
|
pass
|
|
return lst
|
|
|
|
|
|
def product(a, b):
|
|
"""
|
|
Kind of cartesian product between lists a and b
|
|
knowing that a is also a list
|
|
|
|
So it's a cartesian product between a list of list and a list
|
|
"""
|
|
|
|
if a is None or len(a) == 0:
|
|
return b
|
|
if b is None or len(b) == 0:
|
|
return a
|
|
|
|
res = []
|
|
for item_b in b:
|
|
for item_a in a:
|
|
items = item_a + [item_b]
|
|
res.append(items)
|
|
|
|
return res
|
|
|
|
|
|
def strip_quotes(text):
|
|
if not isinstance(text, str):
|
|
return text
|
|
|
|
if text == "":
|
|
return ""
|
|
|
|
if text[0] == "'" or text[0] == '"':
|
|
return text[1:-1]
|
|
|
|
return text
|
|
|
|
|
|
def strip_tokens(tokens, strip_eof=False):
|
|
"""
|
|
Remove the starting and trailing spaces and newline
|
|
"""
|
|
if tokens is None:
|
|
return None
|
|
|
|
start = 0
|
|
length = len(tokens)
|
|
while start < length and tokens[start].type in (TokenKind.WHITESPACE, TokenKind.NEWLINE):
|
|
start += 1
|
|
|
|
if start == length:
|
|
return []
|
|
|
|
end_tokens = (TokenKind.WHITESPACE, TokenKind.NEWLINE, TokenKind.EOF) \
|
|
if strip_eof \
|
|
else (TokenKind.WHITESPACE, TokenKind.NEWLINE)
|
|
|
|
end = length - 1
|
|
while end > 0 and tokens[end].type in end_tokens:
|
|
end -= 1
|
|
|
|
return tokens[start: end + 1]
|
|
|
|
|
|
def escape_char(text, to_escape):
|
|
res = ""
|
|
|
|
for c in text:
|
|
res += ("\\" + c) if c in to_escape else c
|
|
|
|
return res
|
|
|
|
|
|
def pp(items):
|
|
if not hasattr(items, "__iter__"):
|
|
return str(items)
|
|
|
|
if len(items) == 0:
|
|
return str(items)
|
|
|
|
return " \n" + " \n".join(str(item) for item in items)
|