ez-a-sync 0.33.4__cp313-cp313-musllinux_1_2_i686.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.
Files changed (177) hide show
  1. a_sync/ENVIRONMENT_VARIABLES.py +42 -0
  2. a_sync/__init__.pxd +2 -0
  3. a_sync/__init__.py +145 -0
  4. a_sync/_smart.c +22830 -0
  5. a_sync/_smart.cpython-313-i386-linux-musl.so +0 -0
  6. a_sync/_smart.pxd +2 -0
  7. a_sync/_smart.pyi +202 -0
  8. a_sync/_smart.pyx +674 -0
  9. a_sync/_typing.py +258 -0
  10. a_sync/a_sync/__init__.py +60 -0
  11. a_sync/a_sync/_descriptor.c +20537 -0
  12. a_sync/a_sync/_descriptor.cpython-313-i386-linux-musl.so +0 -0
  13. a_sync/a_sync/_descriptor.pyi +33 -0
  14. a_sync/a_sync/_descriptor.pyx +422 -0
  15. a_sync/a_sync/_flags.c +6082 -0
  16. a_sync/a_sync/_flags.cpython-313-i386-linux-musl.so +0 -0
  17. a_sync/a_sync/_flags.pxd +3 -0
  18. a_sync/a_sync/_flags.pyx +92 -0
  19. a_sync/a_sync/_helpers.c +14529 -0
  20. a_sync/a_sync/_helpers.cpython-313-i386-linux-musl.so +0 -0
  21. a_sync/a_sync/_helpers.pxd +3 -0
  22. a_sync/a_sync/_helpers.pyi +10 -0
  23. a_sync/a_sync/_helpers.pyx +167 -0
  24. a_sync/a_sync/_kwargs.c +12202 -0
  25. a_sync/a_sync/_kwargs.cpython-313-i386-linux-musl.so +0 -0
  26. a_sync/a_sync/_kwargs.pxd +2 -0
  27. a_sync/a_sync/_kwargs.pyx +64 -0
  28. a_sync/a_sync/_meta.py +210 -0
  29. a_sync/a_sync/abstract.c +12420 -0
  30. a_sync/a_sync/abstract.cpython-313-i386-linux-musl.so +0 -0
  31. a_sync/a_sync/abstract.pyi +141 -0
  32. a_sync/a_sync/abstract.pyx +221 -0
  33. a_sync/a_sync/base.c +14940 -0
  34. a_sync/a_sync/base.cpython-313-i386-linux-musl.so +0 -0
  35. a_sync/a_sync/base.pyi +60 -0
  36. a_sync/a_sync/base.pyx +271 -0
  37. a_sync/a_sync/config.py +168 -0
  38. a_sync/a_sync/decorator.py +651 -0
  39. a_sync/a_sync/flags.c +5272 -0
  40. a_sync/a_sync/flags.cpython-313-i386-linux-musl.so +0 -0
  41. a_sync/a_sync/flags.pxd +72 -0
  42. a_sync/a_sync/flags.pyi +74 -0
  43. a_sync/a_sync/flags.pyx +72 -0
  44. a_sync/a_sync/function.c +37856 -0
  45. a_sync/a_sync/function.cpython-313-i386-linux-musl.so +0 -0
  46. a_sync/a_sync/function.pxd +28 -0
  47. a_sync/a_sync/function.pyi +571 -0
  48. a_sync/a_sync/function.pyx +1381 -0
  49. a_sync/a_sync/method.c +29662 -0
  50. a_sync/a_sync/method.cpython-313-i386-linux-musl.so +0 -0
  51. a_sync/a_sync/method.pxd +9 -0
  52. a_sync/a_sync/method.pyi +523 -0
  53. a_sync/a_sync/method.pyx +1023 -0
  54. a_sync/a_sync/modifiers/__init__.pxd +1 -0
  55. a_sync/a_sync/modifiers/__init__.py +101 -0
  56. a_sync/a_sync/modifiers/cache/__init__.py +160 -0
  57. a_sync/a_sync/modifiers/cache/memory.py +165 -0
  58. a_sync/a_sync/modifiers/limiter.py +132 -0
  59. a_sync/a_sync/modifiers/manager.c +16157 -0
  60. a_sync/a_sync/modifiers/manager.cpython-313-i386-linux-musl.so +0 -0
  61. a_sync/a_sync/modifiers/manager.pxd +5 -0
  62. a_sync/a_sync/modifiers/manager.pyi +219 -0
  63. a_sync/a_sync/modifiers/manager.pyx +299 -0
  64. a_sync/a_sync/modifiers/semaphores.py +173 -0
  65. a_sync/a_sync/property.c +27268 -0
  66. a_sync/a_sync/property.cpython-313-i386-linux-musl.so +0 -0
  67. a_sync/a_sync/property.pyi +376 -0
  68. a_sync/a_sync/property.pyx +819 -0
  69. a_sync/a_sync/singleton.py +63 -0
  70. a_sync/aliases.py +3 -0
  71. a_sync/async_property/__init__.pxd +1 -0
  72. a_sync/async_property/__init__.py +1 -0
  73. a_sync/async_property/cached.c +20397 -0
  74. a_sync/async_property/cached.cpython-313-i386-linux-musl.so +0 -0
  75. a_sync/async_property/cached.pxd +10 -0
  76. a_sync/async_property/cached.pyi +45 -0
  77. a_sync/async_property/cached.pyx +178 -0
  78. a_sync/async_property/proxy.c +34662 -0
  79. a_sync/async_property/proxy.cpython-313-i386-linux-musl.so +0 -0
  80. a_sync/async_property/proxy.pxd +2 -0
  81. a_sync/async_property/proxy.pyi +124 -0
  82. a_sync/async_property/proxy.pyx +474 -0
  83. a_sync/asyncio/__init__.pxd +6 -0
  84. a_sync/asyncio/__init__.py +164 -0
  85. a_sync/asyncio/as_completed.c +18849 -0
  86. a_sync/asyncio/as_completed.cpython-313-i386-linux-musl.so +0 -0
  87. a_sync/asyncio/as_completed.pxd +8 -0
  88. a_sync/asyncio/as_completed.pyi +109 -0
  89. a_sync/asyncio/as_completed.pyx +269 -0
  90. a_sync/asyncio/create_task.c +15912 -0
  91. a_sync/asyncio/create_task.cpython-313-i386-linux-musl.so +0 -0
  92. a_sync/asyncio/create_task.pxd +2 -0
  93. a_sync/asyncio/create_task.pyi +51 -0
  94. a_sync/asyncio/create_task.pyx +271 -0
  95. a_sync/asyncio/gather.c +16687 -0
  96. a_sync/asyncio/gather.cpython-313-i386-linux-musl.so +0 -0
  97. a_sync/asyncio/gather.pyi +107 -0
  98. a_sync/asyncio/gather.pyx +218 -0
  99. a_sync/asyncio/igather.c +13080 -0
  100. a_sync/asyncio/igather.cpython-313-i386-linux-musl.so +0 -0
  101. a_sync/asyncio/igather.pxd +1 -0
  102. a_sync/asyncio/igather.pyi +8 -0
  103. a_sync/asyncio/igather.pyx +183 -0
  104. a_sync/asyncio/sleep.c +9601 -0
  105. a_sync/asyncio/sleep.cpython-313-i386-linux-musl.so +0 -0
  106. a_sync/asyncio/sleep.pyi +14 -0
  107. a_sync/asyncio/sleep.pyx +49 -0
  108. a_sync/debugging.c +15370 -0
  109. a_sync/debugging.cpython-313-i386-linux-musl.so +0 -0
  110. a_sync/debugging.pyi +76 -0
  111. a_sync/debugging.pyx +107 -0
  112. a_sync/exceptions.c +13320 -0
  113. a_sync/exceptions.cpython-313-i386-linux-musl.so +0 -0
  114. a_sync/exceptions.pyi +376 -0
  115. a_sync/exceptions.pyx +446 -0
  116. a_sync/executor.py +619 -0
  117. a_sync/functools.c +12746 -0
  118. a_sync/functools.cpython-313-i386-linux-musl.so +0 -0
  119. a_sync/functools.pxd +7 -0
  120. a_sync/functools.pyi +33 -0
  121. a_sync/functools.pyx +139 -0
  122. a_sync/future.py +1497 -0
  123. a_sync/iter.c +37279 -0
  124. a_sync/iter.cpython-313-i386-linux-musl.so +0 -0
  125. a_sync/iter.pxd +11 -0
  126. a_sync/iter.pyi +370 -0
  127. a_sync/iter.pyx +981 -0
  128. a_sync/primitives/__init__.pxd +1 -0
  129. a_sync/primitives/__init__.py +53 -0
  130. a_sync/primitives/_debug.c +15765 -0
  131. a_sync/primitives/_debug.cpython-313-i386-linux-musl.so +0 -0
  132. a_sync/primitives/_debug.pxd +12 -0
  133. a_sync/primitives/_debug.pyi +52 -0
  134. a_sync/primitives/_debug.pyx +223 -0
  135. a_sync/primitives/_loggable.c +11538 -0
  136. a_sync/primitives/_loggable.cpython-313-i386-linux-musl.so +0 -0
  137. a_sync/primitives/_loggable.pxd +4 -0
  138. a_sync/primitives/_loggable.pyi +66 -0
  139. a_sync/primitives/_loggable.pyx +102 -0
  140. a_sync/primitives/locks/__init__.pxd +8 -0
  141. a_sync/primitives/locks/__init__.py +17 -0
  142. a_sync/primitives/locks/counter.c +17938 -0
  143. a_sync/primitives/locks/counter.cpython-313-i386-linux-musl.so +0 -0
  144. a_sync/primitives/locks/counter.pxd +12 -0
  145. a_sync/primitives/locks/counter.pyi +151 -0
  146. a_sync/primitives/locks/counter.pyx +267 -0
  147. a_sync/primitives/locks/event.c +17072 -0
  148. a_sync/primitives/locks/event.cpython-313-i386-linux-musl.so +0 -0
  149. a_sync/primitives/locks/event.pxd +22 -0
  150. a_sync/primitives/locks/event.pyi +43 -0
  151. a_sync/primitives/locks/event.pyx +185 -0
  152. a_sync/primitives/locks/prio_semaphore.c +25635 -0
  153. a_sync/primitives/locks/prio_semaphore.cpython-313-i386-linux-musl.so +0 -0
  154. a_sync/primitives/locks/prio_semaphore.pxd +25 -0
  155. a_sync/primitives/locks/prio_semaphore.pyi +217 -0
  156. a_sync/primitives/locks/prio_semaphore.pyx +597 -0
  157. a_sync/primitives/locks/semaphore.c +26553 -0
  158. a_sync/primitives/locks/semaphore.cpython-313-i386-linux-musl.so +0 -0
  159. a_sync/primitives/locks/semaphore.pxd +21 -0
  160. a_sync/primitives/locks/semaphore.pyi +197 -0
  161. a_sync/primitives/locks/semaphore.pyx +454 -0
  162. a_sync/primitives/queue.py +1026 -0
  163. a_sync/py.typed +0 -0
  164. a_sync/sphinx/__init__.py +3 -0
  165. a_sync/sphinx/ext.py +289 -0
  166. a_sync/task.py +934 -0
  167. a_sync/utils/__init__.py +105 -0
  168. a_sync/utils/iterators.py +297 -0
  169. a_sync/utils/repr.c +15866 -0
  170. a_sync/utils/repr.cpython-313-i386-linux-musl.so +0 -0
  171. a_sync/utils/repr.pyi +2 -0
  172. a_sync/utils/repr.pyx +73 -0
  173. ez_a_sync-0.33.4.dist-info/METADATA +368 -0
  174. ez_a_sync-0.33.4.dist-info/RECORD +177 -0
  175. ez_a_sync-0.33.4.dist-info/WHEEL +5 -0
  176. ez_a_sync-0.33.4.dist-info/licenses/LICENSE.txt +17 -0
  177. ez_a_sync-0.33.4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2 @@
