dev4py.utils.awaitables

The awaitables module provides a set of utility functions to simplify Awaitable operations

 1"""
 2The `awaitables` module provides a set of utility functions to simplify Awaitable operations
 3"""
 4
 5# Copyright 2022 the original author or authors (i.e.: St4rG00se for Dev4py).
 6#
 7# Licensed under the Apache License, Version 2.0 (the "License");
 8# you may not use this file except in compliance with the License.
 9# You may obtain a copy of the License at
10#
11#      https://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS,
15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16# See the License for the specific language governing permissions and
17# limitations under the License.
18
19
20from typing import Awaitable, Any, cast
21
22from dev4py.utils import objects
23from dev4py.utils.types import T, R, Function, SyncOrAsync
24
25
26def is_awaitable(value: Any) -> bool:
27    """
28    If the given value is an Awaitable (Coroutine, Task or Future), returns true, otherwise false
29
30    Returns:
31        bool: true if the given value is an Awaitable, otherwise false
32    """
33    return isinstance(value, Awaitable)
34
35
36def to_sync_or_async_param_function(
37        function: Function[T, SyncOrAsync[R]]
38) -> Function[SyncOrAsync[T], Awaitable[R]]:
39    """
40    If the given Function uses sync parameter, create a new equivalent async function supporting sync or Awaitable
41    parameter
42
43    Returned Function specificities:
44        1. Is an async function (it means if the given function result is R the new function result is an Awaitable[R])
45        2. If the given function is async (i.e. result is an Awaitable[R]), the new function result stay an Awaitable[R]
46        3. !WARNING! If the given function expected parameter is an Awaitable, it will be awaited by the wrapper before
47        being passed as given function parameter. So, it will probably raise an error depending on your code
48
49    Note: This function can be useful associated with the map function of a `JOptional` with Awaitable value
50
51    Args:
52        function: The function with sync parameter
53
54    Returns:
55        sync_or_async_param_function: An async function with awaitable parameter
56
57    Raises:
58        TypeError: Raises a TypeError if function is None
59        Exception: If the given function expected parameter is an Awaitable, it will be awaited by the wrapper before
60        being passed as function parameter, and, it will probably raise an error depending on function your code
61    """
62    objects.require_non_none(function)
63
64    async def sync_or_async_param_function(param: SyncOrAsync[T]) -> R:
65        result: SyncOrAsync[R] = function((await cast(Awaitable[T], param)) if is_awaitable(param) else cast(T, param))
66        return await cast(Awaitable[R], result) if is_awaitable(result) else cast(R, result)
67
68    return sync_or_async_param_function
69
70
71def to_awaitable(value: SyncOrAsync[T]) -> Awaitable[T]:
72    """
73    This function map a SyncOrAsync[T] to an Awaitable[T]
74
75    Note: This can be useful to work with SyncOrAsync values in order to always works with `await`. Without this
76    function, you always have to call is_awaitable in order to know if you have to use `await` or not.
77
78    Args:
79        value: the value to map
80
81    Returns:
82        Awaitable[T]: a value to await
83    """
84
85    async def _sync_to_awaitable(param: T) -> T:
86        return param
87
88    return cast(Awaitable[T], value) if is_awaitable(value) else _sync_to_awaitable(cast(T, value))
89
90
91async def async_none() -> None:
92    """
93    This function provides an Awaitable[None]
94
95    Returns:
96        Awaitable[None]: An awaitable of None
97
98    """
99    return None
def is_awaitable(value: Any) -> bool:
27def is_awaitable(value: Any) -> bool:
28    """
29    If the given value is an Awaitable (Coroutine, Task or Future), returns true, otherwise false
30
31    Returns:
32        bool: true if the given value is an Awaitable, otherwise false
33    """
34    return isinstance(value, Awaitable)

If the given value is an Awaitable (Coroutine, Task or Future), returns true, otherwise false

Returns:

bool: true if the given value is an Awaitable, otherwise false

