iterativerecursion 0.2__tar.gz → 1.1__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,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Carlos A. Planchón
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,405 @@
1
+ Metadata-Version: 2.4
2
+ Name: iterativerecursion
3
+ Version: 1.1
4
+ Summary: A Python module to simulate recursive function calls using iteration, providing explicit control over execution flow and avoiding stack overflow issues.
5
+ Author-email: "Carlos A. Planchón" <carlosandresplanchonprestes@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/carlosplanchon/iterativerecursion
8
+ Keywords: iterative,recursion
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Topic :: Software Development :: Build Tools
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Requires-Python: >=3.10
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Provides-Extra: dev
21
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
22
+ Dynamic: license-file
23
+
24
+ # iterativerecursion
25
+
26
+ ![iterativerecursion banner](https://raw.githubusercontent.com/carlosplanchon/iterativerecursion/refs/heads/master/assets/banner.jpeg)
27
+
28
+ [![CI](https://github.com/carlosplanchon/iterativerecursion/actions/workflows/ci.yml/badge.svg)](https://github.com/carlosplanchon/iterativerecursion/actions/workflows/ci.yml)
29
+ [![PyPI version](https://img.shields.io/pypi/v/iterativerecursion.svg)](https://pypi.org/project/iterativerecursion/)
30
+ [![Python versions](https://img.shields.io/pypi/pyversions/iterativerecursion.svg)](https://pypi.org/project/iterativerecursion/)
31
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
32
+ [![DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/carlosplanchon/iterativerecursion)
33
+
34
+ *A Python module to simulate recursive function calls using iteration, providing explicit control over execution flow and avoiding stack overflow issues.*
35
+
36
+ ## Overview
37
+
38
+ `iterativerecursion` provides a mechanism to chain function calls iteratively while maintaining a recursive-like pattern. Instead of relying on the call stack, functions explicitly declare what to call next, making the execution flow transparent and controllable.
39
+
40
+ ### Why Use This?
41
+
42
+ - **Avoid Stack Overflow**: Handle deep recursion without hitting Python's recursion limit
43
+ - **Explicit Control**: See and control the exact flow of function calls
44
+ - **Debugging**: Easier to trace execution without deep call stacks
45
+ - **State Management**: Shared environment for passing data between functions
46
+ - **Safety**: Built-in iteration limits to prevent infinite loops
47
+
48
+ ### When to Use This
49
+
50
+ This library is useful when you need:
51
+ - Deep recursion that exceeds Python's stack limit (~1000 calls)
52
+ - Explicit control over recursive execution flow
53
+ - To convert recursive algorithms to iterative ones systematically
54
+ - State machines or complex control flow patterns
55
+
56
+ ## Scope & limitations
57
+
58
+ This engine is essentially a **trampoline / dispatcher**: each step returns the name of the next function to run.
59
+ That makes it a great fit for **tail recursion (linear step-by-step recursion)**, workflows, and state machines.
60
+
61
+ It does **not** automatically emulate a full call stack. Patterns that require “returning to the caller”
62
+ (e.g. tree recursion like `fib(n-1) + fib(n-2)`, post-order DFS reductions) require you to model an explicit
63
+ stack/frames (continuations) inside `environment_variables`.
64
+
65
+ For most cases, **normal recursion is simpler and preferred**. Use this when recursion depth or explicit control becomes a concern.
66
+
67
+ ## Documentation
68
+
69
+ 📚 **[View interactive documentation on DeepWiki](https://deepwiki.com/carlosplanchon/iterativerecursion)**
70
+
71
+ Explore the full API reference, examples, and guides in an interactive format.
72
+
73
+ ## Installation
74
+
75
+ ### Using uv
76
+ ```bash
77
+ uv add iterativerecursion
78
+ ```
79
+
80
+ ### Using pip
81
+ ```bash
82
+ pip install iterativerecursion
83
+ ```
84
+
85
+ ## Quick Start
86
+
87
+ ```python
88
+ from iterativerecursion import IterativeRecursionEngine, FunctionReturn
89
+
90
+ def greet(name: str) -> FunctionReturn:
91
+ print(f"Hello, {name}!")
92
+ return FunctionReturn(
93
+ returned_values={"next_name": "World"},
94
+ next_function_to_call="farewell",
95
+ arg_env_mapping={"name": "next_name"}
96
+ )
97
+
98
+ def farewell(name: str) -> FunctionReturn:
99
+ print(f"Goodbye, {name}!")
100
+ return FunctionReturn(
101
+ returned_values={}
102
+ # next_function_to_call defaults to None to terminate
103
+ )
104
+
105
+ # Create engine and register functions
106
+ engine = IterativeRecursionEngine()
107
+ engine.add_function(greet)
108
+ engine.add_function(farewell)
109
+
110
+ # Start execution
111
+ engine.start_function_caller(
112
+ next_function_to_call="greet",
113
+ environment_variables={"initial_name": "Alice"},
114
+ arg_env_mapping={"name": "initial_name"}
115
+ )
116
+ ```
117
+
118
+ **Output:**
119
+ ```
120
+ Hello, Alice!
121
+ Goodbye, World!
122
+ ```
123
+
124
+ ## How It Works
125
+
126
+ Functions return a `FunctionReturn` dataclass instance with three attributes:
127
+
128
+ | Attribute | Type | Description |
129
+ |-----------|------|-------------|
130
+ | `returned_values` | `dict[str, Any]` | Values to store in the shared environment |
131
+ | `next_function_to_call` | `str \| None` | Name of the next function to execute, or `None` to stop (default: `None`) |
132
+ | `arg_env_mapping` | `dict[str, str]` | Mapping of parameter names to environment variable keys (default: auto-mapped from `returned_values` keys) |
133
+
134
+ **Key Feature**: If `arg_env_mapping` is not specified, it automatically maps each key in `returned_values` to itself. For example, `{"counter": 5}` automatically creates `{"counter": "counter"}` mapping.
135
+
136
+ The engine maintains a shared environment where functions can store and retrieve values across calls.
137
+
138
+ ## Examples
139
+
140
+ ### Using the @register Decorator
141
+
142
+ The `@register` decorator provides a cleaner way to register functions:
143
+
144
+ ```python
145
+ from iterativerecursion import IterativeRecursionEngine, FunctionReturn
146
+
147
+ engine = IterativeRecursionEngine()
148
+
149
+ @engine.register
150
+ def greet(name: str) -> FunctionReturn:
151
+ print(f"Hello, {name}!")
152
+ return FunctionReturn(
153
+ returned_values={"next_name": "World"},
154
+ next_function_to_call="farewell",
155
+ arg_env_mapping={"name": "next_name"}
156
+ )
157
+
158
+ @engine.register
159
+ def farewell(name: str) -> FunctionReturn:
160
+ print(f"Goodbye, {name}!")
161
+ return FunctionReturn(
162
+ returned_values={}
163
+ )
164
+
165
+ # Start execution and get final state
166
+ result = engine.start_function_caller(
167
+ next_function_to_call="greet",
168
+ environment_variables={"initial_name": "Alice"},
169
+ arg_env_mapping={"name": "initial_name"}
170
+ )
171
+ ```
172
+
173
+ ### Factorial Calculation
174
+
175
+ ```python
176
+ from iterativerecursion import IterativeRecursionEngine, FunctionReturn
177
+
178
+ def factorial_step(n: int, accumulator: int) -> FunctionReturn:
179
+ if n <= 1:
180
+ return FunctionReturn(
181
+ returned_values={"result": accumulator}
182
+ )
183
+ # Auto-mapping: {"n": n-1, "accumulator": ...} automatically maps to itself
184
+ return FunctionReturn(
185
+ returned_values={
186
+ "n": n - 1,
187
+ "accumulator": accumulator * n
188
+ },
189
+ next_function_to_call="factorial_step"
190
+ )
191
+
192
+ engine = IterativeRecursionEngine()
193
+ engine.add_function(factorial_step)
194
+ engine.start_function_caller(
195
+ next_function_to_call="factorial_step",
196
+ environment_variables={"n": 5, "accumulator": 1},
197
+ arg_env_mapping={"n": "n", "accumulator": "accumulator"}
198
+ )
199
+
200
+ print(f"5! = {engine.environment_variables['result']}") # Output: 5! = 120
201
+ ```
202
+
203
+ ### Fibonacci Sequence (tail-recursive / iterative form)
204
+
205
+ ```python
206
+ from iterativerecursion import IterativeRecursionEngine, FunctionReturn
207
+
208
+ def fibonacci(n: int, a: int, b: int) -> FunctionReturn:
209
+ if n == 0:
210
+ return FunctionReturn(
211
+ returned_values={"result": a}
212
+ )
213
+ # Auto-mapping handles {"n": "n", "a": "a", "b": "b"} automatically
214
+ return FunctionReturn(
215
+ returned_values={
216
+ "n": n - 1,
217
+ "a": b,
218
+ "b": a + b
219
+ },
220
+ next_function_to_call="fibonacci"
221
+ )
222
+
223
+ engine = IterativeRecursionEngine()
224
+ engine.add_function(fibonacci)
225
+ engine.start_function_caller(
226
+ next_function_to_call="fibonacci",
227
+ environment_variables={"n": 10, "a": 0, "b": 1},
228
+ arg_env_mapping={"n": "n", "a": "a", "b": "b"}
229
+ )
230
+
231
+ print(f"Fibonacci(10) = {engine.environment_variables['result']}") # Output: 55
232
+ ```
233
+
234
+ ### Preventing Infinite Loops
235
+
236
+ Use the `max_iterations` parameter to prevent runaway execution:
237
+
238
+ ```python
239
+ from iterativerecursion import IterativeRecursionEngine, FunctionReturn
240
+
241
+ def infinite_loop(counter: int) -> FunctionReturn:
242
+ print(f"Iteration: {counter}")
243
+ # Auto-mapping: no need for {"counter": "counter"}
244
+ return FunctionReturn(
245
+ returned_values={"counter": counter + 1},
246
+ next_function_to_call="infinite_loop"
247
+ )
248
+
249
+ engine = IterativeRecursionEngine()
250
+ engine.add_function(infinite_loop)
251
+
252
+ try:
253
+ engine.start_function_caller(
254
+ next_function_to_call="infinite_loop",
255
+ environment_variables={"counter": 0},
256
+ arg_env_mapping={"counter": "counter"},
257
+ max_iterations=10 # Safety limit
258
+ )
259
+ except RuntimeError as e:
260
+ print(f"Caught: {e}")
261
+ # Output: Caught: Maximum iteration limit (10) reached...
262
+ ```
263
+
264
+ ## API Reference
265
+
266
+ ### `IterativeRecursionEngine`
267
+
268
+ The main execution engine for iterative recursion.
269
+
270
+ #### Methods
271
+
272
+ ##### `__init__()`
273
+ Creates a new engine instance.
274
+
275
+ ```python
276
+ engine = IterativeRecursionEngine()
277
+ ```
278
+
279
+ ##### `add_function(function)`
280
+ Registers a function with the engine.
281
+
282
+ - **Parameters**: `function` - A callable that returns `FunctionReturn`
283
+ - **Returns**: None
284
+
285
+ ```python
286
+ engine.add_function(my_function)
287
+ ```
288
+
289
+ ##### `register(function)`
290
+ Decorator to register a function with the engine. Alternative to `add_function()`.
291
+
292
+ - **Parameters**: `function` - A callable that returns `FunctionReturn`
293
+ - **Returns**: The same function (for chaining)
294
+
295
+ ```python
296
+ @engine.register
297
+ def my_function(x: int) -> FunctionReturn:
298
+ return FunctionReturn(
299
+ returned_values={"result": x * 2}
300
+ )
301
+ ```
302
+
303
+ ##### `add_environment_variables(variables: dict[str, Any])`
304
+ Adds or updates variables in the shared environment.
305
+
306
+ - **Parameters**: `variables` - Dictionary of variable names and values
307
+ - **Returns**: None
308
+
309
+ ```python
310
+ engine.add_environment_variables({"x": 10, "y": 20})
311
+ ```
312
+
313
+ ##### `start_function_caller(next_function_to_call, environment_variables, arg_env_mapping, max_iterations=None)`
314
+ Begins executing functions starting from the specified function.
315
+
316
+ - **Parameters**:
317
+ - `next_function_to_call` (str | None): Name of the first function to call. Pass `None` to terminate immediately after recording `environment_variables`.
318
+ - `environment_variables` (dict[str, Any]): Initial environment variables
319
+ - `arg_env_mapping` (dict[str, str]): Parameter mapping for first function
320
+ - `max_iterations` (int | None): Maximum iterations allowed (default: None/unlimited)
321
+ - **Returns**: `dict[str, Any]` - Final state of environment variables after execution
322
+ - **Raises**:
323
+ - `KeyError`: If function not found or environment variable missing
324
+ - `RuntimeError`: If `max_iterations` limit is reached
325
+ - `ValueError`: If function returns invalid structure
326
+ - `TypeError`: If function return has wrong types
327
+
328
+ ```python
329
+ result = engine.start_function_caller(
330
+ next_function_to_call="start_func",
331
+ environment_variables={"value": 42},
332
+ arg_env_mapping={"param": "value"},
333
+ max_iterations=1000
334
+ )
335
+ # Access final state directly from result
336
+ print(result["some_value"])
337
+ ```
338
+
339
+ #### Attributes
340
+
341
+ - `functions_dict` (dict): Registry of available functions
342
+ - `environment_variables` (dict): Shared state accessible to all functions
343
+
344
+ ### Type Definitions
345
+
346
+ #### `FunctionReturn`
347
+ Dataclass defining the required return structure for functions.
348
+
349
+ ```python
350
+ @dataclass
351
+ class FunctionReturn:
352
+ returned_values: dict[str, Any]
353
+ next_function_to_call: str | None = None
354
+ arg_env_mapping: dict[str, str] = field(default_factory=dict)
355
+ ```
356
+
357
+ **Auto-mapping feature**: If `arg_env_mapping` is not provided, it automatically maps each key in `returned_values` to itself. This means you rarely need to specify `arg_env_mapping` explicitly.
358
+
359
+ #### `VarsDict`
360
+ Type alias for variable dictionaries.
361
+
362
+ ```python
363
+ VarsDict = dict[str, Any]
364
+ ```
365
+
366
+ ## Development
367
+
368
+ ### Running Tests
369
+
370
+ ```bash
371
+ # Install with dev dependencies
372
+ pip install -e ".[dev]"
373
+
374
+ # Run tests
375
+ pytest tests/ -v
376
+ ```
377
+
378
+ ### Test Coverage
379
+
380
+ The test suite includes:
381
+ - Basic function chaining
382
+ - Environment variable management
383
+ - Error handling and validation
384
+ - Runtime validation of return structures
385
+ - Iteration limits
386
+ - Decorator API (`@register`)
387
+ - Return value access
388
+ - Improved error messages
389
+ - Complex scenarios (factorial, state machines)
390
+
391
+ ## Contributing
392
+
393
+ Contributions are welcome! Please feel free to submit a Pull Request.
394
+
395
+ ## License
396
+
397
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
398
+
399
+ ## Author
400
+
401
+ Carlos A. Planchón - [GitHub](https://github.com/carlosplanchon/iterativerecursion)
402
+
403
+ ## Acknowledgments
404
+
405
+ This module was created as both a practical solution for deep recursion scenarios and an exploration of alternative execution patterns in Python.