1
+ cdef str get_flag_name(dict kwargs)
2
+ cdef bint is_sync(str flag, dict kwargs, bint pop_flag)
@@ -0,0 +1,64 @@
1
+ # cython: boundscheck=False
2
+ """
3
+ This module provides utility functions for handling keyword arguments related to synchronous and asynchronous flags.
4
+ """
5
+
6
+ from a_sync import exceptions
7
+ from a_sync.a_sync._flags cimport validate_and_negate_if_necessary
8
+ from a_sync.a_sync.flags cimport VIABLE_FLAGS
9
+
10
+ # cdef exceptions
11
+ cdef object TooManyFlags = exceptions.TooManyFlags
12
+ del exceptions
13
+
14
+
15
+ def _get_flag_name(dict kwargs) -> str:
16
+ return get_flag_name(kwargs)
17
+
18
+
19
+ cdef inline str get_flag_name(dict kwargs):
20
+ """
21
+ Get the name of the flag present in the kwargs.
22
+
23
+ Args:
24
+ kwargs: A dictionary of keyword arguments.
25
+
26
+ Returns:
27
+ The name of the flag if present, an empty string otherwise.
28
+
29
+ Raises:
30
+ :class:`exceptions.TooManyFlags`: If more than one flag is present in the kwargs,
31
+ the exception includes the message "kwargs" and the list of present flags.
32
+
33
+ Examples:
34
+ >>> get_flag_name({'sync': True})
35
+ 'sync'
36
+
37
+ >>> get_flag_name({'asynchronous': False})
38
+ 'asynchronous'
39
+
40
+ >>> get_flag_name({})
41
+ ''
42
+ """
43
+ cdef object present_flags = iter(flag for flag in VIABLE_FLAGS if flag in kwargs)
44
+ cdef str flag = next(present_flags, None)
45
+ if flag is None:
46
+ return "" # indicates no flag is present
47
+ if next(present_flags, None) is None:
48
+ return flag
49
+ raise TooManyFlags("kwargs", present_flags)
50
+
51
+
52
+ cdef inline bint is_sync(str flag, dict kwargs, bint pop_flag):
53
+ """
54
+ Determine if the operation should be synchronous based on the flag value.
55
+
56
+ Args:
57
+ flag (str): The name of the flag to check.
58
+ kwargs (dict): A dictionary of keyword arguments.
59
+ pop_flag (bool, optional): Whether to remove the flag from kwargs. Defaults to False.
60
+
61
+ See Also:
62
+ :func:`get_flag_name`: Retrieves the name of the flag present in the kwargs.
63
+ """
64
+ return validate_and_negate_if_necessary(flag, kwargs.pop(flag) if pop_flag else kwargs[flag])
a_sync/a_sync/_meta.py ADDED
@@ -0,0 +1,210 @@
1
+ import logging
2
+ import threading
3
+ from abc import ABCMeta
4
+ from inspect import isasyncgenfunction
5
+ from typing import Any, Dict, Tuple
6
+
7
+ from a_sync import ENVIRONMENT_VARIABLES
8
+ from a_sync.a_sync import modifiers
9
+ from a_sync.a_sync.function import _ASyncFunction, _ModifiedMixin
10
+ from a_sync.a_sync.method import ASyncMethodDescriptor
11
+ from a_sync.a_sync.property import (
12
+ ASyncCachedPropertyDescriptor,
13
+ ASyncPropertyDescriptor,
14
+ )
15
+ from a_sync.future import _ASyncFutureWrappedFn # type: ignore [attr-defined]
16
+ from a_sync.iter import ASyncGeneratorFunction
17
+ from a_sync.primitives.locks.semaphore import Semaphore
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ class ASyncMeta(ABCMeta):
23
+ """Metaclass for wrapping class attributes with asynchronous capabilities.
24
+
25
+ Any class with `ASyncMeta` as its metaclass will have its functions and properties
26
+ wrapped with asynchronous capabilities upon class instantiation. This includes
27
+ wrapping functions with :class:`~a_sync.a_sync.method.ASyncMethodDescriptor` and properties with
28
+ :class:`~a_sync.a_sync.property.ASyncPropertyDescriptor` or :class:`~a_sync.a_sync.property.ASyncCachedPropertyDescriptor`.
29
+ It also handles attributes that are instances of :class:`~a_sync.a_sync.function.ASyncFunction`,
30
+ which are used when functions are decorated with a_sync decorators to apply specific modifiers to those functions.
31
+
32
+ Attributes that are instances of :class:`~a_sync.future._ASyncFutureWrappedFn` and :class:`~a_sync.primitives.locks.semaphore.Semaphore`
33
+ are explicitly skipped and not wrapped.
34
+
35
+ Example:
36
+ To create a class with asynchronous capabilities, define your class with `ASyncMeta` as its metaclass:
37
+
38
+ >>> class MyClass(metaclass=ASyncMeta):
39
+ ... def my_method(self):
40
+ ... return "Hello, World!"
41
+
42
+ The `my_method` function will be wrapped with :class:`~a_sync.a_sync.method.ASyncMethodDescriptor`, allowing it to be used asynchronously.
43
+
44
+ See Also:
45
+ - :class:`~a_sync.a_sync.function.ASyncFunction`
46
+ - :class:`~a_sync.a_sync.method.ASyncMethodDescriptor`
47
+ - :class:`~a_sync.a_sync.property.ASyncPropertyDescriptor`
48
+ - :class:`~a_sync.a_sync.property.ASyncCachedPropertyDescriptor`
49
+ """
50
+
51
+ def __new__(cls, new_class_name, bases, attrs):
52
+ _update_logger(new_class_name)
53
+ logger.debug(
54
+ "woah, you're defining a new ASync class `%s`! let's walk thru it together",
55
+ new_class_name,
56
+ )
57
+ logger.debug(
58
+ "first, I check whether you've defined any modifiers on `%s`",
59
+ new_class_name,
60
+ )
61
+ # NOTE: Open quesion: what do we do when a parent class and subclass define the same modifier differently?
62
+ # Currently the parent value is used for functions defined on the parent,
63
+ # and the subclass value is used for functions defined on the subclass.
64
+ class_defined_modifiers = modifiers.get_modifiers_from(attrs)
65
+
66
+ logger.debug("found modifiers: %s", class_defined_modifiers)
67
+ logger.debug(
68
+ "now I inspect the class definition to figure out which attributes need to be wrapped"
69
+ )
70
+ for attr_name, attr_value in list(attrs.items()):
71
+ if attr_name.startswith("_"):
72
+ logger.debug(
73
+ "`%s.%s` starts with an underscore, skipping",
74
+ new_class_name,
75
+ attr_name,
76
+ )
77
+ continue
78
+ elif "__" in attr_name:
79
+ logger.debug(
80
+ "`%s.%s` incluldes a double-underscore, skipping",
81
+ new_class_name,
82
+ attr_name,
83
+ )
84
+ continue
85
+ elif isinstance(attr_value, (_ASyncFutureWrappedFn, Semaphore)):
86
+ logger.debug(
87
+ "`%s.%s` is a %s, skipping",
88
+ new_class_name,
89
+ attr_name,
90
+ attr_value.__class__.__name__,
91
+ )
92
+ continue
93
+ logger.debug(
94
+ f"inspecting `{new_class_name}.{attr_name}` of type {attr_value.__class__.__name__}"
95
+ )
96
+ fn_modifiers = dict(class_defined_modifiers)
97
+ # Special handling for functions decorated with a_sync decorators
98
+ if isinstance(attr_value, _ModifiedMixin):
99
+ logger.debug(
100
+ "`%s.%s` is a `%s` object, which means you decorated it with an a_sync decorator even though `%s` is an ASyncABC class",
101
+ new_class_name,
102
+ attr_name,
103
+ type(attr_value).__name__,
104
+ new_class_name,
105
+ )
106
+ logger.debug(
107
+ "you probably did this so you could apply some modifiers to `%s` specifically",
108
+ attr_name,
109
+ )
110
+ if modified_modifiers := attr_value.modifiers._modifiers:
111
+ logger.debug(
112
+ "I found `%s.%s` is modified with %s",
113
+ new_class_name,
114
+ attr_name,
115
+ modified_modifiers,
116
+ )
117
+ fn_modifiers.update(modified_modifiers)
118
+ else:
119
+ logger.debug("I did not find any modifiers")
120
+ logger.debug(
121
+ "full modifier set for `%s.%s`: %s",
122
+ new_class_name,
123
+ attr_name,
124
+ fn_modifiers,
125
+ )
126
+ if isinstance(attr_value, (ASyncPropertyDescriptor, ASyncCachedPropertyDescriptor)):
127
+ # Wrap property
128
+ logger.debug("`%s is a property, now let's wrap it", attr_name)
129
+ logger.debug(
130
+ "since `%s` is a property, we will add a hidden dundermethod so you can still access it both sync and async",
131
+ attr_name,
132
+ )
133
+ attrs[attr_value.hidden_method_name] = attr_value.hidden_method_descriptor
134
+ logger.debug(
135
+ "`%s.%s` is now %s",
136
+ new_class_name,
137
+ attr_value.hidden_method_name,
138
+ attr_value.hidden_method_descriptor,
139
+ )
140
+ elif isinstance(attr_value, _ASyncFunction):
141
+ attrs[attr_name] = ASyncMethodDescriptor(attr_value, **fn_modifiers)
142
+ else:
143
+ raise NotImplementedError(attr_name, attr_value)
144
+ elif isasyncgenfunction(attr_value):
145
+ attrs[attr_name] = ASyncGeneratorFunction(attr_value)
146
+ elif callable(attr_value):
147
+ # NOTE We will need to improve this logic if somebody needs to use it with classmethods or staticmethods.
148
+ attrs[attr_name] = ASyncMethodDescriptor(attr_value, **fn_modifiers)
149
+ else:
150
+ logger.debug(
151
+ "`%s.%s` is not callable, we will take no action with it",
152
+ new_class_name,
153
+ attr_name,
154
+ )
155
+ return super(ASyncMeta, cls).__new__(cls, new_class_name, bases, attrs)
156
+
157
+
158
+ class ASyncSingletonMeta(ASyncMeta):
159
+ """Metaclass for creating singleton instances with asynchronous capabilities.
160
+
161
+ This metaclass extends :class:`~a_sync.a_sync._meta.ASyncMeta` to ensure that only one instance of a class
162
+ is created for each synchronous or asynchronous context.
163
+
164
+ Example:
165
+ To create a singleton class with asynchronous capabilities, define your class with `ASyncSingletonMeta` as its metaclass:
166
+
167
+ >>> class MySingleton(metaclass=ASyncSingletonMeta):
168
+ ... def __init__(self):
169
+ ... print("Instance created")
170
+
171
+ The `MySingleton` class will ensure that only one instance is created for each context.
172
+
173
+ See Also:
174
+ - :class:`~a_sync.a_sync._meta.ASyncMeta`
175
+ """
176
+
177
+ def __init__(cls, name: str, bases: Tuple[type, ...], namespace: Dict[str, Any]) -> None:
178
+ cls.__instances: Dict[bool, object] = {}
179
+ """Dictionary to store singleton instances."""
180
+ cls.__lock = threading.Lock()
181
+ """Lock to ensure thread-safe instance creation."""
182
+
183
+ def __call__(cls, *args: Any, **kwargs: Any):
184
+ is_sync = cls.__a_sync_instance_will_be_sync__(args, kwargs) # type: ignore [attr-defined]
185
+ if is_sync not in cls.__instances:
186
+ with cls.__lock:
187
+ # Check again in case `__instance` was set while we were waiting for the lock.
188
+ if is_sync not in cls.__instances:
189
+ cls.__instances[is_sync] = ASyncMeta.__call__(cls, *args, **kwargs)
190
+ return cls.__instances[is_sync]
191
+
192
+
193
+ def _update_logger(new_class_name: str) -> None:
194
+ """Update the logger configuration based on environment variables.
195
+
196
+ Args:
197
+ new_class_name: The name of the new class being created.
198
+ """
199
+ if ENVIRONMENT_VARIABLES.DEBUG_MODE or ENVIRONMENT_VARIABLES.DEBUG_CLASS_NAME == new_class_name:
200
+ logger.addHandler(_debug_handler)
201
+ logger.setLevel(logging.DEBUG)
202
+ logger.info("debug mode activated")
203
+ else:
204
+ logger.removeHandler(_debug_handler)
205
+ logger.setLevel(logging.INFO)
206
+
207
+
208
+ _debug_handler = logging.StreamHandler()
209
+
210
+ __all__ = ["ASyncMeta", "ASyncSingletonMeta"]