def to_sync_or_async_param_function( function: Callable[[~T], Union[Awaitable[~R], ~R]]) -> Callable[[Union[Awaitable[~T], ~T]], Awaitable[~R]]:
37def to_sync_or_async_param_function(
38        function: Function[T, SyncOrAsync[R]]
39) -> Function[SyncOrAsync[T], Awaitable[R]]:
40    """
41    If the given Function uses sync parameter, create a new equivalent async function supporting sync or Awaitable
42    parameter
43
44    Returned Function specificities:
45        1. Is an async function (it means if the given function result is R the new function result is an Awaitable[R])
46        2. If the given function is async (i.e. result is an Awaitable[R]), the new function result stay an Awaitable[R]
47        3. !WARNING! If the given function expected parameter is an Awaitable, it will be awaited by the wrapper before
48        being passed as given function parameter. So, it will probably raise an error depending on your code
49
50    Note: This function can be useful associated with the map function of a `JOptional` with Awaitable value
51
52    Args:
53        function: The function with sync parameter
54
55    Returns:
56        sync_or_async_param_function: An async function with awaitable parameter
57
58    Raises:
59        TypeError: Raises a TypeError if function is None
60        Exception: If the given function expected parameter is an Awaitable, it will be awaited by the wrapper before
61        being passed as function parameter, and, it will probably raise an error depending on function your code
62    """
63    objects.require_non_none(function)
64
65    async def sync_or_async_param_function(param: SyncOrAsync[T]) -> R:
66        result: SyncOrAsync[R] = function((await cast(Awaitable[T], param)) if is_awaitable(param) else cast(T, param))
67        return await cast(Awaitable[R], result) if is_awaitable(result) else cast(R, result)
68
69    return sync_or_async_param_function

If the given Function uses sync parameter, create a new equivalent async function supporting sync or Awaitable parameter

Returned Function specificities:
  1. Is an async function (it means if the given function result is R the new function result is an Awaitable[R])
  2. If the given function is async (i.e. result is an Awaitable[R]), the new function result stay an Awaitable[R]
  3. !WARNING! If the given function expected parameter is an Awaitable, it will be awaited by the wrapper before being passed as given function parameter. So, it will probably raise an error depending on your code

Note: This function can be useful associated with the map function of a JOptional with Awaitable value

Arguments:
  • function: The function with sync parameter
Returns:

sync_or_async_param_function: An async function with awaitable parameter

Raises:
  • TypeError: Raises a TypeError if function is None
  • Exception: If the given function expected parameter is an Awaitable, it will be awaited by the wrapper before
  • being passed as function parameter, and, it will probably raise an error depending on function your code
def to_awaitable(value: Union[Awaitable[~T], ~T]) -> Awaitable[~T]:
72def to_awaitable(value: SyncOrAsync[T]) -> Awaitable[T]:
73    """
74    This function map a SyncOrAsync[T] to an Awaitable[T]
75
76    Note: This can be useful to work with SyncOrAsync values in order to always works with `await`. Without this
77    function, you always have to call is_awaitable in order to know if you have to use `await` or not.
78
79    Args:
80        value: the value to map
81
82    Returns:
83        Awaitable[T]: a value to await
84    """
85
86    async def _sync_to_awaitable(param: T) -> T:
87        return param
88
89    return cast(Awaitable[T], value) if is_awaitable(value) else _sync_to_awaitable(cast(T, value))

This function map a SyncOrAsync[T] to an Awaitable[T]

Note: This can be useful to work with SyncOrAsync values in order to always works with await. Without this function, you always have to call is_awaitable in order to know if you have to use await or not.

Arguments:
  • value: the value to map
Returns:

Awaitable[T]: a value to await

async def async_none() -> None:
 92async def async_none() -> None:
 93    """
 94    This function provides an Awaitable[None]
 95
 96    Returns:
 97        Awaitable[None]: An awaitable of None
 98
 99    """
100    return None

This function provides an Awaitable[None]

Returns:

Awaitable[None]: An awaitable of None