sqlmesh.utils
1from __future__ import annotations 2 3import importlib 4import re 5import sys 6import traceback 7import types 8import typing as t 9import uuid 10from contextlib import contextmanager 11from functools import wraps 12from pathlib import Path 13 14T = t.TypeVar("T") 15KEY = t.TypeVar("KEY", bound=t.Hashable) 16VALUE = t.TypeVar("VALUE") 17DECORATOR_RETURN_TYPE = t.TypeVar("DECORATOR_RETURN_TYPE") 18 19 20def optional_import(name: str) -> t.Optional[types.ModuleType]: 21 """Optionally import a module. 22 23 Args: 24 name: The name of the module to import. 25 Returns: 26 The module if it is installed. 27 """ 28 try: 29 module = importlib.import_module(name) 30 except ImportError: 31 return None 32 return module 33 34 35def unique(iterable: t.Iterable[T], by: t.Callable[[T], t.Any] = lambda i: i) -> t.List[T]: 36 return list({by(i): None for i in iterable}) 37 38 39def random_id() -> str: 40 return uuid.uuid4().hex 41 42 43class UniqueKeyDict(dict, t.Mapping[KEY, VALUE]): 44 """Dict that raises when a duplicate key is set.""" 45 46 def __init__(self, name: str, *args: t.Dict[KEY, VALUE], **kwargs: VALUE) -> None: 47 self.name = name 48 super().__init__(*args, **kwargs) 49 50 def __setitem__(self, k: KEY, v: VALUE) -> None: 51 if k in self: 52 raise ValueError( 53 f"Duplicate key '{k}' found in UniqueKeyDict<{self.name}>. Call dict.update(...) if this is intentional." 54 ) 55 super().__setitem__(k, v) 56 57 58class AttributeDict(dict, t.Mapping[KEY, VALUE]): 59 __getattr__ = dict.get 60 61 62class registry_decorator: 63 """A decorator that registers itself.""" 64 65 registry_name = "" 66 _registry: t.Optional[UniqueKeyDict] = None 67 68 @classmethod 69 def registry(cls) -> UniqueKeyDict: 70 if cls._registry is None: 71 cls._registry = UniqueKeyDict(cls.registry_name) 72 return cls._registry 73 74 def __init__(self, name: str = "") -> None: 75 self.name = name 76 77 def __call__( 78 self, func: t.Callable[..., DECORATOR_RETURN_TYPE] 79 ) -> t.Callable[..., DECORATOR_RETURN_TYPE]: 80 self.func = func 81 self.registry()[(self.name or func.__name__)] = self 82 83 @wraps(func) 84 def wrapper(*args: t.Any, **kwargs: t.Any) -> DECORATOR_RETURN_TYPE: 85 return func(*args, **kwargs) 86 87 return wrapper 88 89 @classmethod 90 def get_registry(cls) -> UniqueKeyDict: 91 """Get a copy of the registry""" 92 return UniqueKeyDict(cls.registry_name, **(cls._registry or {})) 93 94 @classmethod 95 def set_registry(cls, registry: UniqueKeyDict) -> None: 96 """Set the registry.""" 97 cls._registry = registry 98 99 100@contextmanager 101def sys_path(path: Path) -> t.Generator[None, None, None]: 102 """A context manager to temporarily add a path to 'sys.path'.""" 103 path_str = str(path.absolute()) 104 105 if path_str in sys.path: 106 inserted = False 107 else: 108 sys.path.insert(0, path_str) 109 inserted = True 110 111 try: 112 yield 113 finally: 114 if inserted: 115 sys.path.remove(path_str) 116 117 118def format_exception(exception: BaseException) -> t.List[str]: 119 if sys.version_info < (3, 10): 120 return traceback.format_exception( 121 type(exception), exception, exception.__traceback__ 122 ) # type: ignore 123 else: 124 return traceback.format_exception(exception) # type: ignore 125 126 127def word_characters_only(s: str, replacement_char: str = "_") -> str: 128 """ 129 Replace all non-word characters in string with the replacement character. 130 Reference SO: https://stackoverflow.com/questions/1276764/stripping-everything-but-alphanumeric-chars-from-a-string-in-python/70310018#70310018 131 132 >>> word_characters_only("Hello, world!") 133 'Hello__world_' 134 >>> word_characters_only("Hello, world! 123", '') 135 'Helloworld123' 136 """ 137 return re.sub(r"\W", replacement_char, s) 138 139 140def double_escape(s: str) -> str: 141 """ 142 Replace backslashes with another backslash. 143 """ 144 return s.replace("\\", "\\\\") 145 146 147def nullsafe_join(join_char: str, *args: t.Optional[str]) -> str: 148 return join_char.join(filter(None, args))
def
optional_import(name: str) -> Optional[module]:
21def optional_import(name: str) -> t.Optional[types.ModuleType]: 22 """Optionally import a module. 23 24 Args: 25 name: The name of the module to import. 26 Returns: 27 The module if it is installed. 28 """ 29 try: 30 module = importlib.import_module(name) 31 except ImportError: 32 return None 33 return module
Optionally import a module.
Arguments:
- name: The name of the module to import.
Returns:
The module if it is installed.
def
unique( iterable: Iterable[~T], by: Callable[[~T], Any] = <function <lambda>>) -> List[~T]:
def
random_id() -> str:
class
UniqueKeyDict(builtins.dict, typing.Mapping[~KEY, ~VALUE]):
44class UniqueKeyDict(dict, t.Mapping[KEY, VALUE]): 45 """Dict that raises when a duplicate key is set.""" 46 47 def __init__(self, name: str, *args: t.Dict[KEY, VALUE], **kwargs: VALUE) -> None: 48 self.name = name 49 super().__init__(*args, **kwargs) 50 51 def __setitem__(self, k: KEY, v: VALUE) -> None: 52 if k in self: 53 raise ValueError( 54 f"Duplicate key '{k}' found in UniqueKeyDict<{self.name}>. Call dict.update(...) if this is intentional." 55 ) 56 super().__setitem__(k, v)
Dict that raises when a duplicate key is set.
Inherited Members
- builtins.dict
- get
- setdefault
- pop
- popitem
- keys
- items
- values
- update
- fromkeys
- clear
- copy
class
AttributeDict(builtins.dict, typing.Mapping[~KEY, ~VALUE]):
Inherited Members
- builtins.dict
- get
- setdefault
- pop
- popitem
- keys
- items
- values
- update
- fromkeys
- clear
- copy
class
registry_decorator:
63class registry_decorator: 64 """A decorator that registers itself.""" 65 66 registry_name = "" 67 _registry: t.Optional[UniqueKeyDict] = None 68 69 @classmethod 70 def registry(cls) -> UniqueKeyDict: 71 if cls._registry is None: 72 cls._registry = UniqueKeyDict(cls.registry_name) 73 return cls._registry 74 75 def __init__(self, name: str = "") -> None: 76 self.name = name 77 78 def __call__( 79 self, func: t.Callable[..., DECORATOR_RETURN_TYPE] 80 ) -> t.Callable[..., DECORATOR_RETURN_TYPE]: 81 self.func = func 82 self.registry()[(self.name or func.__name__)] = self 83 84 @wraps(func) 85 def wrapper(*args: t.Any, **kwargs: t.Any) -> DECORATOR_RETURN_TYPE: 86 return func(*args, **kwargs) 87 88 return wrapper 89 90 @classmethod 91 def get_registry(cls) -> UniqueKeyDict: 92 """Get a copy of the registry""" 93 return UniqueKeyDict(cls.registry_name, **(cls._registry or {})) 94 95 @classmethod 96 def set_registry(cls, registry: UniqueKeyDict) -> None: 97 """Set the registry.""" 98 cls._registry = registry
A decorator that registers itself.
90 @classmethod 91 def get_registry(cls) -> UniqueKeyDict: 92 """Get a copy of the registry""" 93 return UniqueKeyDict(cls.registry_name, **(cls._registry or {}))
Get a copy of the registry
@contextmanager
def
sys_path(path: pathlib.Path) -> Generator[NoneType, NoneType, NoneType]:
101@contextmanager 102def sys_path(path: Path) -> t.Generator[None, None, None]: 103 """A context manager to temporarily add a path to 'sys.path'.""" 104 path_str = str(path.absolute()) 105 106 if path_str in sys.path: 107 inserted = False 108 else: 109 sys.path.insert(0, path_str) 110 inserted = True 111 112 try: 113 yield 114 finally: 115 if inserted: 116 sys.path.remove(path_str)
A context manager to temporarily add a path to 'sys.path'.
def
format_exception(exception: BaseException) -> List[str]:
def
word_characters_only(s: str, replacement_char: str = '_') -> str:
128def word_characters_only(s: str, replacement_char: str = "_") -> str: 129 """ 130 Replace all non-word characters in string with the replacement character. 131 Reference SO: https://stackoverflow.com/questions/1276764/stripping-everything-but-alphanumeric-chars-from-a-string-in-python/70310018#70310018 132 133 >>> word_characters_only("Hello, world!") 134 'Hello__world_' 135 >>> word_characters_only("Hello, world! 123", '') 136 'Helloworld123' 137 """ 138 return re.sub(r"\W", replacement_char, s)
Replace all non-word characters in string with the replacement character. Reference SO: https://stackoverflow.com/questions/1276764/stripping-everything-but-alphanumeric-chars-from-a-string-in-python/70310018#70310018
>>> word_characters_only("Hello, world!")
'Hello__world_'
>>> word_characters_only("Hello, world! 123", '')
'Helloworld123'
def
double_escape(s: str) -> str:
141def double_escape(s: str) -> str: 142 """ 143 Replace backslashes with another backslash. 144 """ 145 return s.replace("\\", "\\\\")
Replace backslashes with another backslash.
def
nullsafe_join(join_char: str, *args: Optional[str]) -> str: