pelutils 4.3.1__tar.gz → 4.4.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.
Files changed (66) hide show
  1. {pelutils-4.3.1 → pelutils-4.4.0}/PKG-INFO +1 -1
  2. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/__version__.py +1 -1
  3. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/ticktock/__init__.py +2 -2
  4. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/ticktock/_ticktock.py +52 -7
  5. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils.egg-info/PKG-INFO +1 -1
  6. {pelutils-4.3.1 → pelutils-4.4.0}/MANIFEST.in +0 -0
  7. {pelutils-4.3.1 → pelutils-4.4.0}/README.md +0 -0
  8. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/__init__.py +0 -0
  9. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/_c/__init__.py +0 -0
  10. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/_c/array/blob.c +0 -0
  11. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/_c/array/blob.h +0 -0
  12. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/_c/array/unique.c +0 -0
  13. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/_c/array/unique.h +0 -0
  14. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/_c/deque/deque.c +0 -0
  15. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/_c/deque/deque.h +0 -0
  16. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/_c/hashmap/LICENSE +0 -0
  17. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/_c/hashmap/hashmap.c +0 -0
  18. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/_c/hashmap/hashmap.h +0 -0
  19. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/_c/pelutils.c +0 -0
  20. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/_c/types.h +0 -0
  21. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/_entry_points/__init__.py +0 -0
  22. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/_entry_points/linecounter.py +0 -0
  23. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/array/__init__.py +0 -0
  24. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/array/_blob.py +0 -0
  25. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/array/_unique.py +0 -0
  26. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/array/_utils.py +0 -0
  27. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/job_parser/__init__.py +0 -0
  28. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/job_parser/_job_parser.py +0 -0
  29. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/job_parser/_structs.py +0 -0
  30. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/legacy/__init__.py +0 -0
  31. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/legacy/v3/__init__.py +0 -0
  32. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/legacy/v3/_datastorage.py +0 -0
  33. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/logging/__init__.py +0 -0
  34. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/logging/_logger.py +0 -0
  35. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/logging/_rich_string.py +0 -0
  36. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/logging/_rotate.py +0 -0
  37. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/misc/__init__.py +0 -0
  38. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/misc/_conditional_import.py +0 -0
  39. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/misc/_files.py +0 -0
  40. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/misc/_git.py +0 -0
  41. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/misc/_misc.py +0 -0
  42. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/misc/_platform.py +0 -0
  43. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/misc/_table.py +0 -0
  44. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/plots/__init__.py +0 -0
  45. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/plots/_figure.py +0 -0
  46. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/plots/_histogram.py +0 -0
  47. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/plots/_utils.py +0 -0
  48. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/py.typed +0 -0
  49. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/serialization/__init__.py +0 -0
  50. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/serialization/_jsonl.py +0 -0
  51. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/serialization/_pretty_json.py +0 -0
  52. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/serialization/_universal_json_model.py +0 -0
  53. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/stats/__init__.py +0 -0
  54. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/stats/_distributions.py +0 -0
  55. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/stats/_stats.py +0 -0
  56. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/tests/__init__.py +0 -0
  57. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/tests/_tests.py +0 -0
  58. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/types/__init__.py +0 -0
  59. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils/types/_types.py +0 -0
  60. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils.egg-info/SOURCES.txt +0 -0
  61. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils.egg-info/dependency_links.txt +0 -0
  62. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils.egg-info/entry_points.txt +0 -0
  63. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils.egg-info/requires.txt +0 -0
  64. {pelutils-4.3.1 → pelutils-4.4.0}/pelutils.egg-info/top_level.txt +0 -0
  65. {pelutils-4.3.1 → pelutils-4.4.0}/setup.cfg +0 -0
  66. {pelutils-4.3.1 → pelutils-4.4.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pelutils
3
- Version: 4.3.1
3
+ Version: 4.4.0
4
4
  Summary: The Swiss army knife of Python projects
5
5
  Home-page: https://github.com/peleiden/pelutils
6
6
  Download-URL: https://pypi.org/project/pelutils/
@@ -1,2 +1,2 @@
1
1
  # Do not put anything else in this file
2
- __version__ = "4.3.1"
2
+ __version__ = "4.4.0"
@@ -37,6 +37,6 @@ periodic tasks, and ``fuse``/``fuse_multiple`` for combining results across
37
37
  processes.
38
38
  """
39
39
 
40
- from ._ticktock import TT, Profile, TickTock, TickTockException
40
+ from ._ticktock import TT, Profile, TickTock, TickTockException, get_active_ticktock
41
41
 
42
- __all__ = ("TT", "Profile", "TickTock", "TickTockException")
42
+ __all__ = ("TT", "Profile", "TickTock", "TickTockException", "get_active_ticktock")
@@ -1,8 +1,9 @@
1
+ import itertools
2
+ import threading
1
3
  import warnings
2
4
  from collections.abc import Hashable, Iterable, Iterator, Sequence
3
5
  from contextlib import contextmanager
4
6
  from copy import deepcopy
5
- from threading import current_thread
6
7
  from time import perf_counter
7
8
  from typing import TypeAlias, TypeVar, cast
8
9
 
@@ -23,6 +24,20 @@ _time_units: tuple[_TimeUnit, ...] = (
23
24
 
24
25
  T = TypeVar("T")
25
26
 
27
+ _lock = threading.RLock()
28
+ _active_ticktocks: "dict[int, TickTock]" = dict()
29
+ _ids = itertools.count()
30
+ _ids_lock = threading.RLock()
31
+ _local_thread = threading.local()
32
+
33
+
34
+ def _get_thread_uid() -> int:
35
+ """Return a stable, program-lifetime-unique ID for the calling thread."""
36
+ if not hasattr(_local_thread, "__ticktock_uid__"):
37
+ with _ids_lock:
38
+ _local_thread.__ticktock_uid__ = next(_ids)
39
+ return _local_thread.__ticktock_uid__
40
+
26
41
 
27
42
  def _get_smallest_suitable_unit(duration_s: float) -> _TimeUnit:
28
43
  """Return the smallest unit for which the duration is at least the same size as the unit."""
@@ -160,8 +175,8 @@ class TickTock:
160
175
  self._profile_stack: list[Profile] = list() # LIFO stack of active profiles
161
176
  self._root_profiles: list[Profile] = list() # Top level profiles
162
177
 
163
- self._thread_name = current_thread().name
164
- self._thread_id = id(current_thread())
178
+ self._thread_name = threading.current_thread().name
179
+ self._thread_id = _get_thread_uid()
165
180
 
166
181
  def tick(self, key: Hashable = None):
167
182
  """Start a timer identified by an optional hashable key."""
@@ -244,10 +259,10 @@ class TickTock:
244
259
  self._end_profile()
245
260
 
246
261
  def _warn_if_wrong_thread(self, *, stacklevel: int):
247
- if self._thread_id != id(current_thread()):
262
+ if self._thread_id != _get_thread_uid():
248
263
  warnings.warn(
249
264
  f"This TickTock instance was created in the {self._thread_name} thread but profiling was started in "
250
- + f"{current_thread().name}. Profiling is NOT designed to deal with multiple threads. Instead, create a "
265
+ + f"{threading.current_thread().name}. Profiling is NOT designed to deal with multiple threads. Instead, create a "
251
266
  + "TickTock instance for each thread requiring profiling.",
252
267
  stacklevel=stacklevel,
253
268
  )
@@ -393,8 +408,8 @@ class TickTock:
393
408
  raise ValueError("Some TickTocks are the same instance, which is not allowed")
394
409
  for tt in tts[1:]:
395
410
  ticktock.fuse(tt)
396
- ticktock._thread_name = current_thread().name
397
- ticktock._thread_id = id(current_thread())
411
+ ticktock._thread_name = threading.current_thread().name
412
+ ticktock._thread_id = _get_thread_uid()
398
413
  return ticktock
399
414
 
400
415
  @staticmethod
@@ -446,5 +461,35 @@ class TickTock:
446
461
  """Return True if any profiling has been performed."""
447
462
  return len(self._root_profiles) > 0
448
463
 
464
+ @contextmanager
465
+ def as_active(self):
466
+ """Set the ``TickTock`` instance as the active instance in the current thread.
467
+
468
+ It can then be retrieved with :func:`get_active_ticktock`.
469
+ """
470
+ current_thread_id = _get_thread_uid()
471
+ with _lock:
472
+ if current_thread_id in _active_ticktocks:
473
+ raise TickTockException(f"An active TickTock instance has already been set in thread {threading.current_thread().name}")
474
+ _active_ticktocks[current_thread_id] = self
475
+ try:
476
+ yield
477
+ finally:
478
+ with _lock:
479
+ del _active_ticktocks[current_thread_id]
480
+
481
+
482
+ def get_active_ticktock() -> TickTock:
483
+ """Return the active ``TickTock`` instance in the current thread (as set by :meth:`TickTock.as_active`).
484
+
485
+ If no active ``TickTock`` is set, a new ``TickTock`` instance is returned.
486
+ This allows normal profiling usage without having to care if it's actually used or not.
487
+ """
488
+ with _lock:
489
+ ticktock = _active_ticktocks.get(_get_thread_uid())
490
+ return ticktock if ticktock is not None else TickTock()
491
+
449
492
 
493
+ # Globally accessible default instance
494
+ # It suffices to use this for most cases
450
495
  TT = TickTock()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pelutils
3
- Version: 4.3.1
3
+ Version: 4.4.0
4
4
  Summary: The Swiss army knife of Python projects
5
5
  Home-page: https://github.com/peleiden/pelutils
6
6
  Download-URL: https://pypi.org/project/pelutils/
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes