flexibleloop 0.1.0__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.
- flexibleloop-0.1.0/LICENSE +21 -0
- flexibleloop-0.1.0/PKG-INFO +171 -0
- flexibleloop-0.1.0/README.md +134 -0
- flexibleloop-0.1.0/flexibleloop/FlexibleLoop.py +133 -0
- flexibleloop-0.1.0/flexibleloop/__init__.py +1 -0
- flexibleloop-0.1.0/flexibleloop.egg-info/PKG-INFO +171 -0
- flexibleloop-0.1.0/flexibleloop.egg-info/SOURCES.txt +10 -0
- flexibleloop-0.1.0/flexibleloop.egg-info/dependency_links.txt +1 -0
- flexibleloop-0.1.0/flexibleloop.egg-info/top_level.txt +1 -0
- flexibleloop-0.1.0/pyproject.toml +23 -0
- flexibleloop-0.1.0/setup.cfg +4 -0
- flexibleloop-0.1.0/tests/test.py +76 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 tolgakanatli
|
|
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,171 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flexibleloop
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A flexible, customizable while loop for Python with timeout, iteration limits, and pre-iteration hooks.
|
|
5
|
+
Author-email: "Dr. Tolga Kaan Kanatlı" <tolgakanatli@hotmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 tolgakanatli
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/tolgakanatli/flexibleloop
|
|
29
|
+
Keywords: loop,while,timeout,iteration,utility
|
|
30
|
+
Classifier: Programming Language :: Python :: 3
|
|
31
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
32
|
+
Classifier: Operating System :: OS Independent
|
|
33
|
+
Requires-Python: >=3.8
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
License-File: LICENSE
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# flexibleloop
|
|
39
|
+
|
|
40
|
+
A Python utility that extends the standard `while` loop with built-in timeout control, iteration limits, pre-iteration hooks, and dynamic condition functions — all through a clean `for`-loop interface.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Why
|
|
45
|
+
|
|
46
|
+
Python's `while` loop is simple but limited. Adding a timeout, counting iterations, or updating variables before checking a condition requires boilerplate every time. `FlexibleWhile` packages all of that into a reusable, configurable object.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Features
|
|
51
|
+
|
|
52
|
+
- **Timeout** — Stop the loop automatically after a set number of seconds
|
|
53
|
+
- **Max iterations** — Cap the number of iterations without a counter variable
|
|
54
|
+
- **Before function** — Run a function before each iteration; its return value becomes the loop variable
|
|
55
|
+
- **Condition function** — Define the loop condition as a callable instead of inline logic
|
|
56
|
+
- **Callbacks** — Execute custom functions when timeout or max iterations are hit
|
|
57
|
+
- **Clean interface** — Used as a standard `for` loop; no new syntax to learn
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
Clone the repository and import directly:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
git clone https://github.com/tolgakanatli/flexiblewhile.git
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from FlexibleLoop import FlexibleWhile
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Usage
|
|
76
|
+
|
|
77
|
+
### Basic loop with timeout
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from FlexibleLoop import FlexibleWhile
|
|
81
|
+
|
|
82
|
+
loop = FlexibleWhile(timeout=5.0)
|
|
83
|
+
|
|
84
|
+
for _ in loop:
|
|
85
|
+
# Runs until 5 seconds have elapsed
|
|
86
|
+
do_something()
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Loop with a condition function
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
def condition(value):
|
|
93
|
+
return value < 100
|
|
94
|
+
|
|
95
|
+
def update(value):
|
|
96
|
+
return value + 7
|
|
97
|
+
|
|
98
|
+
loop = FlexibleWhile(
|
|
99
|
+
before_func=update,
|
|
100
|
+
cond_func=condition,
|
|
101
|
+
start_vals=(0,)
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
for value in loop:
|
|
105
|
+
print(value)
|
|
106
|
+
# Prints: 7, 14, 21, ... up to 98
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Loop with max iterations and a callback
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
def on_limit():
|
|
113
|
+
print("Max iterations reached")
|
|
114
|
+
|
|
115
|
+
loop = FlexibleWhile(
|
|
116
|
+
max_iterations=10,
|
|
117
|
+
on_max_iterations=on_limit
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
for _ in loop:
|
|
121
|
+
do_something()
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Accessing loop metadata
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
loop = FlexibleWhile(timeout=3.0)
|
|
128
|
+
for _ in loop:
|
|
129
|
+
pass
|
|
130
|
+
|
|
131
|
+
print(f"Completed {loop.iterations} iterations in {loop.time_elapsed:.2f}s")
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## API Reference
|
|
137
|
+
|
|
138
|
+
### `FlexibleWhile(before_func, cond_func, start_vals, timeout, max_iterations, on_timeout, on_max_iterations)`
|
|
139
|
+
|
|
140
|
+
| Parameter | Type | Default | Description |
|
|
141
|
+
|---|---|---|---|
|
|
142
|
+
| `before_func` | callable | None | Called before each iteration. Return value updates loop variable(s). |
|
|
143
|
+
| `cond_func` | callable | None | Loop continues while this returns `True`. `None` is equivalent to `while True`. |
|
|
144
|
+
| `start_vals` | tuple | `(None,)` | Initial values passed to `before_func` and `cond_func` on first iteration. |
|
|
145
|
+
| `timeout` | float | None | Maximum loop duration in seconds. |
|
|
146
|
+
| `max_iterations` | int | None | Maximum number of iterations. |
|
|
147
|
+
| `on_timeout` | callable | None | Called when timeout is reached. |
|
|
148
|
+
| `on_max_iterations` | callable | None | Called when max iterations is reached. |
|
|
149
|
+
|
|
150
|
+
### Instance attributes (after iteration)
|
|
151
|
+
|
|
152
|
+
| Attribute | Description |
|
|
153
|
+
|---|---|
|
|
154
|
+
| `loop.iterations` | Number of completed iterations |
|
|
155
|
+
| `loop.time_elapsed` | Total elapsed time in seconds |
|
|
156
|
+
| `loop.values` | Current value(s) of the loop variable |
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
MIT License — free to use, modify, and distribute, including commercially.
|
|
163
|
+
Attribution required: please credit **Dr. Tolga Kaan Kanatlı** in any derivative work or product.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Author
|
|
168
|
+
|
|
169
|
+
**Dr. Tolga Kaan Kanatlı**
|
|
170
|
+
PhD in Chemical Engineering — PEM Fuel Cells & Hydrogen Production
|
|
171
|
+
[GitHub](https://github.com/tolgakanatli) · [LinkedIn](https://www.linkedin.com/in/tolgakanatli) · tolgakanatli@hotmail.com
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# flexibleloop
|
|
2
|
+
|
|
3
|
+
A Python utility that extends the standard `while` loop with built-in timeout control, iteration limits, pre-iteration hooks, and dynamic condition functions — all through a clean `for`-loop interface.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Why
|
|
8
|
+
|
|
9
|
+
Python's `while` loop is simple but limited. Adding a timeout, counting iterations, or updating variables before checking a condition requires boilerplate every time. `FlexibleWhile` packages all of that into a reusable, configurable object.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- **Timeout** — Stop the loop automatically after a set number of seconds
|
|
16
|
+
- **Max iterations** — Cap the number of iterations without a counter variable
|
|
17
|
+
- **Before function** — Run a function before each iteration; its return value becomes the loop variable
|
|
18
|
+
- **Condition function** — Define the loop condition as a callable instead of inline logic
|
|
19
|
+
- **Callbacks** — Execute custom functions when timeout or max iterations are hit
|
|
20
|
+
- **Clean interface** — Used as a standard `for` loop; no new syntax to learn
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
Clone the repository and import directly:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
git clone https://github.com/tolgakanatli/flexiblewhile.git
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from FlexibleLoop import FlexibleWhile
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
### Basic loop with timeout
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from FlexibleLoop import FlexibleWhile
|
|
44
|
+
|
|
45
|
+
loop = FlexibleWhile(timeout=5.0)
|
|
46
|
+
|
|
47
|
+
for _ in loop:
|
|
48
|
+
# Runs until 5 seconds have elapsed
|
|
49
|
+
do_something()
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Loop with a condition function
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
def condition(value):
|
|
56
|
+
return value < 100
|
|
57
|
+
|
|
58
|
+
def update(value):
|
|
59
|
+
return value + 7
|
|
60
|
+
|
|
61
|
+
loop = FlexibleWhile(
|
|
62
|
+
before_func=update,
|
|
63
|
+
cond_func=condition,
|
|
64
|
+
start_vals=(0,)
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
for value in loop:
|
|
68
|
+
print(value)
|
|
69
|
+
# Prints: 7, 14, 21, ... up to 98
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Loop with max iterations and a callback
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
def on_limit():
|
|
76
|
+
print("Max iterations reached")
|
|
77
|
+
|
|
78
|
+
loop = FlexibleWhile(
|
|
79
|
+
max_iterations=10,
|
|
80
|
+
on_max_iterations=on_limit
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
for _ in loop:
|
|
84
|
+
do_something()
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Accessing loop metadata
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
loop = FlexibleWhile(timeout=3.0)
|
|
91
|
+
for _ in loop:
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
print(f"Completed {loop.iterations} iterations in {loop.time_elapsed:.2f}s")
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## API Reference
|
|
100
|
+
|
|
101
|
+
### `FlexibleWhile(before_func, cond_func, start_vals, timeout, max_iterations, on_timeout, on_max_iterations)`
|
|
102
|
+
|
|
103
|
+
| Parameter | Type | Default | Description |
|
|
104
|
+
|---|---|---|---|
|
|
105
|
+
| `before_func` | callable | None | Called before each iteration. Return value updates loop variable(s). |
|
|
106
|
+
| `cond_func` | callable | None | Loop continues while this returns `True`. `None` is equivalent to `while True`. |
|
|
107
|
+
| `start_vals` | tuple | `(None,)` | Initial values passed to `before_func` and `cond_func` on first iteration. |
|
|
108
|
+
| `timeout` | float | None | Maximum loop duration in seconds. |
|
|
109
|
+
| `max_iterations` | int | None | Maximum number of iterations. |
|
|
110
|
+
| `on_timeout` | callable | None | Called when timeout is reached. |
|
|
111
|
+
| `on_max_iterations` | callable | None | Called when max iterations is reached. |
|
|
112
|
+
|
|
113
|
+
### Instance attributes (after iteration)
|
|
114
|
+
|
|
115
|
+
| Attribute | Description |
|
|
116
|
+
|---|---|
|
|
117
|
+
| `loop.iterations` | Number of completed iterations |
|
|
118
|
+
| `loop.time_elapsed` | Total elapsed time in seconds |
|
|
119
|
+
| `loop.values` | Current value(s) of the loop variable |
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## License
|
|
124
|
+
|
|
125
|
+
MIT License — free to use, modify, and distribute, including commercially.
|
|
126
|
+
Attribution required: please credit **Dr. Tolga Kaan Kanatlı** in any derivative work or product.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Author
|
|
131
|
+
|
|
132
|
+
**Dr. Tolga Kaan Kanatlı**
|
|
133
|
+
PhD in Chemical Engineering — PEM Fuel Cells & Hydrogen Production
|
|
134
|
+
[GitHub](https://github.com/tolgakanatli) · [LinkedIn](https://www.linkedin.com/in/tolgakanatli) · tolgakanatli@hotmail.com
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import inspect
|
|
3
|
+
|
|
4
|
+
class FlexibleWhile:
|
|
5
|
+
"""
|
|
6
|
+
A flexible, customizable loop class that provides more control over loop behavior than the standard Python `while` loop.
|
|
7
|
+
|
|
8
|
+
Attributes:
|
|
9
|
+
before_func (callable, optional): A function to be executed before each iteration of the loop. This function can modify variables or perform actions that affect the loop's behavior. Defaults to None.
|
|
10
|
+
cond_func (callable, optional): A function that determines the loop's condition. If this function returns True, the loop continues; if it returns False, the loop stops. Defaults to None.
|
|
11
|
+
start_vals (tuple, optional): A tuple containing the initial values for variables used within the loop. Defaults to (None,).
|
|
12
|
+
timeout (float, optional): A maximum time limit for the loop. If the loop runs for longer than this time, it will stop. Defaults to None.
|
|
13
|
+
max_iterations (int, optional): A maximum number of iterations for the loop. If the loop runs for more iterations than this, it will stop. Defaults to None.
|
|
14
|
+
on_timeout (callable, optional): A function to be called if the loop times out. Defaults to None.
|
|
15
|
+
on_max_iterations (callable, optional): A function to be called if the loop reaches the maximum number of iterations. Defaults to None.
|
|
16
|
+
values (tuple): A tuple that holds the current values of the loop's variables.
|
|
17
|
+
start_time (float): Stores the time when the loop starts.
|
|
18
|
+
iterations (int): Keeps track of the number of iterations the loop has completed.
|
|
19
|
+
"""
|
|
20
|
+
def __init__(self,
|
|
21
|
+
before_func=None,
|
|
22
|
+
cond_func=None,
|
|
23
|
+
start_vals: tuple=(None,),
|
|
24
|
+
timeout=None, max_iterations=None,
|
|
25
|
+
on_timeout=None,
|
|
26
|
+
on_max_iterations=None):
|
|
27
|
+
|
|
28
|
+
"""
|
|
29
|
+
Initializes a FlexibleWhile object.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
before_func (callable, optional): Function to execute before each iteration.
|
|
33
|
+
cond_func (callable, optional): Function to determine loop condition. Setting to None is equivalent to "while True:". Defaults to None.
|
|
34
|
+
start_vals (tuple, optional): Initial values for loop variables. Defaults to (None,). If your before_func uses values from previous loop, you must set these.
|
|
35
|
+
timeout (float, optional): Maximum loop time in seconds.
|
|
36
|
+
max_iterations (int, optional): Maximum loop iterations.
|
|
37
|
+
on_timeout (callable, optional): Function to call on timeout.
|
|
38
|
+
on_max_iterations (callable, optional): Function to call on max iterations.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
self.before_func = before_func
|
|
42
|
+
self.cond_func = cond_func
|
|
43
|
+
self.timeout = timeout
|
|
44
|
+
self.max_iterations = max_iterations
|
|
45
|
+
self.on_timeout = on_timeout
|
|
46
|
+
self.on_max_iterations = on_max_iterations
|
|
47
|
+
self.values = start_vals
|
|
48
|
+
self.start_time = None
|
|
49
|
+
self.iterations = 0
|
|
50
|
+
|
|
51
|
+
def __iter__(self):
|
|
52
|
+
"""
|
|
53
|
+
Makes the FlexibleWhile object iterable, allowing it to be used in a for loop.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
self: The FlexibleWhile object itself.
|
|
57
|
+
"""
|
|
58
|
+
self.start_time = time.time()
|
|
59
|
+
self.iterations = 0
|
|
60
|
+
return self
|
|
61
|
+
|
|
62
|
+
def __next__(self):
|
|
63
|
+
"""
|
|
64
|
+
Executes the next iteration of the loop.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
tuple: The current values of the loop's variables.
|
|
68
|
+
|
|
69
|
+
Raises:
|
|
70
|
+
StopIteration: If the loop condition is not met, the timeout is reached, or the maximum number of iterations is reached.
|
|
71
|
+
"""
|
|
72
|
+
self.time_elapsed = time.time() - self.start_time
|
|
73
|
+
if self.timeout and self.time_elapsed > self.timeout:
|
|
74
|
+
if self.on_timeout:
|
|
75
|
+
self._call_func(self.on_timeout)
|
|
76
|
+
raise StopIteration("Timeout reached")
|
|
77
|
+
|
|
78
|
+
if self.max_iterations and self.iterations >= self.max_iterations:
|
|
79
|
+
if self.on_max_iterations:
|
|
80
|
+
self._call_func(self.on_max_iterations)
|
|
81
|
+
raise StopIteration("Max iterations reached")
|
|
82
|
+
|
|
83
|
+
# Update values before checking the condition
|
|
84
|
+
result = self._call_func(self.before_func)
|
|
85
|
+
if result is not None:
|
|
86
|
+
# Ensure values is a tuple
|
|
87
|
+
if not isinstance(result, tuple):
|
|
88
|
+
self.values = (result,)
|
|
89
|
+
else:
|
|
90
|
+
self.values = result
|
|
91
|
+
|
|
92
|
+
# Check the condition function
|
|
93
|
+
if self.cond_func and not self._call_func(self.cond_func):
|
|
94
|
+
raise StopIteration("Condition not met")
|
|
95
|
+
|
|
96
|
+
self.iterations += 1
|
|
97
|
+
|
|
98
|
+
# Return values ensuring it's not a tuple if there's only one item
|
|
99
|
+
if len(self.values) == 1:
|
|
100
|
+
return self.values[0]
|
|
101
|
+
else:
|
|
102
|
+
return self.values
|
|
103
|
+
|
|
104
|
+
def _call_func(self, func):
|
|
105
|
+
"""
|
|
106
|
+
Calls a function with the appropriate arguments.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
func (callable): The function to call.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Any: The result of the function call.
|
|
113
|
+
"""
|
|
114
|
+
if func is None:
|
|
115
|
+
return
|
|
116
|
+
if callable(func):
|
|
117
|
+
# Use inspect to get function signature
|
|
118
|
+
sig = inspect.signature(func)
|
|
119
|
+
params = sig.parameters
|
|
120
|
+
num_params = len(params)
|
|
121
|
+
|
|
122
|
+
if num_params == 0:
|
|
123
|
+
return func()
|
|
124
|
+
elif num_params == 1:
|
|
125
|
+
result = func(self.values[0])
|
|
126
|
+
return result
|
|
127
|
+
else:
|
|
128
|
+
return func(*self.values)
|
|
129
|
+
return
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
if __name__ == "__main__":
|
|
133
|
+
print("Module loaded")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#no one but ghosts here
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flexibleloop
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A flexible, customizable while loop for Python with timeout, iteration limits, and pre-iteration hooks.
|
|
5
|
+
Author-email: "Dr. Tolga Kaan Kanatlı" <tolgakanatli@hotmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 tolgakanatli
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/tolgakanatli/flexibleloop
|
|
29
|
+
Keywords: loop,while,timeout,iteration,utility
|
|
30
|
+
Classifier: Programming Language :: Python :: 3
|
|
31
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
32
|
+
Classifier: Operating System :: OS Independent
|
|
33
|
+
Requires-Python: >=3.8
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
License-File: LICENSE
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# flexibleloop
|
|
39
|
+
|
|
40
|
+
A Python utility that extends the standard `while` loop with built-in timeout control, iteration limits, pre-iteration hooks, and dynamic condition functions — all through a clean `for`-loop interface.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Why
|
|
45
|
+
|
|
46
|
+
Python's `while` loop is simple but limited. Adding a timeout, counting iterations, or updating variables before checking a condition requires boilerplate every time. `FlexibleWhile` packages all of that into a reusable, configurable object.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Features
|
|
51
|
+
|
|
52
|
+
- **Timeout** — Stop the loop automatically after a set number of seconds
|
|
53
|
+
- **Max iterations** — Cap the number of iterations without a counter variable
|
|
54
|
+
- **Before function** — Run a function before each iteration; its return value becomes the loop variable
|
|
55
|
+
- **Condition function** — Define the loop condition as a callable instead of inline logic
|
|
56
|
+
- **Callbacks** — Execute custom functions when timeout or max iterations are hit
|
|
57
|
+
- **Clean interface** — Used as a standard `for` loop; no new syntax to learn
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
Clone the repository and import directly:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
git clone https://github.com/tolgakanatli/flexiblewhile.git
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from FlexibleLoop import FlexibleWhile
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Usage
|
|
76
|
+
|
|
77
|
+
### Basic loop with timeout
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from FlexibleLoop import FlexibleWhile
|
|
81
|
+
|
|
82
|
+
loop = FlexibleWhile(timeout=5.0)
|
|
83
|
+
|
|
84
|
+
for _ in loop:
|
|
85
|
+
# Runs until 5 seconds have elapsed
|
|
86
|
+
do_something()
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Loop with a condition function
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
def condition(value):
|
|
93
|
+
return value < 100
|
|
94
|
+
|
|
95
|
+
def update(value):
|
|
96
|
+
return value + 7
|
|
97
|
+
|
|
98
|
+
loop = FlexibleWhile(
|
|
99
|
+
before_func=update,
|
|
100
|
+
cond_func=condition,
|
|
101
|
+
start_vals=(0,)
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
for value in loop:
|
|
105
|
+
print(value)
|
|
106
|
+
# Prints: 7, 14, 21, ... up to 98
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Loop with max iterations and a callback
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
def on_limit():
|
|
113
|
+
print("Max iterations reached")
|
|
114
|
+
|
|
115
|
+
loop = FlexibleWhile(
|
|
116
|
+
max_iterations=10,
|
|
117
|
+
on_max_iterations=on_limit
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
for _ in loop:
|
|
121
|
+
do_something()
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Accessing loop metadata
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
loop = FlexibleWhile(timeout=3.0)
|
|
128
|
+
for _ in loop:
|
|
129
|
+
pass
|
|
130
|
+
|
|
131
|
+
print(f"Completed {loop.iterations} iterations in {loop.time_elapsed:.2f}s")
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## API Reference
|
|
137
|
+
|
|
138
|
+
### `FlexibleWhile(before_func, cond_func, start_vals, timeout, max_iterations, on_timeout, on_max_iterations)`
|
|
139
|
+
|
|
140
|
+
| Parameter | Type | Default | Description |
|
|
141
|
+
|---|---|---|---|
|
|
142
|
+
| `before_func` | callable | None | Called before each iteration. Return value updates loop variable(s). |
|
|
143
|
+
| `cond_func` | callable | None | Loop continues while this returns `True`. `None` is equivalent to `while True`. |
|
|
144
|
+
| `start_vals` | tuple | `(None,)` | Initial values passed to `before_func` and `cond_func` on first iteration. |
|
|
145
|
+
| `timeout` | float | None | Maximum loop duration in seconds. |
|
|
146
|
+
| `max_iterations` | int | None | Maximum number of iterations. |
|
|
147
|
+
| `on_timeout` | callable | None | Called when timeout is reached. |
|
|
148
|
+
| `on_max_iterations` | callable | None | Called when max iterations is reached. |
|
|
149
|
+
|
|
150
|
+
### Instance attributes (after iteration)
|
|
151
|
+
|
|
152
|
+
| Attribute | Description |
|
|
153
|
+
|---|---|
|
|
154
|
+
| `loop.iterations` | Number of completed iterations |
|
|
155
|
+
| `loop.time_elapsed` | Total elapsed time in seconds |
|
|
156
|
+
| `loop.values` | Current value(s) of the loop variable |
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
MIT License — free to use, modify, and distribute, including commercially.
|
|
163
|
+
Attribution required: please credit **Dr. Tolga Kaan Kanatlı** in any derivative work or product.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Author
|
|
168
|
+
|
|
169
|
+
**Dr. Tolga Kaan Kanatlı**
|
|
170
|
+
PhD in Chemical Engineering — PEM Fuel Cells & Hydrogen Production
|
|
171
|
+
[GitHub](https://github.com/tolgakanatli) · [LinkedIn](https://www.linkedin.com/in/tolgakanatli) · tolgakanatli@hotmail.com
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
flexibleloop/FlexibleLoop.py
|
|
5
|
+
flexibleloop/__init__.py
|
|
6
|
+
flexibleloop.egg-info/PKG-INFO
|
|
7
|
+
flexibleloop.egg-info/SOURCES.txt
|
|
8
|
+
flexibleloop.egg-info/dependency_links.txt
|
|
9
|
+
flexibleloop.egg-info/top_level.txt
|
|
10
|
+
tests/test.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
flexibleloop
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "flexibleloop"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A flexible, customizable while loop for Python with timeout, iteration limits, and pre-iteration hooks."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { file = "LICENSE" }
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Dr. Tolga Kaan Kanatlı", email = "tolgakanatli@hotmail.com" }
|
|
13
|
+
]
|
|
14
|
+
keywords = ["loop", "while", "timeout", "iteration", "utility"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
]
|
|
20
|
+
requires-python = ">=3.8"
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://github.com/tolgakanatli/flexibleloop"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#test code for flexible while
|
|
2
|
+
from flexibleloop.FlexibleLoop import FlexibleWhile
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
######## EXAMPLE 1: GENERAL USAGE ########
|
|
6
|
+
a = 0
|
|
7
|
+
b = 10
|
|
8
|
+
|
|
9
|
+
def before(): #define a function to be run before each condition check
|
|
10
|
+
global a, b #you can use global a and b like this, or use the start_vals argument for a closed loop.
|
|
11
|
+
a += 1
|
|
12
|
+
b -= 1
|
|
13
|
+
return a, b
|
|
14
|
+
|
|
15
|
+
def condition(a, b): #define the condition of the while loop, using the variables processed before
|
|
16
|
+
return a < 5 and b > 5
|
|
17
|
+
|
|
18
|
+
print("Test 1")
|
|
19
|
+
# Using the FlexibleWhile as an iterator
|
|
20
|
+
for a,b in FlexibleWhile(before_func=before, cond_func=condition):
|
|
21
|
+
print(f"Current values: a={a}, b={b}")
|
|
22
|
+
if a == 3:
|
|
23
|
+
print("Good value, continuing...")
|
|
24
|
+
continue
|
|
25
|
+
if b == 8:
|
|
26
|
+
print("Eh, close enough")
|
|
27
|
+
break
|
|
28
|
+
|
|
29
|
+
print("Test 1 ended")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
######## EXAMPLE 2: LAMBDA USE ########
|
|
33
|
+
|
|
34
|
+
print("\n Test 2")
|
|
35
|
+
starttime = time.time()
|
|
36
|
+
for timer in FlexibleWhile(before_func= lambda: time.time()-starttime, #you can use lambda to make it easier
|
|
37
|
+
cond_func= lambda timer: timer < 5, #gets the timer value from the before_funcs output
|
|
38
|
+
max_iterations= 10, #the loop will break after 10 iterations max
|
|
39
|
+
on_max_iterations=lambda: print("Max iterations reached")): #function to call if max_iterations is reached
|
|
40
|
+
print(timer)
|
|
41
|
+
time.sleep(1)
|
|
42
|
+
|
|
43
|
+
print("Loop 2 ended")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
######### EXAMPLE 3: TIMEOUT ##########
|
|
47
|
+
|
|
48
|
+
print("\n Test 3")
|
|
49
|
+
for a,b in FlexibleWhile(before_func= lambda a,b: (a+1,b+2), #example function
|
|
50
|
+
cond_func= None, #this (or omitting cond_func alltogether) is the same as "while true:"
|
|
51
|
+
start_vals = (0,0), #Starting vars of a and b. Must be a tuple even if you have a single var.
|
|
52
|
+
timeout= 1,
|
|
53
|
+
on_timeout= lambda: print("Timeout reached")): #timeout in seconds. will break out if reached.
|
|
54
|
+
print(a,b)
|
|
55
|
+
time.sleep(0.1)
|
|
56
|
+
|
|
57
|
+
print("Loop 3 ended")
|
|
58
|
+
|
|
59
|
+
######### EXAMPLE 3: CHANGING VARS WITHIN LOOP ##########
|
|
60
|
+
print("\n Test 4")
|
|
61
|
+
|
|
62
|
+
#you can get the class
|
|
63
|
+
MyLoop = FlexibleWhile(before_func = lambda v: v*v, #square the v
|
|
64
|
+
cond_func = lambda v: v!=-999, #an impossible condition
|
|
65
|
+
start_vals = (2,), #must be a tuple, even for a single value
|
|
66
|
+
timeout = 2,
|
|
67
|
+
on_timeout = lambda v: print(f"\nTimeout of {MyLoop.timeout} seconds reached with a value of {v} in {MyLoop.iterations} iterations"))
|
|
68
|
+
|
|
69
|
+
for v in MyLoop:
|
|
70
|
+
print(f"{v} at {MyLoop.time_elapsed:.2f}")
|
|
71
|
+
if v > 256:
|
|
72
|
+
print(f"slow down buckaroo {v} is too high")
|
|
73
|
+
MyLoop.values = (2,) #"v=2" will not set the internal value. You must use this. Remember to use tuples.
|
|
74
|
+
time.sleep(0.1)
|
|
75
|
+
|
|
76
|
+
print(f"Loop 4 ended with {v}")
|