"""General utilities."""
import datetime
import hashlib
import os
from string import Template
from typing import Any
[docs]
class TemplateStore:
"""
Collection of string templates with substitution capabilities.
Parameters
----------
templates : dict[str, str | Template]
Dictionary of templates.
substitutes : dict[str, str]
Dictionary of substitution values.
substitute_timestamp : bool
Whether to automatically substitute the current timestamp.
substitute_pid : bool
Whether to automatically substitute the current process ID.
"""
templates: dict[str, Template]
substitutes: dict[str, str]
def __init__(
self,
templates: dict[str, str | Template] | None = None,
substitutes: dict[str, str] | None = None,
substitute_timestamp: bool = True,
substitute_pid: bool = True,
) -> None:
self.templates = {}
if templates is not None:
d: dict[str, Template] = {}
for key, value in templates.items():
if isinstance(value, Template):
d[key] = value
else:
d[key] = Template(value)
self.templates = d
if substitutes is None:
self.substitutes = {}
else:
self.substitutes = substitutes
self.substitute_timestamp = substitute_timestamp
self.substitute_pid = substitute_pid
def __copy__(self) -> "TemplateStore":
"""
Create a copy of the TemplateStore.
Returns
-------
TemplateStore
A copy of the current TemplateStore.
"""
templates_copy: dict[str, str | Template] = {}
for key, value in self.templates.items():
templates_copy[key] = Template(value.template)
return TemplateStore(
templates=templates_copy,
substitutes=self.substitutes.copy(),
substitute_timestamp=self.substitute_timestamp,
substitute_pid=self.substitute_pid,
)
def __getitem__(self, template_name: str) -> str:
"""
Get the template string with substitutions applied.
Parameters
----------
template_name : str
Name of the template to retrieve.
Returns
-------
str
The template string with substitutions applied.
"""
delete_timestamp = False
if self.substitute_timestamp and ("timestamp" not in self.substitutes):
self.substitutes["timestamp"] = datetime.datetime.now().strftime("%Y-%m-%dT%H-%M-%S")
delete_timestamp = True
delete_pid = False
if self.substitute_pid and ("pid" not in self.substitutes):
self.substitutes["pid"] = str(os.getpid())
delete_pid = True
substituted_str = self.templates[template_name].substitute(self.substitutes)
if delete_timestamp:
del self.substitutes["timestamp"]
if delete_pid:
del self.substitutes["pid"]
return substituted_str
[docs]
def complete(self, template_name: str) -> str:
"""
Complete the template by performing substitutions.
Parameters
----------
template_name : str
Name of the template to complete.
Returns
-------
str
The completed template string.
"""
template_str = self[template_name]
# ToDo: template.get_identifiers() is available in Python 3.11
if "$" in template_str:
raise ValueError("Template not completely substituted.")
return template_str
def __contains__(self, key: str) -> bool:
"""
Check if a template exists.
Parameters
----------
key : str
Name of the template.
Returns
-------
bool
True if the template exists, False otherwise.
"""
return key in self.templates
[docs]
def add(self, key: str, value: str | Template) -> None:
"""
Add a new template.
Parameters
----------
key : str
Name of the template.
value : str | Template
The template string or Template object.
"""
if not isinstance(value, Template):
self.templates[key] = Template(value)
else:
self.templates[key] = value
[docs]
def add_substitutes(self, **kwargs: str) -> None:
r"""
Add new substitution values.
Parameters
----------
\*\*kwargs : dict[str, str]
Key-value pairs for substitution.
"""
for key, value in kwargs.items():
self.substitutes[key] = value
[docs]
def unique_hex_digest(unique_elements: Any, length: int = 8) -> str:
"""
Generate a unique hexadecimal digest based on the input elements.
Parameters
----------
unique_elements : Any
The elements to generate a unique digest for. They must have a unique string representation.
length : int
The length of the hexadecimal digest truncation to return.
Returns
-------
str
A hexadecimal digest string of the specified length.
"""
return hashlib.sha256(str(unique_elements).encode()).hexdigest()[0:length]