mapres 3.dev23__tar.gz → 3.dev25__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.
Files changed (23) hide show
  1. {mapres-3.dev23/src/mapres.egg-info → mapres-3.dev25}/PKG-INFO +1 -1
  2. {mapres-3.dev23 → mapres-3.dev25}/pyproject.toml +1 -1
  3. {mapres-3.dev23 → mapres-3.dev25}/src/mapres/datamap.py +17 -18
  4. {mapres-3.dev23 → mapres-3.dev25}/src/mapres/evaluator.py +43 -0
  5. {mapres-3.dev23 → mapres-3.dev25/src/mapres.egg-info}/PKG-INFO +1 -1
  6. {mapres-3.dev23 → mapres-3.dev25}/LICENSE +0 -0
  7. {mapres-3.dev23 → mapres-3.dev25}/README.md +0 -0
  8. {mapres-3.dev23 → mapres-3.dev25}/setup.cfg +0 -0
  9. {mapres-3.dev23 → mapres-3.dev25}/src/mapres/__init__.py +0 -0
  10. {mapres-3.dev23 → mapres-3.dev25}/src/mapres/ast.py +0 -0
  11. {mapres-3.dev23 → mapres-3.dev25}/src/mapres/cache.py +0 -0
  12. {mapres-3.dev23 → mapres-3.dev25}/src/mapres/exceptions.py +0 -0
  13. {mapres-3.dev23 → mapres-3.dev25}/src/mapres/layers.py +0 -0
  14. {mapres-3.dev23 → mapres-3.dev25}/src/mapres/maps/__init__.py +0 -0
  15. {mapres-3.dev23 → mapres-3.dev25}/src/mapres/maps/color.py +0 -0
  16. {mapres-3.dev23 → mapres-3.dev25}/src/mapres/maps/time.py +0 -0
  17. {mapres-3.dev23 → mapres-3.dev25}/src/mapres/parser.py +0 -0
  18. {mapres-3.dev23 → mapres-3.dev25}/src/mapres/resolver.py +0 -0
  19. {mapres-3.dev23 → mapres-3.dev25}/src/mapres/tokenizer.py +0 -0
  20. {mapres-3.dev23 → mapres-3.dev25}/src/mapres.egg-info/SOURCES.txt +0 -0
  21. {mapres-3.dev23 → mapres-3.dev25}/src/mapres.egg-info/dependency_links.txt +0 -0
  22. {mapres-3.dev23 → mapres-3.dev25}/src/mapres.egg-info/requires.txt +0 -0
  23. {mapres-3.dev23 → mapres-3.dev25}/src/mapres.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapres
3
- Version: 3.dev23
3
+ Version: 3.dev25
4
4
  Summary: A powerfull mapping utility
5
5
  Author: iFamished
6
6
  License: MIT
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "mapres"
10
- version = "3-dev.23"
10
+ version = "3-dev.25"
11
11
  description = "A powerfull mapping utility"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.9"
@@ -36,6 +36,8 @@ class DataMap:
36
36
  __syntax__: str = None
37
37
  __mode__: str | None = None # 'dynamic', 'config', 'callable', or None
38
38
  __missing_key__: str = 'error' # 'error', 'silent', 'placeholder'
39
+ __recursive__: bool = False
40
+ __max_depth__: int = 10
39
41
 
40
42
  def as_map(self):
