state-rules 2026.3.29__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.3
2
+ Name: state-rules
3
+ Version: 2026.3.29
4
+ Summary: Add your description here
5
+ Requires-Python: >=3.14
6
+ Description-Content-Type: text/markdown
7
+
File without changes
@@ -0,0 +1,22 @@
1
+ [project]
2
+ name = "state-rules"
3
+ version = "2026.3.29"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ requires-python = ">=3.14"
7
+ dependencies = [
8
+ ]
9
+
10
+ [dependency-groups]
11
+ dev = [
12
+ 'fire',
13
+ "marimo", "pyzmq",
14
+ 'pre-commit',
15
+ ]
16
+
17
+ [project.scripts]
18
+ dyrules = "state_rules:main"
19
+
20
+ [build-system]
21
+ requires = ["uv_build>=0.10.8,<0.11.0"]
22
+ build-backend = "uv_build"
File without changes
@@ -0,0 +1,78 @@
1
+ class types:
2
+ state_keys = int | str
3
+ state = dict # can it be something else? just need mapping and iter
4
+ from typing import Callable
5
+ argmap = dict[state_keys, state_keys | Callable ] # callable[state keys,-> ]
6
+
7
+ class Rules:
8
+
9
+ def __init__(self, state: types.state = {}, log: bool=True):
10
+ self.state = state
11
+ self.funcs = []
12
+ self.log = [] if log is True else False
13
+
14
+ def register(self, argmap: types.argmap | None = None):
15
+ """decorator on a function"""
16
+ from inspect import signature
17
+ def add_func(f, argmap=argmap):
18
+ if argmap is None:
19
+ argmap = {p:p for p in signature(f).parameters}
20
+ for s in signature(f).parameters:
21
+ if s not in argmap:
22
+ argmap[s] = s
23
+
24
+ if 'return' not in argmap:
25
+ argmap['return'] = f'{f.__module__}.{f.__name__}({','.join(v for v in argmap.values())})'
26
+
27
+ f.argmap = argmap
28
+ f._argmap_no_return = {fa:s for fa,s in f.argmap.items() if (fa != 'return') }
29
+ self.funcs.append(f)
30
+ return add_func
31
+
32
+ @classmethod
33
+ def _argmapf2args(cls, am: types.argmap, state: types.state):
34
+ for fa, s in am.items():
35
+ if callable(s):
36
+ for sk,sv in state.items():
37
+ ssk = s(sk)
38
+ if ssk == True:
39
+ yield fa, sv
40
+ else:
41
+ assert(ssk == False)
42
+
43
+ def __iter__(self):
44
+ state = self.state
45
+ for f in self.funcs:
46
+ _ = {fa:state[s] for fa,s in f._argmap_no_return.items() if not callable(s) } # simple case
47
+ _.update(self._argmapf2args(f._argmap_no_return, state ) )
48
+ _ = f(**_)
49
+ state[f.argmap['return']] = _
50
+ yield state
51
+
52
+ def run(self, maxiter = 10):
53
+ i = 0
54
+ from types import SimpleNamespace as NS
55
+ class Iteration(NS): pass
56
+
57
+ if self.log is not False:
58
+ self.log.append(Iteration(i=i, state=self.state.copy()))
59
+
60
+ while True:
61
+ if i >= maxiter: break
62
+ oldstate = self.state.copy() # shallow vs deep?
63
+ _ = iter(self)
64
+ self.state = newstate = next(_)
65
+
66
+ if self.log is not False:
67
+ self.log.append(Iteration(i=i+1, state=newstate.copy()))
68
+
69
+ if newstate == oldstate:
70
+ break
71
+ else:
72
+ i = i+1
73
+ newstate = oldstate
74
+ continue
75
+
76
+ return self.state
77
+
78
+