cachier 3.4.0__py3-none-any.whl → 3.4.1__py3-none-any.whl

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.
cachier/cores/pickle.py CHANGED
@@ -6,8 +6,10 @@
6
6
  # Licensed under the MIT license:
7
7
  # http://www.opensource.org/licenses/MIT-license
8
8
  # Copyright (c) 2016, Shay Palachy <shaypal5@gmail.com>
9
+ import logging
9
10
  import os
10
11
  import pickle # for local caching
12
+ import time
11
13
  from datetime import datetime
12
14
  from typing import Any, Dict, Optional, Tuple, Union
13
15
 
@@ -51,12 +53,14 @@ class _PickleCore(_BaseCore):
51
53
  if not entry._processing:
52
54
  # print('stopping observer!')
53
55
  self.value = entry.value
54
- self.observer.stop()
56
+ if self.observer is not None:
57
+ self.observer.stop()
55
58
  # else:
56
59
  # print('NOT stopping observer... :(')
57
60
  except AttributeError: # catching entry being None
58
61
  self.value = None
59
- self.observer.stop()
62
+ if self.observer is not None:
63
+ self.observer.stop()
60
64
 
61
65
  def on_created(self, event) -> None:
62
66
  """A Watchdog Event Handler method.""" # noqa: D401
@@ -256,29 +260,93 @@ class _PickleCore(_BaseCore):
256
260
  cache[key]._processing = False
257
261
  self._save_cache(cache)
258
262
 
263
+ def _create_observer(self) -> Observer:
264
+ """Create a new observer instance."""
265
+ return Observer()
266
+
267
+ def _cleanup_observer(self, observer: Observer) -> None:
268
+ """Clean up observer properly."""
269
+ try:
270
+ if observer.is_alive():
271
+ observer.stop()
272
+ observer.join(timeout=1.0)
273
+ except Exception as e:
274
+ logging.debug("Observer cleanup failed: %s", e)
275
+
259
276
  def wait_on_entry_calc(self, key: str) -> Any:
277
+ """Wait for entry calculation to complete with inotify protection."""
260
278
  if self.separate_files:
261
279
  entry = self._load_cache_by_key(key)
262
280
  filename = f"{self.cache_fname}_{key}"
263
281
  else:
264
282
  with self.lock:
265
- entry = self.get_cache_dict()[key]
283
+ entry = self.get_cache_dict().get(key)
266
284
  filename = self.cache_fname
285
+
267
286
  if entry and not entry._processing:
268
287
  return entry.value
288
+
289
+ # Try to use inotify-based waiting
290
+ try:
291
+ return self._wait_with_inotify(key, filename)
292
+ except OSError as e:
293
+ if "inotify instance limit reached" in str(e):
294
+ # Fall back to polling if inotify limit is reached
295
+ return self._wait_with_polling(key)
296
+ else:
297
+ raise
298
+
299
+ def _wait_with_inotify(self, key: str, filename: str) -> Any:
300
+ """Wait for calculation using inotify with proper cleanup."""
269
301
  event_handler = _PickleCore.CacheChangeHandler(
270
302
  filename=filename, core=self, key=key
271
303
  )
272
- observer = Observer()
304
+
305
+ observer = self._create_observer()
273
306
  event_handler.inject_observer(observer)
274
- observer.schedule(event_handler, path=self.cache_dir, recursive=True)
275
- observer.start()
307
+
308
+ try:
309
+ observer.schedule(
310
+ event_handler, path=self.cache_dir, recursive=True
311
+ )
312
+ observer.start()
313
+
314
+ time_spent = 0
315
+ while observer.is_alive():
316
+ observer.join(timeout=1.0)
317
+ time_spent += 1
318
+ self.check_calc_timeout(time_spent)
319
+
320
+ # Check if calculation is complete
321
+ if event_handler.value is not None:
322
+ break
323
+
324
+ return event_handler.value
325
+ finally:
326
+ # Always cleanup the observer
327
+ self._cleanup_observer(observer)
328
+
329
+ def _wait_with_polling(self, key: str) -> Any:
330
+ """Fallback method using polling instead of inotify."""
276
331
  time_spent = 0
277
- while observer.is_alive():
278
- observer.join(timeout=1.0)
332
+ while True:
333
+ time.sleep(1) # Poll every 1 second (matching other cores)
279
334
  time_spent += 1