41
43
  '''
@@ -92,11 +94,13 @@ class DataMap:
92
94
  return out
93
95
 
94
96
 
95
- def datamap(_cls=None, *, syntax=None, mode=None, missing_key=None):
97
+ def datamap(_cls=None, *, syntax=None, mode=None, missing_key=None, recursive=None, max_depth=None):
96
98
  def wrap(cls):
97
99
  cls.__syntax__ = syntax
98
100
  cls.__mode__ = mode
99
101
  cls.__missing_key__ = missing_key or 'error'
102
+ cls.__recursive__ = recursive or False
103
+ cls.__max_depth__ = max_depth or 10
100
104
 
101
105
  namespace = dict(cls.__dict__)
102
106
  namespace['__dict__'] = {}
@@ -117,14 +121,6 @@ def datamap(_cls=None, *, syntax=None, mode=None, missing_key=None):
117
121
 
118
122
  # syntax-bound decorator factories
119
123
  class _SyntaxFactory:
120
- '''
121
- Allows:
122
- @datamap.angles
123
- @datamap.angles(mode='config')
124
- @datamap.angles.config
125
- @datamap.angles.dynamic
126
- @datamap.angles.callable
127
- '''
128
124
  def __init__(self, syntax_name):
129
125
  self._syntax = syntax_name
130
126
 
@@ -133,17 +129,20 @@ class _SyntaxFactory:
133
129
  return datamap(_cls, syntax=self._syntax)
134
130
  return datamap(syntax=self._syntax, **kwargs)
135
131
 
136
- @property
137
- def config(self):
138
- return datamap(syntax=self._syntax, mode='config')
132
+ def config(self, _cls=None, **kwargs):
133
+ if _cls is not None and isinstance(_cls, type):
134
+ return datamap(_cls, syntax=self._syntax, mode='config')
135
+ return datamap(syntax=self._syntax, mode='config', **kwargs)
139
136
 
140
- @property
141
- def dynamic(self):
142
- return datamap(syntax=self._syntax, mode='dynamic')
137
+ def dynamic(self, _cls=None, **kwargs):
138
+ if _cls is not None and isinstance(_cls, type):
139
+ return datamap(_cls, syntax=self._syntax, mode='dynamic')
140
+ return datamap(syntax=self._syntax, mode='dynamic', **kwargs)
143
141
 
144
- @property
145
- def callable(self):
146
- return datamap(syntax=self._syntax, mode='callable')
142
+ def callable(self, _cls=None, **kwargs):
143
+ if _cls is not None and isinstance(_cls, type):
144
+ return datamap(_cls, syntax=self._syntax, mode='callable')
145
+ return datamap(syntax=self._syntax, mode='callable', **kwargs)
147
146
 
148
147
 
149
148
  datamap.braces = _SyntaxFactory(syntax.braces)
@@ -33,6 +33,13 @@ class Evaluator:
33
33
  return self._eval_call(node)
34
34
 
35
35
  raise EvaluationError(f'Unknown AST node: {node}')
36
+
37
+ # re-resolve
38
+ def _re_resolve(self, text: str) -> str:
39
+ tokens = Tokenizer(text).tokenize()
40
+ ast = Parser(tokens).parse()
41
+ return self.evaluate(ast)
42
+
36
43
 
37
44
  # template
38
45
  def _eval_template(self, node: TemplateNode):
@@ -40,6 +47,42 @@ class Evaluator:
40
47
  for child in node.children:
41
48
  parts.append(self._eval(child))
42
49
  out = ''.join(parts)
50
+
51
+ # ---------------------------------------
52
+ # PER-MAP RECURSION (syntax-scoped)
53
+ # ---------------------------------------
54
+ # Find all maps in the layerstack that have recursive=True
55
+ recursive_maps = [
56
+ m for m in self.layerstack.all_maps()
57
+ if getattr(m, '__recursive__', False) is True
58
+ ]
59
+
60
+ # If no maps are recursive, return the first-pass output
61
+ if not recursive_maps:
62
+ return out
63
+
64
+ # Determine max recursion depth across all recursive maps
65
+ max_depth = max(getattr(m, '__max_depth__', 10) for m in recursive_maps)
66
+
67
+ seen = set()
68
+ depth = 0
69
+
70
+ while depth < max_depth:
71
+ # Re-tokenize and re-evaluate the ENTIRE output string
72
+ new_out = self._re_resolve(out)
73
+
74
+ # If stable, stop recursion
75
+ if new_out == out:
76
+ break
77
+
78
+ # Cycle detection
79
+ if new_out in seen:
80
+ raise EvaluationError('Cycle detected in recursive map resolution')
81
+
82
+ seen.add(new_out)
83
+ out = new_out
84
+ depth += 1
85
+
43
86
  return out
44
87
 
45
88
  # identifier
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapres
3
- Version: 3.dev23
3
+ Version: 3.dev25
4
4
  Summary: A powerfull mapping utility
5
5
  Author: iFamished
6
6
  License: MIT
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes