async-timer 1.0.2__tar.gz → 1.0.3__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: async-timer
3
- Version: 1.0.2
3
+ Version: 1.0.3
4
4
  Summary: The missing Python async timer.
5
5
  License: MIT
6
6
  Keywords: async,timer
@@ -48,16 +48,62 @@ This package is particularly useful for tasks like automatically updating caches
48
48
 
49
49
  ## Example Usage
50
50
 
51
+ ### FastAPI
52
+
53
+ This snippet starts fastapi webserver with the `refresh_db` function being executed every 5 seconds, refresing a shared `DB_CACHE` object.
54
+
55
+ ```python
56
+
57
+ import contextlib
58
+ import time
59
+
60
+ import uvicorn
61
+ from fastapi import FastAPI
62
+
63
+ import async_timer
64
+
65
+ DB_CACHE = {"initialised": False}
66
+
67
+
68
+ async def refresh_db():
69
+ global DB_CACHE
70
+ DB_CACHE |= {"initialised": True, "cur_value": time.time()}
71
+
72
+
73
+ @contextlib.asynccontextmanager
74
+ async def lifespan(_app: FastAPI):
75
+ async with async_timer.Timer(delay=5, target=refresh_db) as timer:
76
+ await timer.wait(hit_count=1) # block until the timer triggers at least once
77
+ yield
78
+
79
+
80
+ app = FastAPI(lifespan=lifespan)
81
+
82
+
83
+ @app.get("/")
84
+ async def root():
85
+ return {"message": "Hello World", "db_cache": DB_CACHE}
86
+
87
+
88
+ if __name__ == "__main__":
89
+ uvicorn.run(app, host="0.0.0.0", port=8000)
90
+
91
+ ```
92
+
93
+ ### join()
51
94
  ```python
52
95
 
53
96
  import async_timer
54
97
 
55
- # Simple timer example
56
98
  timer = async_timer.Timer(12, target=lambda: 42)
57
99
  timer.start()
58
- val = await timer.join() # `val` will be 42 after 12 seconds
100
+ val = await timer.join() # `val` will be set to 42 after 12 seconds
101
+ ```
59
102
 
103
+ ### for loop
104
+ ```python
60
105
  # Async for loop example
106
+ import async_timer
61
107
  import time
62
108
  with async_timer.Timer(14, target=time.time) as timer:
63
109
  async for time_rv in timer:
@@ -26,16 +26,62 @@ This package is particularly useful for tasks like automatically updating caches
26
26
 
27
27
  ## Example Usage
28
28
 
29
+ ### FastAPI
30
+
31
+ This snippet starts fastapi webserver with the `refresh_db` function being executed every 5 seconds, refresing a shared `DB_CACHE` object.
32
+
33
+ ```python
34
+
35
+ import contextlib
36
+ import time
37
+
38
+ import uvicorn
39
+ from fastapi import FastAPI
40
+
41
+ import async_timer
42
+
43
+ DB_CACHE = {"initialised": False}
44
+
45
+
46
+ async def refresh_db():
47
+ global DB_CACHE
48
+ DB_CACHE |= {"initialised": True, "cur_value": time.time()}
49
+
50
+
51
+ @contextlib.asynccontextmanager
52
+ async def lifespan(_app: FastAPI):
53
+ async with async_timer.Timer(delay=5, target=refresh_db) as timer:
54
+ await timer.wait(hit_count=1) # block until the timer triggers at least once
55
+ yield
56
+
57
+
58
+ app = FastAPI(lifespan=lifespan)
59
+
60
+
61
+ @app.get("/")
62
+ async def root():
63
+ return {"message": "Hello World", "db_cache": DB_CACHE}
64
+
65
+
66
+ if __name__ == "__main__":
67
+ uvicorn.run(app, host="0.0.0.0", port=8000)
68
+
69
+ ```
70
+
71
+ ### join()
29
72
  ```python
30
73
 
31
74
  import async_timer
32
75
 
33
- # Simple timer example
34
76
  timer = async_timer.Timer(12, target=lambda: 42)
35
77
  timer.start()
36
- val = await timer.join() # `val` will be 42 after 12 seconds
78
+ val = await timer.join() # `val` will be set to 42 after 12 seconds
79
+ ```
37
80
 
81
+ ### for loop
82
+ ```python
38
83
  # Async for loop example
84
+ import async_timer
39
85
  import time
40
86
  with async_timer.Timer(14, target=time.time) as timer:
41
87
  async for time_rv in timer:
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "async-timer"
3
- version = "v1.0.2"
3
+ version = "v1.0.3"
4
4
  description = "The missing Python async timer."
5
5
  authors = ["Ilya O. <vrghost@gmail.com>"]
6
6
  license = "MIT"
@@ -66,7 +66,7 @@ line-length = 88
66
66
 
67
67
  [tool.ruff.isort]
68
68
  order-by-type = true
69
- known-first-party = ["tc_rrf", ]
69
+ known-first-party = ["async_timer", ]
70
70
  forced-separate = ["tests"]
71
71
 
72
72
  [tool.black]
@@ -61,6 +61,7 @@ def _default_main_loop_exception_callback(*_, **__):
61
61
 
62
62
  class Timer(typing.Generic[T]):
63
63
  delay: float
64
+ hit_count: int = 0 # Number of times the timer has run so far
64
65
  target: TimerMainTaskT[T]
65
66
 
66
67
  result_fanout: FanoutRv[T]
@@ -111,6 +112,29 @@ class Timer(typing.Generic[T]):
111
112
  await self.result_fanout.wait()
112
113
  ) # this can raise `asyncio.CancelledError`
113
114
 
115
+ async def wait(
116
+ self, /, hit_count: int = None, hits: int = None
117
+ ) -> typing.Optional[T]:
118
+ """
119
+ Wait for the timer to reach certain hit count
120
+ or wait for a certain number of hits.
121
+
122
+ Returns the last generated result IF there was a need to wait.
123
+ Returns `None` otherwise.
124
+ """
125
+ if hit_count is not None:
126
+ target_hit_count = max(0, hit_count)
127
+ elif hits is not None:
128
+ target_hit_count = self.hit_count + max(0, hits)
129
+ else:
130
+ raise RuntimeError("Please provide either `hits` or `hit_count`")
131
+ need_to_wait_for = target_hit_count - self.hit_count
132
+ last_rv = None
133
+ while need_to_wait_for > 0:
134
+ last_rv = await self.join()
135
+ need_to_wait_for -= 1
136
+ return last_rv
137
+
114
138
  async def __anext__(self) -> T:
115
139
  try:
116
140
  return await self.join()
@@ -169,6 +193,7 @@ class Timer(typing.Generic[T]):
169
193
  else:
170
194
  await self.result_fanout.send_result(rv)
171
195
  first_iter = False
196
+ self.hit_count += 1
172
197
  await asyncio.sleep(self.delay)
173
198
  finally:
174
199
  # Main loop finished - cancel all watchers