aboutsummaryrefslogtreecommitdiff
path: root/src/utils/parse/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/parse/__init__.py')
-rw-r--r--src/utils/parse/__init__.py150
1 files changed, 150 insertions, 0 deletions
diff --git a/src/utils/parse/__init__.py b/src/utils/parse/__init__.py
new file mode 100644
index 00000000..bc3b8647
--- /dev/null
+++ b/src/utils/parse/__init__.py
@@ -0,0 +1,150 @@
+import decimal, io, typing
+from src.utils import datetime, errors
+
+from .time import duration
+from .spec import *
+
+COMMENT_TYPES = ["#", "//"]
+def hashflags(filename: str
+ ) -> typing.List[typing.Tuple[str, typing.Optional[str]]]:
+ hashflags = [] # type: typing.List[typing.Tuple[str, typing.Optional[str]]]
+ with io.open(filename, mode="r", encoding="utf8") as f:
+ for line in f:
+ line = line.strip("\n")
+ found = False
+ for comment_type in COMMENT_TYPES:
+ if line.startswith(comment_type):
+ line = line.replace(comment_type, "", 1).lstrip()
+ found = True
+ break
+
+ if not found:
+ break
+ elif line.startswith("--"):
+ hashflag, sep, value = line[2:].partition(" ")
+ hashflags.append((hashflag, (value if sep else None)))
+ return hashflags
+
+class Docstring(object):
+ def __init__(self, description: str, items: typing.Dict[str, str],
+ var_items: typing.Dict[str, typing.List[str]]):
+ self.description = description
+ self.items = items
+ self.var_items = var_items
+
+def docstring(s: str) -> Docstring:
+ description = ""
+ last_item = None
+ last_item_no_space = False
+ items = {} # type: typing.Dict[str, str]
+ var_items = {} # type: typing.Dict[str, typing.List[str]]
+ if s:
+ for line in s.split("\n"):
+ line = line.strip()
+
+ if line:
+ if line[0] == ":":
+ key, _, value = line[1:].partition(": ")
+ last_item = key.lstrip("-")
+ last_item_no_space = key.startswith("-")
+
+ if key in var_items:
+ var_items[last_item].append(value)
+ elif key in items:
+ var_items[last_item] = [items.pop(last_item), value]
+ else:
+ items[last_item] = value
+ else:
+ if last_item:
+ if last_item_no_space:
+ items[last_item] += line
+ else:
+ items[last_item] += " %s" % line
+ else:
+ if description:
+ description += " "
+ description += line
+ return Docstring(description, items, var_items)
+
+def keyvalue(s: str, delimiter: str=" "
+ ) -> typing.Dict[str, typing.Optional[str]]:
+ items = {} # type: typing.Dict[str, typing.Optional[str]]
+ pairs = s.split(delimiter)
+ for pair in filter(None, pairs):
+ key, sep, value = pair.partition("=")
+ if sep:
+ items[key] = value
+ else:
+ items[key] = None
+ return items
+
+def try_int(s: str) -> typing.Optional[int]:
+ try:
+ return int(s)
+ except ValueError:
+ return None
+
+def line_normalise(s: str) -> str:
+ lines = list(filter(None, [line.strip() for line in s.split("\n")]))
+ return " ".join(line.replace(" ", " ") for line in lines)
+
+def parse_number(s: str) -> str:
+ try:
+ decimal.Decimal(s)
+ return s
+ except:
+ pass
+
+ unit = s[-1].lower()
+ number_str = s[:-1]
+ try:
+ number = decimal.Decimal(number_str)
+ except:
+ raise ValueError("Invalid format '%s' passed to parse_number" %
+ number_str)
+
+ if unit == "k":
+ number *= decimal.Decimal("1_000")
+ elif unit == "m":
+ number *= decimal.Decimal("1_000_000")
+ elif unit == "b":
+ number *= decimal.Decimal("1_000_000_000")
+ else:
+ raise ValueError("Unknown unit '%s' given to parse_number" % unit)
+ return str(number)
+
+def format_tokens(s: str, names: typing.List[str], sigil: str="$"
+ ) -> typing.List[typing.Tuple[int, str]]:
+ names = names.copy()
+ names.sort()
+ names.reverse()
+
+ i = 0
+ max = len(s)-1
+ sigil_found = False
+ tokens: typing.List[typing.Tuple[int, str]] = []
+
+ while i < max:
+ if s[i] == sigil:
+ i += 1
+ if not s[i] == sigil:
+ for name in names:
+ if len(name) <= (len(s)-i) and s[i:i+len(name)] == name:
+ tokens.append((i-1, "%s%s" % (sigil, name)))
+ i += len(name)
+ break
+ else:
+ tokens.append((i-1, "$$"))
+ i += 1
+ return tokens
+
+def format_token_replace(s: str, vars: typing.Dict[str, str],
+ sigil: str="$") -> str:
+ vars = vars.copy()
+ vars.update({sigil: sigil})
+ tokens = format_tokens(s, list(vars.keys()), sigil)
+ tokens.sort(key=lambda x: x[0])
+ tokens.reverse()
+ for i, token in tokens:
+ s = s[:i] + vars[token.replace(sigil, "", 1)] + s[i+len(token):]
+ return s