Skip to content

Commit 845ff91

Browse files
committed
Initial project
1 parent 787b92b commit 845ff91

File tree

4 files changed

+230
-0
lines changed

4 files changed

+230
-0
lines changed

__init__.py

Whitespace-only changes.

example.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from micro_env import micro_env
2+
3+
4+
if __name__ == "__main__":
5+
micro_env = micro_env({"prop_a": 1, "prop_b": 2}, {"id": "my_env"})
6+
print(micro_env)

micro_env.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
from typing import Any, Dict, List, Optional, TypeVar, Callable, Union, Protocol
2+
from supply_demand import supply_demand
3+
4+
5+
class GetterProtocol(Protocol):
6+
def __call__(self, data: Dict[str, Any]) -> Any: ...
7+
8+
9+
class SetterProtocol(Protocol):
10+
def __call__(self, data: Dict[str, Any]) -> Any: ...
11+
12+
13+
def create_get(custom: Optional[GetterProtocol] = None) -> Any:
14+
def get_supplier(data: Dict[str, Any], context: Dict[str, str]) -> Any:
15+
descriptor = data.get("descriptor")
16+
obj = data.get("obj")
17+
caller = data.get("caller")
18+
next_val = data.get("next")
19+
key = context["key"]
20+
21+
if custom:
22+
return custom(
23+
{
24+
"key": key,
25+
"descriptor": descriptor,
26+
"obj": obj,
27+
"caller": caller,
28+
"next": next_val,
29+
}
30+
)
31+
32+
return obj.get(key, descriptor.get("defaultData") if descriptor else None)
33+
34+
return get_supplier
35+
36+
37+
def create_set(custom: Optional[SetterProtocol] = None) -> Any:
38+
def set_supplier(data: Dict[str, Any], context: Dict[str, str]) -> Any:
39+
obj = data.get("obj")
40+
descriptor = data.get("descriptor")
41+
value = data.get("value")
42+
caller = data.get("caller")
43+
key = context["key"]
44+
45+
if custom:
46+
return custom(
47+
{
48+
"key": key,
49+
"descriptor": descriptor,
50+
"obj": obj,
51+
"value": value,
52+
"caller": caller,
53+
}
54+
)
55+
56+
obj[key] = value
57+
return value
58+
59+
return set_supplier
60+
61+
62+
def micro_env(obj=None, descriptor=None, suppliers=None):
63+
if obj is None:
64+
obj = {}
65+
if suppliers is None:
66+
suppliers = {}
67+
if descriptor is None:
68+
descriptor = {}
69+
return supply_demand(
70+
{
71+
"obj": obj,
72+
"descriptor": descriptor,
73+
},
74+
{
75+
**suppliers,
76+
"get": create_get(),
77+
"set": create_set(),
78+
},
79+
)

supply_demand.py

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
from typing import Any, Callable, Dict, Optional, Union
2+
3+
4+
# Type aliases
5+
DemandProps = Dict[str, Any]
6+
SupplyMethod = Callable[[Optional[Any], "Scope"], Any]
7+
ScopedDemand = Callable[[DemandProps], Any]
8+
SuppliersMerge = Dict[str, Union[bool, Dict[str, SupplyMethod], list]]
9+
ExtendSuppliersMethod = Callable[
10+
[Dict[str, SupplyMethod], SuppliersMerge], Dict[str, SupplyMethod]
11+
]
12+
DemandReturn = Any
13+
14+
15+
# Supplier function type (Callable with specific signature)
16+
def supplier_type(data: Optional[Any], scope: "Scope") -> DemandReturn:
17+
pass
18+
19+
20+
# Scope class for holding demand context
21+
class Scope:
22+
def __init__(self, key: str, _type: str, path: str, demand: ScopedDemand):
23+
self.key = key
24+
self.type = _type
25+
self.path = path
26+
self.demand = demand
27+
28+
29+
# Function to merge suppliers with operations: clear, add, remove
30+
def merge_suppliers(
31+
original: Dict[str, SupplyMethod], merge_op: SuppliersMerge
32+
) -> Dict[str, SupplyMethod]:
33+
merged = {}
34+
if not merge_op.get("clear", False):
35+
merged.update(original)
36+
merged.update(merge_op.get("add", {}))
37+
for key in merge_op.get("remove", []):
38+
merged.pop(key, None)
39+
return merged
40+
41+
42+
# Main function to handle global demand
43+
def global_demand(props: DemandProps) -> DemandReturn:
44+
key = props["key"]
45+
_type = props["type"]
46+
path = props["path"]
47+
suppliers = props.get("suppliers", {})
48+
49+
if not key or not _type or not path:
50+
raise ValueError("Key, Type, and Path are required in global_demand.")
51+
52+
print(f"Global demand called with: Key: {key}, Type: {_type}, Path: {path}")
53+
54+
supplier_func = suppliers.get(_type)
55+
if supplier_func:
56+
print(f"Calling supplier for type: {_type}")
57+
return supplier_func(
58+
props.get("data"),
59+
{
60+
"key": key,
61+
"type": _type,
62+
"path": path,
63+
"demand": create_scoped_demand(props),
64+
},
65+
)
66+
print(f"Supplier not found for type: {_type}")
67+
68+
69+
# Function to create a demand function that is scoped
70+
def create_scoped_demand(super_props: DemandProps) -> ScopedDemand:
71+
def demand_func(props: DemandProps) -> DemandReturn:
72+
demand_key = props.get("key", super_props["key"])
73+
74+
if "type" not in props:
75+
raise ValueError("Type is required in scoped demand.")
76+
77+
path = f"{super_props['path']}/{demand_key}({props['type']})"
78+
new_suppliers = merge_suppliers(
79+
super_props["suppliers"], props.get("suppliers_merge", {})
80+
)
81+
82+
return global_demand(
83+
{
84+
"key": demand_key,
85+
"type": props["type"],
86+
"path": path,
87+
"data": props.get("data"),
88+
"suppliers": new_suppliers,
89+
}
90+
)
91+
92+
return demand_func
93+
94+
95+
# Initiate supply and demand process
96+
def supply_demand(
97+
root_supplier: SupplyMethod, suppliers: Dict[str, SupplyMethod]
98+
) -> DemandReturn:
99+
suppliers_copy = suppliers.copy()
100+
suppliers_copy["$$root"] = root_supplier
101+
return global_demand(
102+
{
103+
"key": "root",
104+
"type": "$$root",
105+
"path": "root",
106+
"suppliers": suppliers_copy,
107+
}
108+
)
109+
110+
111+
# Example supplier functions
112+
def first_supplier(data: Optional[Any], scope: Scope) -> str:
113+
print("First supplier function called.")
114+
return "1st"
115+
116+
117+
def second_supplier(data: Optional[Any], scope: Scope) -> str:
118+
print("Second supplier function called.")
119+
return "2nd"
120+
121+
122+
def third_supplier(data: Optional[Any], scope: Scope) -> DemandReturn:
123+
print("Third supplier function called.")
124+
return scope["demand"](
125+
{
126+
"type": "first",
127+
}
128+
)
129+
130+
131+
# Main execution
132+
if __name__ == "__main__":
133+
suppliers = {"first": first_supplier, "second": second_supplier}
134+
135+
def root_supplier(data: Optional[Any], scope: Scope) -> None:
136+
print("Root supplier function called.")
137+
res = scope["demand"](
138+
{
139+
"type": "third",
140+
"suppliers_merge": {"add": {"third": third_supplier}},
141+
}
142+
)
143+
print("Root supplier function call result is:", res)
144+
145+
supply_demand(root_supplier, suppliers)

0 commit comments

Comments
 (0)