Skip to content

Instantly share code, notes, and snippets.

@Tishka17
Created June 5, 2025 16:27
Show Gist options
  • Save Tishka17/c407b821eb9c4766af746c9a6c8f87ec to your computer and use it in GitHub Desktop.
Save Tishka17/c407b821eb9c4766af746c9a6c8f87ec to your computer and use it in GitHub Desktop.
Env vars processing using adaptix
from dataclasses import dataclass
from typing import Any, TypedDict
from adaptix import Retort, CannotProvide, name_mapping, loader, Chain
from adaptix._internal.provider.loc_stack_filtering import LocStack, P
from adaptix._internal.provider.location import TypeHintLoc
from adaptix._internal.provider.shape_provider import InputShapeRequest
class ClassTOTD:
def __init__(self):
self.retort = Retort()
def convert(self, t: Any, prefix: str,
path: list[str] | None = None) -> Any:
res = {}
types = {}
if path is None:
path = []
try:
shape = self.retort._provide_from_recipe(
InputShapeRequest(LocStack(TypeHintLoc(type=t))),
)
except CannotProvide:
return None, None
for field in shape.fields:
field_name = prefix + "_" + field.id.upper()
field_path = path + [field.id]
tmp, tmp_types = self.convert(field.type, field_name, field_path)
if not tmp:
res[field_name] = field_path
types[field_name] = field.type
else:
res.update(tmp)
types.update(tmp_types)
return res, types
def process(cfg_class, data):
names, types = ClassTOTD().convert(cfg_class, "MYAPP")
print(names, types)
cls = TypedDict("Config_td", types, total=False)
retort = Retort(
recipe=[
loader(set[str], lambda s: s.split(","), Chain.FIRST),
],
strict_coercion=False,
)
retort2 = Retort(
recipe=[name_mapping(cls, map=names)],
)
return retort2.dump(retort.load(data, cls), cls)
# ====
@dataclass
class Db:
uri: str
@dataclass
class Config:
db: Db
log_level: str
blacklist: set[str]
env_data = {
"MYAPP_DB_URI": "xxx",
"MYAPP_LOG_LEVEL": "INFO",
"MYAPP_BLACKLIST": "x,y,x"
}
print(process(Config, env_data))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment