ez-a-sync 0.22.15__py3-none-any.whl → 0.22.16__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.

Potentially problematic release.


This version of ez-a-sync might be problematic. Click here for more details.

Files changed (49) hide show
  1. a_sync/ENVIRONMENT_VARIABLES.py +34 -3
  2. a_sync/__init__.py +32 -9
  3. a_sync/_smart.py +105 -6
  4. a_sync/_typing.py +56 -3
  5. a_sync/a_sync/_descriptor.py +174 -12
  6. a_sync/a_sync/_flags.py +64 -3
  7. a_sync/a_sync/_helpers.py +40 -8
  8. a_sync/a_sync/_kwargs.py +30 -6
  9. a_sync/a_sync/_meta.py +35 -6
  10. a_sync/a_sync/abstract.py +57 -9
  11. a_sync/a_sync/config.py +44 -7
  12. a_sync/a_sync/decorator.py +217 -37
  13. a_sync/a_sync/function.py +339 -47
  14. a_sync/a_sync/method.py +241 -52
  15. a_sync/a_sync/modifiers/__init__.py +39 -1
  16. a_sync/a_sync/modifiers/cache/__init__.py +75 -5
  17. a_sync/a_sync/modifiers/cache/memory.py +50 -6
  18. a_sync/a_sync/modifiers/limiter.py +55 -6
  19. a_sync/a_sync/modifiers/manager.py +46 -2
  20. a_sync/a_sync/modifiers/semaphores.py +84 -11
  21. a_sync/a_sync/singleton.py +43 -19
  22. a_sync/asyncio/__init__.py +137 -1
  23. a_sync/asyncio/as_completed.py +44 -38
  24. a_sync/asyncio/create_task.py +46 -10
  25. a_sync/asyncio/gather.py +72 -25
  26. a_sync/exceptions.py +178 -11
  27. a_sync/executor.py +51 -3
  28. a_sync/future.py +671 -29
  29. a_sync/iter.py +64 -7
  30. a_sync/primitives/_debug.py +59 -5
  31. a_sync/primitives/_loggable.py +36 -6
  32. a_sync/primitives/locks/counter.py +74 -7
  33. a_sync/primitives/locks/prio_semaphore.py +87 -8
  34. a_sync/primitives/locks/semaphore.py +68 -20
  35. a_sync/primitives/queue.py +65 -26
  36. a_sync/task.py +51 -15
  37. a_sync/utils/iterators.py +52 -16
  38. {ez_a_sync-0.22.15.dist-info → ez_a_sync-0.22.16.dist-info}/METADATA +1 -1
  39. ez_a_sync-0.22.16.dist-info/RECORD +74 -0
  40. {ez_a_sync-0.22.15.dist-info → ez_a_sync-0.22.16.dist-info}/WHEEL +1 -1
  41. tests/executor.py +150 -12
  42. tests/test_abstract.py +15 -0
  43. tests/test_base.py +198 -2
  44. tests/test_executor.py +23 -0
  45. tests/test_singleton.py +13 -1
  46. tests/test_task.py +45 -17
  47. ez_a_sync-0.22.15.dist-info/RECORD +0 -74
  48. {ez_a_sync-0.22.15.dist-info → ez_a_sync-0.22.16.dist-info}/LICENSE.txt +0 -0
  49. {ez_a_sync-0.22.15.dist-info → ez_a_sync-0.22.16.dist-info}/top_level.txt +0 -0
a_sync/a_sync/_flags.py CHANGED
@@ -11,6 +11,10 @@ AFFIRMATIVE_FLAGS: Set of flags indicating synchronous behavior. Currently inclu
11
11
  NEGATIVE_FLAGS: Set of flags indicating asynchronous behavior. Currently includes "asynchronous".
12
12
 
13
13
  VIABLE_FLAGS: Set of all valid flags, combining both synchronous and asynchronous indicators.
14
+
15
+ Functions:
16
+ - negate_if_necessary: Negates the flag value if necessary based on the flag type.
17
+ - validate_flag_value: Validates that the flag value is a boolean.
14
18
  """
15
19
 
16
20
  from typing import Any
@@ -18,18 +22,51 @@ from typing import Any
18
22
  from a_sync import exceptions
19
23
 
20
24
  AFFIRMATIVE_FLAGS = {"sync"}
21
- """Set of flags indicating synchronous behavior."""
25
+ """Set of flags indicating synchronous behavior.
26
+
27
+ Examples:
28
+ >>> 'sync' in AFFIRMATIVE_FLAGS
29
+ True
30
+
31
+ >>> 'async' in AFFIRMATIVE_FLAGS
32
+ False
33
+ """
22
34
 
23
35
  NEGATIVE_FLAGS = {"asynchronous"}
24
- """Set of flags indicating asynchronous behavior."""
36
+ """Set of flags indicating asynchronous behavior.
37
+
38
+ Examples:
39
+ >>> 'asynchronous' in NEGATIVE_FLAGS
40
+ True
41
+
42
+ >>> 'sync' in NEGATIVE_FLAGS
43
+ False
44
+ """
25
45
 
26
46
  VIABLE_FLAGS = AFFIRMATIVE_FLAGS | NEGATIVE_FLAGS
27
- """Set of all valid flags."""
47
+ """Set of all valid flags, combining both synchronous and asynchronous indicators.
48
+
49
+ A-Sync uses 'flags' to indicate whether objects or function calls will be sync or async.
50
+ You can use any of the provided flags, whichever makes most sense for your use case.
51
+
52
+ Examples:
53
+ >>> 'sync' in VIABLE_FLAGS
54
+ True
55
+
56
+ >>> 'asynchronous' in VIABLE_FLAGS
57
+ True
58
+
59
+ >>> 'invalid' in VIABLE_FLAGS
60
+ False
61
+ """
28
62
 
29
63
 
30
64
  def negate_if_necessary(flag: str, flag_value: bool) -> bool:
31
65
  """Negate the flag value if necessary based on the flag type.
32
66
 
67
+ This function checks if the provided flag is in the set of affirmative or negative flags
68
+ and negates the flag value accordingly. If the flag is not recognized, it raises an exception.
69
+
33
70
  Args:
34
71
  flag: The flag to check.
35
72
  flag_value: The value of the flag.
@@ -39,6 +76,16 @@ def negate_if_necessary(flag: str, flag_value: bool) -> bool:
39
76
 
40
77
  Raises:
41
78
  exceptions.InvalidFlag: If the flag is not recognized.
79
+
80
+ Examples:
81
+ >>> negate_if_necessary('sync', True)
82
+ True
83
+
84
+ >>> negate_if_necessary('asynchronous', True)
85
+ False
86
+
87
+ See Also:
88
+ - :func:`validate_flag_value`: Validates that the flag value is a boolean.
42
89
  """
43
90
  validate_flag_value(flag, flag_value)
44
91
  if flag in AFFIRMATIVE_FLAGS:
@@ -52,6 +99,8 @@ def validate_flag_value(flag: str, flag_value: Any) -> bool:
52
99
  """
53
100
  Validate that the flag value is a boolean.
54
101
 
102
+ This function ensures that the provided flag value is of type boolean. If not, it raises an exception.
103
+
55
104
  Args:
56
105
  flag: The flag being validated.
57
106
  flag_value: The value to validate.
@@ -61,6 +110,18 @@ def validate_flag_value(flag: str, flag_value: Any) -> bool:
61
110
 
62
111
  Raises:
63
112
  exceptions.InvalidFlagValue: If the flag value is not a boolean.
113
+
114
+ Examples:
115
+ >>> validate_flag_value('sync', True)
116
+ True
117
+
118
+ >>> validate_flag_value('asynchronous', 'yes')
119
+ Traceback (most recent call last):
120
+ ...
121
+ exceptions.InvalidFlagValue: Invalid flag value for 'asynchronous': 'yes'
122
+
123
+ See Also:
124
+ - :func:`negate_if_necessary`: Negates the flag value if necessary based on the flag type.
64
125
  """
65
126
  if not isinstance(flag_value, bool):
66
127
  raise exceptions.InvalidFlagValue(flag, flag_value)
a_sync/a_sync/_helpers.py CHANGED
@@ -17,10 +17,21 @@ def _await(awaitable: Awaitable[T]) -> T:
17
17
  Await an awaitable object in a synchronous context.
18
18
 
19
19
  Args:
20
- awaitable: The awaitable object to be awaited.
20
+ awaitable (Awaitable[T]): The awaitable object to be awaited.
21
21
 
22
22
  Raises:
23
23
  exceptions.SyncModeInAsyncContextError: If the event loop is already running.
24
+
25
+ Examples:
26
+ >>> async def example_coroutine():
27
+ ... return 42
28
+ ...
29
+ >>> result = _await(example_coroutine())
30
+ >>> print(result)
31
+ 42
32
+
33
+ See Also:
34
+ - :func:`asyncio.run`: For running the main entry point of an asyncio program.
24
35
  """
25
36
  try:
26
37
  return a_sync.asyncio.get_event_loop().run_until_complete(awaitable)
@@ -32,17 +43,38 @@ def _await(awaitable: Awaitable[T]) -> T:
32
43
 
33
44
  def _asyncify(func: SyncFn[P, T], executor: Executor) -> CoroFn[P, T]: # type: ignore [misc]
34
45
  """
35
- Convert a synchronous function to a coroutine function.
46
+ Convert a synchronous function to a coroutine function using an executor.
36
47
 
37
- Args:
38
- func: The synchronous function to be converted.
39
- executor: The executor used to run the synchronous function.
48
+ This function submits the synchronous function to the provided executor and wraps
49
+ the resulting future in a coroutine function. This allows the synchronous function
50
+ to be executed asynchronously.
40
51
 
41
- Returns:
42
- A coroutine function wrapping the input function.
52
+ Note:
53
+ The function `_asyncify` uses `asyncio.futures.wrap_future` to wrap the future
54
+ returned by the executor, specifying the event loop with `a_sync.asyncio.get_event_loop()`.
55
+ Ensure that your environment supports this usage or adjust the import if necessary.
56
+
57
+ Args:
58
+ func (SyncFn[P, T]): The synchronous function to be converted.
59
+ executor (Executor): The executor used to run the synchronous function.
43
60
 
44
61
  Raises:
45
- exceptions.FunctionNotSync: If the input function is a coroutine function or an instance of ASyncFunction.
62
+ exceptions.FunctionNotSync: If the input function is a coroutine function or an instance of :class:`~a_sync.a_sync.function.ASyncFunction`.
63
+
64
+ Examples:
65
+ >>> from concurrent.futures import ThreadPoolExecutor
66
+ >>> def sync_function(x):
67
+ ... return x * 2
68
+ ...
69
+ >>> executor = ThreadPoolExecutor()
70
+ >>> async_function = _asyncify(sync_function, executor)
71
+ >>> result = await async_function(3)
72
+ >>> print(result)
73
+ 6
74
+
75
+ See Also:
76
+ - :class:`concurrent.futures.Executor`: For managing pools of threads or processes.
77
+ - :func:`asyncio.to_thread`: For running blocking code in a separate thread.
46
78
  """
47
79
  from a_sync.a_sync.function import ASyncFunction
48
80
 
a_sync/a_sync/_kwargs.py CHANGED
@@ -19,7 +19,21 @@ def get_flag_name(kwargs: dict) -> Optional[str]:
19
19
  The name of the flag if present, None otherwise.
20
20
 
21
21
  Raises:
22
- :class:`exceptions.TooManyFlags`: If more than one flag is present in the kwargs.
22
+ :class:`exceptions.TooManyFlags`: If more than one flag is present in the kwargs,
23
+ the exception includes the message "kwargs" and the list of present flags.
24
+
25
+ Examples:
26
+ >>> get_flag_name({'sync': True})
27
+ 'sync'
28
+
29
+ >>> get_flag_name({'async': False})
30
+ 'async'
31
+
32
+ >>> get_flag_name({})
33
+ None
34
+
35
+ See Also:
36
+ :func:`is_sync`: Determines if the operation should be synchronous based on the flag value.
23
37
  """
24
38
  present_flags = [flag for flag in _flags.VIABLE_FLAGS if flag in kwargs]
25
39
  if len(present_flags) == 0:
@@ -34,12 +48,22 @@ def is_sync(flag: str, kwargs: dict, pop_flag: bool = False) -> bool:
34
48
  Determine if the operation should be synchronous based on the flag value.
35
49
 
36
50
  Args:
37
- flag: The name of the flag to check.
38
- kwargs: A dictionary of keyword arguments.
39
- pop_flag: Whether to remove the flag from kwargs. Defaults to False.
51
+ flag (str): The name of the flag to check.
52
+ kwargs (dict): A dictionary of keyword arguments.
53
+ pop_flag (bool, optional): Whether to remove the flag from kwargs. Defaults to False.
40
54
 
41
- Returns:
42
- True if the operation should be synchronous, False otherwise.
55
+ Examples:
56
+ >>> is_sync('sync', {'sync': True})
57
+ True
58
+
59
+ >>> is_sync('async', {'async': False})
60
+ False
61
+
62
+ >>> is_sync('sync', {'sync': True}, pop_flag=True)
63
+ True
64
+
65
+ See Also:
66
+ :func:`get_flag_name`: Retrieves the name of the flag present in the kwargs.
43
67
  """