280
- self.check_calc_timeout(time_spent)
281
- return event_handler.value
335
+
336
+ try:
337
+ if self.separate_files:
338
+ entry = self._load_cache_by_key(key)
339
+ else:
340
+ with self.lock:
341
+ entry = self.get_cache_dict().get(key)
342
+
343
+ if entry and not entry._processing:
344
+ return entry.value
345
+
346
+ self.check_calc_timeout(time_spent)
347
+ except (FileNotFoundError, EOFError):
348
+ # Continue polling even if there are file errors
349
+ pass
282
350
 
283
351
  def clear_cache(self) -> None:
284
352
  if self.separate_files:
cachier/version.info CHANGED
@@ -1 +1 @@
1
- 3.4.0
1
+ 3.4.1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cachier
3
- Version: 3.4.0
3
+ Version: 3.4.1
4
4
  Summary: Persistent, stale-free, local and cross-machine caching for Python functions.
5
5
  Author-email: Shay Palachy Affek <shay.palachy@gmail.com>
6
6
  License: MIT License
@@ -5,17 +5,17 @@ cachier/_version.py,sha256=jnPPRn_qmjNi-qmQjlHnzNGf3LSBTYkMmJdGjxMTOBM,1089
5
5
  cachier/config.py,sha256=6hyQtn9T6UXu2UQhKJltWT0Nu4OBS4ION1x7Lt1i8Og,3838
6
6
  cachier/core.py,sha256=W1O_a9rkgsErG3spVPZpnfRu9k0MbV94rGkv79KDgBA,16243
7
7
  cachier/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- cachier/version.info,sha256=9ePpPlj_wqIKPKU-gCW8UNfB3MvvSzTiOIqpu_hnhGY,6
8
+ cachier/version.info,sha256=zHFPXgIkp4MR9INen7uI5pujX2Xn3Vy32GyrtKhLvXI,6
9
9
  cachier/cores/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  cachier/cores/base.py,sha256=s7qgmDJA4LGub6ydGfMk9vVJW4fgeU0EXl-9gmpuh28,3683
11
11
  cachier/cores/memory.py,sha256=fsvqq9rwwmAaMBvYo-oUNAxB6UOyfBpuf8ACW_XTaU0,3572
12
12
  cachier/cores/mongo.py,sha256=wVit36jQeNkP1KyxMtm6jDglazpdORYzTOPJ0q10BWI,4979
13
- cachier/cores/pickle.py,sha256=FuEl2i_U4Q3k9JUs4ylJqM3n7BVY6cXEqKmdW56AEDg,10650
13
+ cachier/cores/pickle.py,sha256=L_IwKSnskJqlGsulkhMQukKdylq_ghpyG5BvdB_7WzM,12901
14
14
  cachier/cores/redis.py,sha256=rWrkEwWPzfFvH1eLkgBdhzxqPtJtx6N_sYcqRPy_P9Y,7553
15
15
  cachier/cores/sql.py,sha256=nuf2-Szo7VTPRa7IC3JGWEtGsBtdkIrx0bhOm3U0mfE,9895
16
- cachier-3.4.0.dist-info/licenses/LICENSE,sha256=-2WrMJkIa0gVP6YQHXXDT7ws-S3M2NEVEF4XF3K8qrY,1069
17
- cachier-3.4.0.dist-info/METADATA,sha256=V409D2EKlPVNAEf_uAzJDIJCQQJjzyoE_g1FnjaSnzs,24446
18
- cachier-3.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
- cachier-3.4.0.dist-info/entry_points.txt,sha256=x4Y7t6Y0Qev_3fgG-Jv7TrsvVdJty3FnGAdkT8-_5mY,49
20
- cachier-3.4.0.dist-info/top_level.txt,sha256=_rW_HiJumDCch67YT-WAgzcyvKg5RiYDMZq9d-0ZpaE,8
21
- cachier-3.4.0.dist-info/RECORD,,
16
+ cachier-3.4.1.dist-info/licenses/LICENSE,sha256=-2WrMJkIa0gVP6YQHXXDT7ws-S3M2NEVEF4XF3K8qrY,1069
17
+ cachier-3.4.1.dist-info/METADATA,sha256=__yRE190T79aUMOS9uaXSWj8q-YJp-3LpwLoLpOZxt8,24446
18
+ cachier-3.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
+ cachier-3.4.1.dist-info/entry_points.txt,sha256=x4Y7t6Y0Qev_3fgG-Jv7TrsvVdJty3FnGAdkT8-_5mY,49
20
+ cachier-3.4.1.dist-info/top_level.txt,sha256=_rW_HiJumDCch67YT-WAgzcyvKg5RiYDMZq9d-0ZpaE,8
21
+ cachier-3.4.1.dist-info/RECORD,,