jumeaux/utils.py
# -*- coding:utf-8 -*-
import ast
import math
import re
from datetime import datetime, timedelta
from typing import Any
import pydash as py_
from jinja2 import BaseLoader, Environment
from jinja2.exceptions import TemplateSyntaxError
from owlmixin import TOption
from tzlocal import get_localzone
LOCAL_ZONE = get_localzone()
def exact_match(target: str, regexp: str) -> bool:
return bool(re.search(f"^({regexp})$", target))
def now():
return datetime.now(LOCAL_ZONE)
def mill_seconds_until(from_: datetime) -> float:
dt = now() - from_
return dt.seconds * 1000 + dt.microseconds / 1000
def to_jumeaux_xpath(xpath: str):
return xpath.replace("[", "<").replace("]", ">")
def get_by_diff_key(dic: dict, diff_key: str) -> Any:
return py_.get(
dic,
diff_key.replace("root", "")
.replace("><", ".")
.replace(">", "")
.replace("<", "")
.replace("'", ""),
)
def calc_distance_km(
wgs84_deg_lat1: float,
wgs84_deg_lon1: float,
wgs84_deg_lat2: float,
wgs84_deg_lon2: float,
) -> float:
R = 6371
rad1 = math.radians(wgs84_deg_lat1)
rad2 = math.radians(wgs84_deg_lat2)
delta_lat_rad = math.radians(wgs84_deg_lat2 - wgs84_deg_lat1)
delta_lon_rad = math.radians(wgs84_deg_lon2 - wgs84_deg_lon1)
a = math.sin(delta_lat_rad / 2) * math.sin(delta_lat_rad / 2) + math.cos(
rad1
) * math.cos(rad2) * math.sin(delta_lon_rad / 2) * math.sin(delta_lon_rad / 2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
return R * c
def equals_without_host(one: str, other: str) -> bool:
pattern = "https?://[^$/]+"
return re.sub(pattern, "", one) == re.sub(pattern, "", other)
ENV = Environment(loader=BaseLoader())
ENV.filters["reg"] = exact_match
ENV.globals["calc_distance_km"] = calc_distance_km
ENV.globals["equals_without_host"] = equals_without_host
def when_filter(when: str, data: dict) -> bool:
return ast.literal_eval(ENV.from_string("{{" + when + "}}").render(data))
def when_optional_filter(when: TOption[str], data: dict) -> bool:
return when.map(lambda x: when_filter(x, data)).get_or(True)
def jinja2_format(fmt: str, data: dict) -> str:
return ENV.from_string(fmt).render(data)
def get_jinja2_format_error(fmt: str) -> TOption[str]:
try:
ENV.from_string(fmt)
return TOption(None)
except TemplateSyntaxError as err:
return TOption(err.message)
def parse_datetime_dsl(value: str):
m = re.search(r"^\$DATETIME\((.+)\)\((.+)\)$", value)
return (now() + timedelta(seconds=int(m[2]))).strftime(m[1]) if m else value