44
68
  flag_value = kwargs.pop(flag) if pop_flag else kwargs[flag]
45
69
  return _flags.negate_if_necessary(flag, flag_value)
a_sync/a_sync/_meta.py CHANGED
@@ -24,11 +24,28 @@ class ASyncMeta(ABCMeta):
24
24
 
25
25
  Any class with `ASyncMeta` as its metaclass will have its functions and properties
26
26
  wrapped with asynchronous capabilities upon class instantiation. This includes
27
- wrapping functions with `ASyncMethodDescriptor` and properties with
28
- `ASyncPropertyDescriptor` or `ASyncCachedPropertyDescriptor`. Additionally, it handles
29
- `_ModifiedMixin` objects (# TODO replace this with the actual subclasses of _modifiedMixin, which is just an internal use mixin class that has no meaning ot the user),
30
- which are used when functions are decorated with a_sync decorators
31
- to apply specific modifiers to those functions.
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`
32
49
  """
33
50
 
34
51
  def __new__(cls, new_class_name, bases, attrs):
@@ -145,8 +162,20 @@ class ASyncMeta(ABCMeta):
145
162
  class ASyncSingletonMeta(ASyncMeta):
146
163
  """Metaclass for creating singleton instances with asynchronous capabilities.
147
164
 
148
- This metaclass extends `ASyncMeta` to ensure that only one instance of a class
165
+ This metaclass extends :class:`~a_sync.a_sync._meta.ASyncMeta` to ensure that only one instance of a class
149
166
  is created for each synchronous or asynchronous context.
167
+
168
+ Example:
169
+ To create a singleton class with asynchronous capabilities, define your class with `ASyncSingletonMeta` as its metaclass:
170
+
171
+ >>> class MySingleton(metaclass=ASyncSingletonMeta):
172
+ ... def __init__(self):
173
+ ... print("Instance created")
174
+
175
+ The `MySingleton` class will ensure that only one instance is created for each context.
176
+
177
+ See Also:
178
+ - :class:`~a_sync.a_sync._meta.ASyncMeta`
150
179
  """
151
180
 
152
181
  def __init__(
a_sync/a_sync/abstract.py CHANGED
@@ -1,12 +1,11 @@
1
1
  """
2
2
  This module provides an abstract base class for defining asynchronous and synchronous behavior.
3
3
 
4
- The ASyncABC class uses the ASyncMeta metaclass to automatically wrap its methods
5
- with asynchronous or synchronous behavior based on flags. Subclasses must
6
- implement the abstract methods to define the flag name, flag value, and
7
- default mode for asynchronous or synchronous execution.
4
+ The :class:`ASyncABC` class uses the :class:`ASyncMeta` metaclass to facilitate the creation of classes
5
+ that can operate in both asynchronous and synchronous contexts. It provides concrete methods to determine
6
+ the execution mode based on flags and keyword arguments.
8
7
 
9
- Note: It is recommended to use ASyncGenericBase for most use cases. This class
8
+ Note: It is recommended to use :class:`ASyncGenericBase` for most use cases. This class
10
9
  is intended for more custom implementations if necessary.
11
10
  """
12
11
 
@@ -26,10 +25,35 @@ logger = logging.getLogger(__name__)
26
25
  class ASyncABC(metaclass=ASyncMeta):
27
26
  """Abstract Base Class for defining asynchronous and synchronous behavior.
28
27
 
29
- This class uses the ASyncMeta metaclass to automatically wrap its methods
30
- with asynchronous or synchronous behavior based on flags. Subclasses must
31
- implement the abstract methods to define the flag name, flag value, and
32
- default mode for asynchronous or synchronous execution.
28
+ This class provides methods to determine the execution mode based on flags and keyword arguments.
29
+ It is designed to be subclassed, allowing developers to create classes that can be used in both
30
+ synchronous and asynchronous contexts.
31
+
32
+ See Also:
33
+ - :class:`ASyncGenericBase`: A more user-friendly base class for creating dual-mode classes.
34
+ - :class:`ASyncMeta`: Metaclass that facilitates asynchronous capabilities in class attributes.
35
+
36
+ Examples:
37
+ To create a class that inherits from `ASyncABC`, you need to implement the abstract methods
38
+ and can override the concrete methods if needed.
39
+
40
+ ```python
41
+ class MyASyncClass(ASyncABC):
42
+ @property
43
+ def __a_sync_flag_name__(self) -> str:
44
+ return "sync"
45
+
46
+ @property
47
+ def __a_sync_flag_value__(self) -> bool:
48
+ return True
49
+
50
+ @classmethod
51
+ def __a_sync_default_mode__(cls) -> bool:
52
+ return False
53
+ ```
54
+
55
+ In this example, `MyASyncClass` is a subclass of `ASyncABC` with custom implementations
56
+ for the required abstract methods.
33
57
  """
34
58
 
35
59
  ##################################
@@ -45,6 +69,11 @@ class ASyncABC(metaclass=ASyncMeta):
45
69
 
46
70
  Args:
47
71
  kwargs: A dictionary of keyword arguments to check for flags.
72
+
73
+ Examples:
74
+ >>> instance = MyASyncClass()
75
+ >>> instance.__a_sync_should_await__({'sync': True})
76
+ False
48
77
  """
49
78
  try:
50
79
  return self.__a_sync_should_await_from_kwargs__(kwargs)
@@ -58,6 +87,11 @@ class ASyncABC(metaclass=ASyncMeta):
58
87
  This property can be overridden if dynamic behavior is needed. For
59
88
  instance, to allow hot-swapping of instance modes, redefine this as a
60
89
  non-cached property.
90
+
91
+ Examples:
92
+ >>> instance = MyASyncClass()
93
+ >>> instance.__a_sync_instance_should_await__
94
+ True
61
95
  """
62
96
  return _flags.negate_if_necessary(
63
97
  self.__a_sync_flag_name__, self.__a_sync_flag_value__
@@ -74,6 +108,11 @@ class ASyncABC(metaclass=ASyncMeta):
74
108
 
75
109
  Raises:
76
110
  NoFlagsFound: If no valid flags are found in the keyword arguments.
111
+
112
+ Examples:
113
+ >>> instance = MyASyncClass()
114
+ >>> instance.__a_sync_should_await_from_kwargs__({'sync': False})
115
+ True
77
116
  """
78
117
  if flag := _kwargs.get_flag_name(kwargs):
79
118
  return _kwargs.is_sync(flag, kwargs, pop_flag=True) # type: ignore [arg-type]
@@ -89,6 +128,10 @@ class ASyncABC(metaclass=ASyncMeta):
89
128
  Args:
90
129
  args: A tuple of positional arguments for the instance.
91
130
  kwargs: A dictionary of keyword arguments for the instance.
131
+
132
+ Examples:
133
+ >>> MyASyncClass.__a_sync_instance_will_be_sync__((), {'sync': True})
134
+ True
92
135
  """
93
136
  logger.debug(
94
137
  "checking `%s.%s.__init__` signature against provided kwargs to determine a_sync mode for the new instance",
@@ -119,6 +162,11 @@ class ASyncABC(metaclass=ASyncMeta):
119
162
 
120
163
  This method should not be overridden. It returns the modifiers
121
164
  associated with the instance, which are used to customize behavior.
165
+
166
+ Examples:
167
+ >>> instance = MyASyncClass()
168
+ >>> instance.__a_sync_modifiers__
169
+ {'cache_type': 'memory'}
122
170
  """
123
171
  return modifiers.get_modifiers_from(self)
124
172
 
a_sync/a_sync/config.py CHANGED
@@ -1,23 +1,46 @@
1
1
  """
2
- Configuration module for the a_sync library.
3
-
4
2
  This module provides configuration options and default settings for the a_sync library.
5
3
  It includes functionality for setting up executors, defining default modifiers,
6
4
  and handling environment variable configurations.
7
5
 
8
6
  Environment Variables:
9
7
  A_SYNC_EXECUTOR_TYPE: Specifies the type of executor to use. Valid values are
10
- strings that start with 'p' for ProcessPoolExecutor (e.g., 'processes')
11
- or 't' for ThreadPoolExecutor (e.g., 'threads'). Defaults to 'threads'.
8
+ strings that start with 'p' for :class:`~concurrent.futures.ProcessPoolExecutor`
9
+ (e.g., 'processes') or 't' for :class:`~concurrent.futures.ThreadPoolExecutor`
10
+ (e.g., 'threads'). Defaults to 'threads'.
12
11
  A_SYNC_EXECUTOR_VALUE: Specifies the number of workers for the executor.
13
12
  Defaults to 8.
14
13
  A_SYNC_DEFAULT_MODE: Sets the default mode for a_sync functions if not specified.
15
14
  A_SYNC_CACHE_TYPE: Sets the default cache type. If not specified, defaults to None.
16
15
  A_SYNC_CACHE_TYPED: Boolean flag to determine if cache keys should consider types.
17
16
  A_SYNC_RAM_CACHE_MAXSIZE: Sets the maximum size for the RAM cache. Defaults to -1.
18
- A_SYNC_RAM_CACHE_TTL: Sets the time-to-live for cache entries. Defaults to None.
17
+ A_SYNC_RAM_CACHE_TTL: Sets the time-to-live for cache entries. If not specified,
18
+ defaults to None, meaning cache entries do not expire by default.
19
+ Note: Although the environment variable retrieval process uses 0 as a placeholder,
20
+ the actual default behavior is determined by `null_modifiers["ram_cache_ttl"]`,
21
+ which is `None`.
19
22
  A_SYNC_RUNS_PER_MINUTE: Sets the rate limit for function execution.
20
23
  A_SYNC_SEMAPHORE: Sets the semaphore limit for function execution.
24
+
25
+ Examples:
26
+ To set the executor type to use threads with 4 workers, set the environment variables:
27
+
28
+ .. code-block:: bash
29
+
30
+ export A_SYNC_EXECUTOR_TYPE=threads
31
+ export A_SYNC_EXECUTOR_VALUE=4
32
+
33
+ To configure caching with a maximum size of 100 and a TTL of 60 seconds:
34
+
35
+ .. code-block:: bash
36
+
37
+ export A_SYNC_CACHE_TYPE=memory
38
+ export A_SYNC_RAM_CACHE_MAXSIZE=100
39
+ export A_SYNC_RAM_CACHE_TTL=60
40
+
41
+ See Also:
42
+ - :mod:`concurrent.futures`: For more details on executors.
43
+ - :mod:`functools`: For caching mechanisms.
21
44
  """
22
45
 
23
46
  import functools
@@ -36,11 +59,25 @@ def get_default_executor() -> Executor:
36
59
  """Get the default executor based on the EXECUTOR_TYPE environment variable.
37
60
 
38
61
  Returns:
39
- An instance of either ProcessPoolExecutor or ThreadPoolExecutor.
62
+ An instance of either :class:`~concurrent.futures.ProcessPoolExecutor`
63
+ or :class:`~concurrent.futures.ThreadPoolExecutor`.
40
64
 
41
65
  Raises:
42
66
  ValueError: If an invalid EXECUTOR_TYPE is specified. Valid values are
43
- strings that start with 'p' for ProcessPoolExecutor or 't' for ThreadPoolExecutor.
67
+ strings that start with 'p' for :class:`~concurrent.futures.ProcessPoolExecutor`
68
+ or 't' for :class:`~concurrent.futures.ThreadPoolExecutor`.
69
+
70
+ Examples:
71
+ >>> import os
72
+ >>> os.environ["A_SYNC_EXECUTOR_TYPE"] = "threads"
73
+ >>> executor = get_default_executor()
74
+ >>> isinstance(executor, ThreadPoolExecutor)
75
+ True
76
+
77
+ >>> os.environ["A_SYNC_EXECUTOR_TYPE"] = "processes"
78
+ >>> executor = get_default_executor()
79
+ >>> isinstance(executor, ProcessPoolExecutor)
80
+ True
44
81
  """
45
82
  if EXECUTOR_TYPE.lower().startswith("p"): # p, P, proc, Processes, etc
46
83
  return ProcessPoolExecutor(EXECUTOR_VALUE)