import re
from datetime import datetime
from typing import Any, Optional, Sequence
__all__ = [
"format_with_config",
]
def dict_get(d: dict[str, Any], path_seq: Sequence[str]) -> Any:
"""Gets dictionary element of key path.
Examples:
.. code-block:: python
>>> config = {"hp": {"batch_size": 32, "lr": 1e-2}}
>>> dict_get(config, "hp.batch_size".split("."))
32
"""
for key in path_seq:
d = d[key]
return d
def dict_set(d: dict[str, Any], path_seq: Sequence[str], value: Any):
"""Sets dictionary element of key path with given value.
Examples:
.. code-block:: python
>>> config = {"hp": {"batch_size": 32, "lr": 1e-2}}
>>> dict_set(config, "hp.batch_size".split("."), 64)
>>> config["hp"]["batch_size"]
64
"""
for key in path_seq[:-1]:
d = d[key]
d[path_seq[-1]] = value
def encode_pair(left: str, right: str, rep: int, s: str) -> str:
"""Encodes a left/right pair using temporary characters."""
return (
s.replace("", "")
.replace(left, "\ufffe" * rep)
.replace(right, "\uffff" * rep)
)
def decode_pair(left: str, right: str, rep: int, s: str) -> str:
"""Decodes a left/right pair using temporary characters."""
return (
s.replace("", "")
.replace("\ufffe" * rep, left)
.replace("\uffff" * rep, right)
)
def _format_term(
term: str, config: dict[str, Any], now: datetime, silent: bool = False
) -> str:
"""Formats term using given config.
Examples:
.. code-block:: python
>>> from datetime import datetime
>>> date_string = "2020-01-01 00:00:03.141592"
>>> now = datetime.strptime(date_string, "%Y-%m-%d %H:%M:%S.%f")
>>> config = {"hp": {"batch_size": 32, "lr": 1e-2}}
>>> _format_term("{hp.batch_size:04}", config)
'0032'
>>> _format_term("{hp.lr:.1e}", config)
'1.0e-02'
>>> _format_term("{date:%Y-%m-%d_%H-%M-%S_%3f}", config, now=now)
'2020-01-01_00-00-03_141'
"""
if term == "":
return ""
key, *opt = term[1:-1].split(":", maxsplit=1)
if key == "date":
fmt = opt[0] if len(opt) != 0 else "%Y-%m-%d_%H-%M-%S_%3f"
return _strftime(fmt, now)
fmt = "{}" if len(opt) == 0 else f"{{:{opt[0]}}}"
try:
value = dict_get(config, key.split("."))
except KeyError as e:
if silent:
return term
raise e
return fmt.format(value)
def _strftime(fmt: str, dt: datetime) -> str:
"""Formats via strftime, but also supports width specifiers.
See more information `here <so>`_.
.. note:: `%%` specifier is not supported.
.. _so: https://stackoverflow.com/a/71715115/365102
Examples:
.. code-block:: python
>>> from datetime import datetime
>>> date_string = "2020-01-01 00:00:03.141592"
>>> dt = datetime.strptime(date_string, "%Y-%m-%d %H:%M:%S.%f")
>>> _strftime("%Y-%m-%d %H:%M:%S.%3f", dt)
'2020-01-01 00:00:03.141'
"""
tokens = fmt.split("%")
tokens[1:] = [_strftime_format_token(dt, x) for x in tokens[1:]]
return "".join(tokens)
def _strftime_format_token(dt: datetime, token: str) -> str:
if len(token) == 0:
return ""
if token[0].isnumeric():
width = int(token[0])
s = dt.strftime(f"%{token[1]}")[:width]
return f"{s}{token[2:]}"
return dt.strftime(f"%{token}")