dev4py.utils.async_joptional
The AsyncJOptional
class is like the JOptional
one but simplify the use of Awaitable values
1"""The `AsyncJOptional` class is like the `JOptional` one but simplify the use of Awaitable values""" 2 3# Copyright 2022 the original author or authors (i.e.: St4rG00se for Dev4py). 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# https://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17from __future__ import annotations 18 19from functools import partial 20from typing import Generic, Final, Optional, TypeAlias, cast, Any, Awaitable 21 22from dev4py.utils.joptional import JOptional 23from dev4py.utils.awaitables import is_awaitable 24from dev4py.utils.objects import async_require_non_none, non_none, is_none, require_non_none, to_self, to_none 25from dev4py.utils.types import T, V, SyncOrAsync, Supplier, Function, R, Consumer, Runnable, Predicate 26 27_VType: TypeAlias = SyncOrAsync[Optional[V]] # pragma: no mutate 28 29 30class AsyncJOptional(Generic[T]): 31 """A JOptional class for async value mapping""" 32 33 __CREATE_KEY: Final[object] = object() 34 __NO_VALUE_ERROR_MSG: Final[str] = "No value present" 35 __EMPTY: AsyncJOptional[Any] 36 37 @classmethod 38 # pylint: disable=E1136 39 def of(cls, value: _VType[T]) -> AsyncJOptional[T]: 40 """ 41 Returns a JOptional describing the given non-None value or Awaitable value 42 43 Args: 44 value: The value (or Awaitable value) to describe, which must be non-None and not an Awaitable of None 45 46 Returns: 47 JOptional[T]: A JOptional of value T or Awaitable[T] type with the value present 48 49 Raises: 50 TypeError: Raises a TypeError on terminal operation if value is None or is an Awaitable of None 51 """ 52 return AsyncJOptional(async_require_non_none(value, cls.__NO_VALUE_ERROR_MSG), cls.__CREATE_KEY) 53 54 @classmethod 55 # pylint: disable=E1136 56 def of_noneable(cls, value: _VType[T]) -> AsyncJOptional[T]: 57 """ 58 Returns a JOptional describing the given value or Awaitable value, if non-None, otherwise returns an empty 59 AsyncJOptional 60 61 Args: 62 value: The possibly-None or Awaitable of None value to describe 63 64 Returns: 65 JOptional[T]: A JOptional of value T or Awaitable[T] type with the value present if the specified value is 66 non-None, otherwise an empty AsyncJOptional 67 """ 68 return AsyncJOptional(value, cls.__CREATE_KEY) 69 70 @classmethod 71 def empty(cls) -> AsyncJOptional[T]: 72 """Return an empty instance of AsyncJOptional""" 73 return cls.__EMPTY 74 75 # pylint: disable=E1136 76 def __init__(self, value: _VType[T], create_key: object): 77 """AsyncJOptional private constructor: Constructs an instance with the described value""" 78 assert create_key == self.__CREATE_KEY, \ 79 "AsyncJOptional private constructor! Please use AsyncJOptional.of or AsyncJOptional.of_noneable" 80 self._value: _VType[T] = value 81 82 async def _get_value(self) -> Optional[T]: 83 """ 84 Private method in order to manage Sync or Awaitable value 85 86 Returns: 87 Optional[T]: the current value 88 """ 89 if is_awaitable(self._value): 90 self._value = await cast(Awaitable[Optional[T]], self._value) 91 return cast(Optional[T], self._value) 92 93 async def is_present(self) -> bool: 94 """ 95 If a value is present, returns true, otherwise false 96 97 Note: A value is present when not None and not an Awaitable of None 98 99 Returns: 100 bool: true if a value is not None and not an Awaitable of None, otherwise false 101 """ 102 return non_none(await self._get_value()) 103 104 async def is_empty(self) -> bool: 105 """ 106 If a value is not present, returns true, otherwise false. 107 108 Note: A value is empty when None or an Awaitable of None 109 110 Returns: 111 bool: true if a value is None or an Awaitable of None, otherwise false 112 """ 113 return is_none(await self._get_value()) 114 115 def get(self) -> Awaitable[T]: 116 """ 117 If a value is present, returns the value, otherwise raises a ValueError 118 119 Returns: 120 value: The non-None value described by this AsyncJOptional 121 122 Raises: 123 ValueError: Raises a ValueError if the value is empty 124 """ 125 return self.or_else_raise() 126 127 def or_else(self, other: Optional[T] = None) -> Awaitable[Optional[T]]: 128 """ 129 If a value is present, returns the value, otherwise returns other 130 131 Args: 132 other: The value to be returned, if no value is present. May be None. 133 134 Returns: 135 value: The value, if present, otherwise other 136 """ 137 return self.or_else_get(cast(Supplier[Optional[T]], partial(to_self, obj=other))) 138 139 async def or_else_get(self, supplier: Supplier[Optional[T]] = to_none) -> Optional[T]: 140 """ 141 If a value is present, returns the value, otherwise returns the result produced by the supplying function 142 143 Args: 144 supplier: The supplying function that produces a value to be returned 145 146 Returns: 147 value: The value, if present, otherwise the result produced by the supplying function 148 149 Raises: 150 TypeError: if the supplying function is None 151 """ 152 require_non_none(supplier) 153 return cast(Optional[T], self._value if await self.is_present() else supplier()) 154 155 @staticmethod # pragma: no mutate 156 def __or_else_raise_supplier_lambda() -> Exception: 157 """ 158 private static method to replace or_else_raise lambda supplier by a function 159 Note: lambda are not used in order to be compatible with multiprocessing (lambda are not serializable) 160 """ 161 # lambda: cast(Exception, ValueError(AsyncJOptional.__NO_VALUE_ERROR_MSG)) 162 return cast(Exception, ValueError(AsyncJOptional.__NO_VALUE_ERROR_MSG)) 163 164 async def or_else_raise( 165 self, 166 supplier: Supplier[Exception] = __or_else_raise_supplier_lambda 167 ) -> T: 168 """ 169 If a value is present, returns the value, otherwise raises an exception produced by the exception supplying 170 function 171 172 Args: 173 supplier: The supplying function that produces an exception to be raised (default: ValueError) 174 175 Returns: 176 value: The value, if present 177 178 Raises: 179 Exception: If value is empty 180 TypeError: if the exception supplying function is None 181 """ 182 require_non_none(supplier) 183 if await self.is_empty(): 184 raise supplier() 185 return cast(T, self._value) 186 187 def or_get(self, supplier: Supplier[AsyncJOptional[T]]) -> AsyncJOptional[T]: 188 """ 189 This is the `or` equivalent in java Optional (Reminder: `or` is a python keyword) 190 191 If a value is present, returns an AsyncJOptional describing the value, otherwise returns an AsyncJOptional 192 produced by the supplying function 193 194 Args: 195 supplier: The supplying function that produces an AsyncJOptional to be returned 196 197 Returns: 198 AsyncJOptional[T]: Returns an AsyncJOptional describing the value of this AsyncJOptional, if a value is 199 present, otherwise an AsyncJOptional produced by the supplying function 200 201 Raises: 202 TypeError: if the supplying function is None 203 """ 204 require_non_none(supplier) 205 206 async def _async_or_get(current: AsyncJOptional[T], suppl: Supplier[AsyncJOptional[T]]) -> Optional[T]: 207 return await current.get() if await current.is_present() else await require_non_none(suppl()).or_else_get() 208 209 return AsyncJOptional.of_noneable(_async_or_get(self, supplier)) 210 211 @staticmethod # pragma: no mutate 212 def __map_lambda(v: T, mapper: Function[T, _VType[R]]) -> AsyncJOptional[R]: 213 """ 214 private static method to replace inner map lambda supplier by a function 215 Note: lambda are not used in order to be compatible with multiprocessing (lambda are not serializable) 216 """ 217 # lambda v: AsyncJOptional.of_noneable(mapper(v)) 218 return AsyncJOptional.of_noneable(mapper(v)) 219 220 def map(self, mapper: Function[T, _VType[R]]) -> AsyncJOptional[R]: 221 """ 222 If a value is present, returns an AsyncJOptional describing (as if by of_noneable) the result of applying the 223 given mapping function to the value, otherwise returns an empty AsyncJOptional 224 225 If the mapping function returns a None result then this method returns an empty AsyncJOptional. 226 227 Note: mapping function can be sync or Awaitable (like async coroutine) 228 229 Args: 230 mapper: The mapping function to apply to a value, if present 231 232 Returns: 233 AsyncJOptional[R]: An AsyncJOptional describing the result of applying a mapping function to the value of 234 this AsyncJOptional, if a value is present, otherwise an empty AsyncJOptional 235 236 Raises: 237 TypeError: If the mapping function is None 238 """ 239 require_non_none(mapper) 240 return self.flat_map(partial(AsyncJOptional.__map_lambda, mapper=mapper)) 241 242 def flat_map(self, mapper: Function[T, AsyncJOptional[R]]) -> AsyncJOptional[R]: 243 """ 244 If a value is present, returns the result of applying the given AsyncJOptional-bearing mapping function to the 245 value, otherwise returns an empty AsyncJOptional 246 247 This method is similar to map(Function), but the mapping function is one whose result is already an 248 AsyncJOptional, and if invoked, flatMap does not wrap it within an additional AsyncJOptional 249 250 Args: 251 mapper: The mapping function to apply to a value, if present 252 253 Returns: 254 AsyncJOptional[R]: The result of applying a AsyncJOptional-bearing mapping function to the value of this 255 AsyncJOptional, if a value is present, otherwise an empty AsyncJOptional 256 257 Raises: 258 TypeError: if the mapping function is None 259 """ 260 require_non_none(mapper) 261 262 async def _async_flat_map( 263 current: AsyncJOptional[T], flat_mapper: Function[T, AsyncJOptional[R]] 264 ) -> Optional[R]: 265 if await current.is_present(): 266 new_async_joptional: AsyncJOptional[R] = require_non_none(flat_mapper(await current.get())) 267 return await new_async_joptional.or_else_get() 268 return None 269 270 return AsyncJOptional.of_noneable(_async_flat_map(self, mapper)) 271 272 async def if_present(self, consumer: Consumer[T]) -> None: 273 """ 274 If a value is present, performs the given consumer with the value, otherwise does nothing 275 276 Args: 277 consumer: The consumer to be performed, if a value is present 278 279 Returns: 280 Nothing 281 282 Raises: 283 TypeError: if the consumer is None 284 """ 285 require_non_none(consumer) 286 # pylint: disable=W0106 287 (await self.is_present()) and consumer(cast(T, self._value)) 288 289 async def if_empty(self, empty_action: Runnable) -> None: 290 """ 291 If a value is not present, performs the given runnable, otherwise does nothing 292 293 Args: 294 empty_action: The runnable to be performed, if a value is not present 295 296 Returns: 297 Nothing 298 299 Raises: 300 TypeError: if the runnable is None 301 """ 302 require_non_none(empty_action) 303 # pylint: disable=W0106 304 (await self.is_empty()) and empty_action() 305 306 async def if_present_or_else(self, consumer: Consumer[T], empty_action: Runnable) -> None: 307 """ 308 If a value is present, performs the given consumer with the value, otherwise performs the given empty_action 309 310 Args: 311 consumer: The consumer to be performed, if a value is present 312 empty_action: The runnable to be performed, if a value is not 313 314 Returns: 315 Nothing 316 317 Raises: 318 TypeError: if the consumer is None or if the runnable is None 319 """ 320 require_non_none(consumer) 321 require_non_none(empty_action) 322 # pylint: disable=W0106 323 consumer(cast(T, self._value)) if await self.is_present() else empty_action() 324 325 def filter(self, predicate: Predicate[T]) -> AsyncJOptional[T]: 326 """ 327 If a value is present, and the value matches the given predicate, returns an AsyncJOptional describing the 328 value, otherwise returns an empty AsyncJOptional 329 330 Args: 331 predicate: The predicate to apply to a value, if present 332 333 Returns: 334 AsyncJOptional[T]: An AsyncJOptional describing the value of this AsyncJOptional, if a value is present and 335 the value matches the given predicate, otherwise an empty AsyncJOptional 336 337 Raises: 338 TypeError: if the predicate is None 339 """ 340 require_non_none(predicate) 341 342 async def _async_filter(current: AsyncJOptional[T]) -> Optional[T]: 343 return await current.or_else_get() if await current.is_empty() or predicate(await current.get()) else None 344 345 return AsyncJOptional.of_noneable(_async_filter(self)) 346 347 def peek(self, consumer: Consumer[T]) -> AsyncJOptional[T]: 348 """ 349 If a value is present, performs the given consumer with the value, otherwise does nothing and returns the 350 current equivalent of AsyncJOptional 351 352 Args: 353 consumer: The consumer to be performed, if a value is present 354 355 Returns: 356 AsyncJOptional[T]: The current equivalent of AsyncJOptional 357 358 Raises: 359 TypeError: if the consumer is None 360 """ 361 require_non_none(consumer) 362 363 async def _async_peek(current: AsyncJOptional[T], cons: Consumer[T]) -> Optional[T]: 364 await current.if_present(cons) 365 return await current.or_else_get() 366 367 return AsyncJOptional.of_noneable(_async_peek(self, consumer)) 368 369 def to_joptional(self) -> JOptional[Awaitable[Optional[T]]]: 370 """ 371 Convert the current AsyncJOptional to a JOptional 372 373 Note: the returned JOptional will contain an Awaitable[Optional[T]] value 374 375 Returns: 376 JOptional[Awaitable[Optional[T]]]: The corresponding JOptional 377 """ 378 return JOptional.of_noneable(cast(Awaitable[Optional[T]], self._get_value())) 379 380 381# INIT STATIC VARIABLES 382# noinspection PyProtectedMember 383# noinspection PyUnresolvedReferences 384# pylint: disable=W0212 385AsyncJOptional._AsyncJOptional__EMPTY = AsyncJOptional(None, AsyncJOptional._AsyncJOptional__CREATE_KEY) # type: ignore
31class AsyncJOptional(Generic[T]): 32 """A JOptional class for async value mapping""" 33 34 __CREATE_KEY: Final[object] = object() 35 __NO_VALUE_ERROR_MSG: Final[str] = "No value present" 36 __EMPTY: AsyncJOptional[Any] 37 38 @classmethod 39 # pylint: disable=E1136 40 def of(cls, value: _VType[T]) -> AsyncJOptional[T]: 41 """ 42 Returns a JOptional describing the given non-None value or Awaitable value 43 44 Args: 45 value: The value (or Awaitable value) to describe, which must be non-None and not an Awaitable of None 46 47 Returns: 48 JOptional[T]: A JOptional of value T or Awaitable[T] type with the value present 49 50 Raises: 51 TypeError: Raises a TypeError on terminal operation if value is None or is an Awaitable of None 52 """ 53 return AsyncJOptional(async_require_non_none(value, cls.__NO_VALUE_ERROR_MSG), cls.__CREATE_KEY) 54 55 @classmethod 56 # pylint: disable=E1136 57 def of_noneable(cls, value: _VType[T]) -> AsyncJOptional[T]: 58 """ 59 Returns a JOptional describing the given value or Awaitable value, if non-None, otherwise returns an empty 60 AsyncJOptional 61 62 Args: 63 value: The possibly-None or Awaitable of None value to describe 64 65 Returns: 66 JOptional[T]: A JOptional of value T or Awaitable[T] type with the value present if the specified value is 67 non-None, otherwise an empty AsyncJOptional 68 """ 69 return AsyncJOptional(value, cls.__CREATE_KEY) 70 71 @classmethod 72 def empty(cls) -> AsyncJOptional[T]: 73 """Return an empty instance of AsyncJOptional""" 74 return cls.__EMPTY 75 76 # pylint: disable=E1136 77 def __init__(self, value: _VType[T], create_key: object): 78 """AsyncJOptional private constructor: Constructs an instance with the described value""" 79 assert create_key == self.__CREATE_KEY, \ 80 "AsyncJOptional private constructor! Please use AsyncJOptional.of or AsyncJOptional.of_noneable" 81 self._value: _VType[T] = value 82 83 async def _get_value(self) -> Optional[T]: 84 """ 85 Private method in order to manage Sync or Awaitable value 86 87 Returns: 88 Optional[T]: the current value 89 """ 90 if is_awaitable(self._value): 91 self._value = await cast(Awaitable[Optional[T]], self._value) 92 return cast(Optional[T], self._value) 93 94 async def is_present(self) -> bool: 95 """ 96 If a value is present, returns true, otherwise false 97 98 Note: A value is present when not None and not an Awaitable of None 99 100 Returns: 101 bool: true if a value is not None and not an Awaitable of None, otherwise false 102 """ 103 return non_none(await self._get_value()) 104 105 async def is_empty(self) -> bool: 106 """ 107 If a value is not present, returns true, otherwise false. 108 109 Note: A value is empty when None or an Awaitable of None 110 111 Returns: 112 bool: true if a value is None or an Awaitable of None, otherwise false 113 """ 114 return is_none(await self._get_value()) 115 116 def get(self) -> Awaitable[T]: 117 """ 118 If a value is present, returns the value, otherwise raises a ValueError 119 120 Returns: 121 value: The non-None value described by this AsyncJOptional 122 123 Raises: 124 ValueError: Raises a ValueError if the value is empty 125 """ 126 return self.or_else_raise() 127 128 def or_else(self, other: Optional[T] = None) -> Awaitable[Optional[T]]: 129 """ 130 If a value is present, returns the value, otherwise returns other 131 132 Args: 133 other: The value to be returned, if no value is present. May be None. 134 135 Returns: 136 value: The value, if present, otherwise other 137 """ 138 return self.or_else_get(cast(Supplier[Optional[T]], partial(to_self, obj=other))) 139 140 async def or_else_get(self, supplier: Supplier[Optional[T]] = to_none) -> Optional[T]: 141 """ 142 If a value is present, returns the value, otherwise returns the result produced by the supplying function 143 144 Args: 145 supplier: The supplying function that produces a value to be returned 146 147 Returns: 148 value: The value, if present, otherwise the result produced by the supplying function 149 150 Raises: 151 TypeError: if the supplying function is None 152 """ 153 require_non_none(supplier) 154 return cast(Optional[T], self._value if await self.is_present() else supplier()) 155 156 @staticmethod # pragma: no mutate 157 def __or_else_raise_supplier_lambda() -> Exception: 158 """ 159 private static method to replace or_else_raise lambda supplier by a function 160 Note: lambda are not used in order to be compatible with multiprocessing (lambda are not serializable) 161 """ 162 # lambda: cast(Exception, ValueError(AsyncJOptional.__NO_VALUE_ERROR_MSG)) 163 return cast(Exception, ValueError(AsyncJOptional.__NO_VALUE_ERROR_MSG)) 164 165 async def or_else_raise( 166 self, 167 supplier: Supplier[Exception] = __or_else_raise_supplier_lambda 168 ) -> T: 169 """ 170 If a value is present, returns the value, otherwise raises an exception produced by the exception supplying 171 function 172 173 Args: 174 supplier: The supplying function that produces an exception to be raised (default: ValueError) 175 176 Returns: 177 value: The value, if present 178 179 Raises: 180 Exception: If value is empty 181 TypeError: if the exception supplying function is None 182 """ 183 require_non_none(supplier) 184 if await self.is_empty(): 185 raise supplier() 186 return cast(T, self._value) 187 188 def or_get(self, supplier: Supplier[AsyncJOptional[T]]) -> AsyncJOptional[T]: 189 """ 190 This is the `or` equivalent in java Optional (Reminder: `or` is a python keyword) 191 192 If a value is present, returns an AsyncJOptional describing the value, otherwise returns an AsyncJOptional 193 produced by the supplying function 194 195 Args: 196 supplier: The supplying function that produces an AsyncJOptional to be returned 197 198 Returns: 199 AsyncJOptional[T]: Returns an AsyncJOptional describing the value of this AsyncJOptional, if a value is 200 present, otherwise an AsyncJOptional produced by the supplying function 201 202 Raises: 203 TypeError: if the supplying function is None 204 """ 205 require_non_none(supplier) 206 207 async def _async_or_get(current: AsyncJOptional[T], suppl: Supplier[AsyncJOptional[T]]) -> Optional[T]: 208 return await current.get() if await current.is_present() else await require_non_none(suppl()).or_else_get() 209 210 return AsyncJOptional.of_noneable(_async_or_get(self, supplier)) 211 212 @staticmethod # pragma: no mutate 213 def __map_lambda(v: T, mapper: Function[T, _VType[R]]) -> AsyncJOptional[R]: 214 """ 215 private static method to replace inner map lambda supplier by a function 216 Note: lambda are not used in order to be compatible with multiprocessing (lambda are not serializable) 217 """ 218 # lambda v: AsyncJOptional.of_noneable(mapper(v)) 219 return AsyncJOptional.of_noneable(mapper(v)) 220 221 def map(self, mapper: Function[T, _VType[R]]) -> AsyncJOptional[R]: 222 """ 223 If a value is present, returns an AsyncJOptional describing (as if by of_noneable) the result of applying the 224 given mapping function to the value, otherwise returns an empty AsyncJOptional 225 226 If the mapping function returns a None result then this method returns an empty AsyncJOptional. 227 228 Note: mapping function can be sync or Awaitable (like async coroutine) 229 230 Args: 231 mapper: The mapping function to apply to a value, if present 232 233 Returns: 234 AsyncJOptional[R]: An AsyncJOptional describing the result of applying a mapping function to the value of 235 this AsyncJOptional, if a value is present, otherwise an empty AsyncJOptional 236 237 Raises: 238 TypeError: If the mapping function is None 239 """ 240 require_non_none(mapper) 241 return self.flat_map(partial(AsyncJOptional.__map_lambda, mapper=mapper)) 242 243 def flat_map(self, mapper: Function[T, AsyncJOptional[R]]) -> AsyncJOptional[R]: 244 """ 245 If a value is present, returns the result of applying the given AsyncJOptional-bearing mapping function to the 246 value, otherwise returns an empty AsyncJOptional 247 248 This method is similar to map(Function), but the mapping function is one whose result is already an 249 AsyncJOptional, and if invoked, flatMap does not wrap it within an additional AsyncJOptional 250 251 Args: 252 mapper: The mapping function to apply to a value, if present 253 254 Returns: 255 AsyncJOptional[R]: The result of applying a AsyncJOptional-bearing mapping function to the value of this 256 AsyncJOptional, if a value is present, otherwise an empty AsyncJOptional 257 258 Raises: 259 TypeError: if the mapping function is None 260 """ 261 require_non_none(mapper) 262 263 async def _async_flat_map( 264 current: AsyncJOptional[T], flat_mapper: Function[T, AsyncJOptional[R]] 265 ) -> Optional[R]: 266 if await current.is_present(): 267 new_async_joptional: AsyncJOptional[R] = require_non_none(flat_mapper(await current.get())) 268 return await new_async_joptional.or_else_get() 269 return None 270 271 return AsyncJOptional.of_noneable(_async_flat_map(self, mapper)) 272 273 async def if_present(self, consumer: Consumer[T]) -> None: 274 """ 275 If a value is present, performs the given consumer with the value, otherwise does nothing 276 277 Args: 278 consumer: The consumer to be performed, if a value is present 279 280 Returns: 281 Nothing 282 283 Raises: 284 TypeError: if the consumer is None 285 """ 286 require_non_none(consumer) 287 # pylint: disable=W0106 288 (await self.is_present()) and consumer(cast(T, self._value)) 289 290 async def if_empty(self, empty_action: Runnable) -> None: 291 """ 292 If a value is not present, performs the given runnable, otherwise does nothing 293 294 Args: 295 empty_action: The runnable to be performed, if a value is not present 296 297 Returns: 298 Nothing 299 300 Raises: 301 TypeError: if the runnable is None 302 """ 303 require_non_none(empty_action) 304 # pylint: disable=W0106 305 (await self.is_empty()) and empty_action() 306 307 async def if_present_or_else(self, consumer: Consumer[T], empty_action: Runnable) -> None: 308 """ 309 If a value is present, performs the given consumer with the value, otherwise performs the given empty_action 310 311 Args: 312 consumer: The consumer to be performed, if a value is present 313 empty_action: The runnable to be performed, if a value is not 314 315 Returns: 316 Nothing 317 318 Raises: 319 TypeError: if the consumer is None or if the runnable is None 320 """ 321 require_non_none(consumer) 322 require_non_none(empty_action) 323 # pylint: disable=W0106 324 consumer(cast(T, self._value)) if await self.is_present() else empty_action() 325 326 def filter(self, predicate: Predicate[T]) -> AsyncJOptional[T]: 327 """ 328 If a value is present, and the value matches the given predicate, returns an AsyncJOptional describing the 329 value, otherwise returns an empty AsyncJOptional 330 331 Args: 332 predicate: The predicate to apply to a value, if present 333 334 Returns: 335 AsyncJOptional[T]: An AsyncJOptional describing the value of this AsyncJOptional, if a value is present and 336 the value matches the given predicate, otherwise an empty AsyncJOptional 337 338 Raises: 339 TypeError: if the predicate is None 340 """ 341 require_non_none(predicate) 342 343 async def _async_filter(current: AsyncJOptional[T]) -> Optional[T]: 344 return await current.or_else_get() if await current.is_empty() or predicate(await current.get()) else None 345 346 return AsyncJOptional.of_noneable(_async_filter(self)) 347 348 def peek(self, consumer: Consumer[T]) -> AsyncJOptional[T]: 349 """ 350 If a value is present, performs the given consumer with the value, otherwise does nothing and returns the 351 current equivalent of AsyncJOptional 352 353 Args: 354 consumer: The consumer to be performed, if a value is present 355 356 Returns: 357 AsyncJOptional[T]: The current equivalent of AsyncJOptional 358 359 Raises: 360 TypeError: if the consumer is None 361 """ 362 require_non_none(consumer) 363 364 async def _async_peek(current: AsyncJOptional[T], cons: Consumer[T]) -> Optional[T]: 365 await current.if_present(cons) 366 return await current.or_else_get() 367 368 return AsyncJOptional.of_noneable(_async_peek(self, consumer)) 369 370 def to_joptional(self) -> JOptional[Awaitable[Optional[T]]]: 371 """ 372 Convert the current AsyncJOptional to a JOptional 373 374 Note: the returned JOptional will contain an Awaitable[Optional[T]] value 375 376 Returns: 377 JOptional[Awaitable[Optional[T]]]: The corresponding JOptional 378 """ 379 return JOptional.of_noneable(cast(Awaitable[Optional[T]], self._get_value()))
A JOptional class for async value mapping
77 def __init__(self, value: _VType[T], create_key: object): 78 """AsyncJOptional private constructor: Constructs an instance with the described value""" 79 assert create_key == self.__CREATE_KEY, \ 80 "AsyncJOptional private constructor! Please use AsyncJOptional.of or AsyncJOptional.of_noneable" 81 self._value: _VType[T] = value
AsyncJOptional private constructor: Constructs an instance with the described value
38 @classmethod 39 # pylint: disable=E1136 40 def of(cls, value: _VType[T]) -> AsyncJOptional[T]: 41 """ 42 Returns a JOptional describing the given non-None value or Awaitable value 43 44 Args: 45 value: The value (or Awaitable value) to describe, which must be non-None and not an Awaitable of None 46 47 Returns: 48 JOptional[T]: A JOptional of value T or Awaitable[T] type with the value present 49 50 Raises: 51 TypeError: Raises a TypeError on terminal operation if value is None or is an Awaitable of None 52 """ 53 return AsyncJOptional(async_require_non_none(value, cls.__NO_VALUE_ERROR_MSG), cls.__CREATE_KEY)
Returns a JOptional describing the given non-None value or Awaitable value
Arguments:
- value: The value (or Awaitable value) to describe, which must be non-None and not an Awaitable of None
Returns:
JOptional[T]: A JOptional of value T or Awaitable[T] type with the value present
Raises:
- TypeError: Raises a TypeError on terminal operation if value is None or is an Awaitable of None
55 @classmethod 56 # pylint: disable=E1136 57 def of_noneable(cls, value: _VType[T]) -> AsyncJOptional[T]: 58 """ 59 Returns a JOptional describing the given value or Awaitable value, if non-None, otherwise returns an empty 60 AsyncJOptional 61 62 Args: 63 value: The possibly-None or Awaitable of None value to describe 64 65 Returns: 66 JOptional[T]: A JOptional of value T or Awaitable[T] type with the value present if the specified value is 67 non-None, otherwise an empty AsyncJOptional 68 """ 69 return AsyncJOptional(value, cls.__CREATE_KEY)
Returns a JOptional describing the given value or Awaitable value, if non-None, otherwise returns an empty AsyncJOptional
Arguments:
- value: The possibly-None or Awaitable of None value to describe
Returns:
JOptional[T]: A JOptional of value T or Awaitable[T] type with the value present if the specified value is non-None, otherwise an empty AsyncJOptional
71 @classmethod 72 def empty(cls) -> AsyncJOptional[T]: 73 """Return an empty instance of AsyncJOptional""" 74 return cls.__EMPTY
Return an empty instance of AsyncJOptional
94 async def is_present(self) -> bool: 95 """ 96 If a value is present, returns true, otherwise false 97 98 Note: A value is present when not None and not an Awaitable of None 99 100 Returns: 101 bool: true if a value is not None and not an Awaitable of None, otherwise false 102 """ 103 return non_none(await self._get_value())
If a value is present, returns true, otherwise false
Note: A value is present when not None and not an Awaitable of None
Returns:
bool: true if a value is not None and not an Awaitable of None, otherwise false
105 async def is_empty(self) -> bool: 106 """ 107 If a value is not present, returns true, otherwise false. 108 109 Note: A value is empty when None or an Awaitable of None 110 111 Returns: 112 bool: true if a value is None or an Awaitable of None, otherwise false 113 """ 114 return is_none(await self._get_value())
If a value is not present, returns true, otherwise false.
Note: A value is empty when None or an Awaitable of None
Returns:
bool: true if a value is None or an Awaitable of None, otherwise false
116 def get(self) -> Awaitable[T]: 117 """ 118 If a value is present, returns the value, otherwise raises a ValueError 119 120 Returns: 121 value: The non-None value described by this AsyncJOptional 122 123 Raises: 124 ValueError: Raises a ValueError if the value is empty 125 """ 126 return self.or_else_raise()
If a value is present, returns the value, otherwise raises a ValueError
Returns:
value: The non-None value described by this AsyncJOptional
Raises:
- ValueError: Raises a ValueError if the value is empty
128 def or_else(self, other: Optional[T] = None) -> Awaitable[Optional[T]]: 129 """ 130 If a value is present, returns the value, otherwise returns other 131 132 Args: 133 other: The value to be returned, if no value is present. May be None. 134 135 Returns: 136 value: The value, if present, otherwise other 137 """ 138 return self.or_else_get(cast(Supplier[Optional[T]], partial(to_self, obj=other)))
If a value is present, returns the value, otherwise returns other
Arguments:
- other: The value to be returned, if no value is present. May be None.
Returns:
value: The value, if present, otherwise other
140 async def or_else_get(self, supplier: Supplier[Optional[T]] = to_none) -> Optional[T]: 141 """ 142 If a value is present, returns the value, otherwise returns the result produced by the supplying function 143 144 Args: 145 supplier: The supplying function that produces a value to be returned 146 147 Returns: 148 value: The value, if present, otherwise the result produced by the supplying function 149 150 Raises: 151 TypeError: if the supplying function is None 152 """ 153 require_non_none(supplier) 154 return cast(Optional[T], self._value if await self.is_present() else supplier())
If a value is present, returns the value, otherwise returns the result produced by the supplying function
Arguments:
- supplier: The supplying function that produces a value to be returned
Returns:
value: The value, if present, otherwise the result produced by the supplying function
Raises:
- TypeError: if the supplying function is None
165 async def or_else_raise( 166 self, 167 supplier: Supplier[Exception] = __or_else_raise_supplier_lambda 168 ) -> T: 169 """ 170 If a value is present, returns the value, otherwise raises an exception produced by the exception supplying 171 function 172 173 Args: 174 supplier: The supplying function that produces an exception to be raised (default: ValueError) 175 176 Returns: 177 value: The value, if present 178 179 Raises: 180 Exception: If value is empty 181 TypeError: if the exception supplying function is None 182 """ 183 require_non_none(supplier) 184 if await self.is_empty(): 185 raise supplier() 186 return cast(T, self._value)
If a value is present, returns the value, otherwise raises an exception produced by the exception supplying function
Arguments:
- supplier: The supplying function that produces an exception to be raised (default: ValueError)
Returns:
value: The value, if present
Raises:
- Exception: If value is empty
- TypeError: if the exception supplying function is None
188 def or_get(self, supplier: Supplier[AsyncJOptional[T]]) -> AsyncJOptional[T]: 189 """ 190 This is the `or` equivalent in java Optional (Reminder: `or` is a python keyword) 191 192 If a value is present, returns an AsyncJOptional describing the value, otherwise returns an AsyncJOptional 193 produced by the supplying function 194 195 Args: 196 supplier: The supplying function that produces an AsyncJOptional to be returned 197 198 Returns: 199 AsyncJOptional[T]: Returns an AsyncJOptional describing the value of this AsyncJOptional, if a value is 200 present, otherwise an AsyncJOptional produced by the supplying function 201 202 Raises: 203 TypeError: if the supplying function is None 204 """ 205 require_non_none(supplier) 206 207 async def _async_or_get(current: AsyncJOptional[T], suppl: Supplier[AsyncJOptional[T]]) -> Optional[T]: 208 return await current.get() if await current.is_present() else await require_non_none(suppl()).or_else_get() 209 210 return AsyncJOptional.of_noneable(_async_or_get(self, supplier))
This is the or
equivalent in java Optional (Reminder: or
is a python keyword)
If a value is present, returns an AsyncJOptional describing the value, otherwise returns an AsyncJOptional produced by the supplying function
Arguments:
- supplier: The supplying function that produces an AsyncJOptional to be returned
Returns:
AsyncJOptional[T]: Returns an AsyncJOptional describing the value of this AsyncJOptional, if a value is present, otherwise an AsyncJOptional produced by the supplying function
Raises:
- TypeError: if the supplying function is None
221 def map(self, mapper: Function[T, _VType[R]]) -> AsyncJOptional[R]: 222 """ 223 If a value is present, returns an AsyncJOptional describing (as if by of_noneable) the result of applying the 224 given mapping function to the value, otherwise returns an empty AsyncJOptional 225 226 If the mapping function returns a None result then this method returns an empty AsyncJOptional. 227 228 Note: mapping function can be sync or Awaitable (like async coroutine) 229 230 Args: 231 mapper: The mapping function to apply to a value, if present 232 233 Returns: 234 AsyncJOptional[R]: An AsyncJOptional describing the result of applying a mapping function to the value of 235 this AsyncJOptional, if a value is present, otherwise an empty AsyncJOptional 236 237 Raises: 238 TypeError: If the mapping function is None 239 """ 240 require_non_none(mapper) 241 return self.flat_map(partial(AsyncJOptional.__map_lambda, mapper=mapper))
If a value is present, returns an AsyncJOptional describing (as if by of_noneable) the result of applying the given mapping function to the value, otherwise returns an empty AsyncJOptional
If the mapping function returns a None result then this method returns an empty AsyncJOptional.
Note: mapping function can be sync or Awaitable (like async coroutine)
Arguments:
- mapper: The mapping function to apply to a value, if present
Returns:
AsyncJOptional[R]: An AsyncJOptional describing the result of applying a mapping function to the value of this AsyncJOptional, if a value is present, otherwise an empty AsyncJOptional
Raises:
- TypeError: If the mapping function is None
243 def flat_map(self, mapper: Function[T, AsyncJOptional[R]]) -> AsyncJOptional[R]: 244 """ 245 If a value is present, returns the result of applying the given AsyncJOptional-bearing mapping function to the 246 value, otherwise returns an empty AsyncJOptional 247 248 This method is similar to map(Function), but the mapping function is one whose result is already an 249 AsyncJOptional, and if invoked, flatMap does not wrap it within an additional AsyncJOptional 250 251 Args: 252 mapper: The mapping function to apply to a value, if present 253 254 Returns: 255 AsyncJOptional[R]: The result of applying a AsyncJOptional-bearing mapping function to the value of this 256 AsyncJOptional, if a value is present, otherwise an empty AsyncJOptional 257 258 Raises: 259 TypeError: if the mapping function is None 260 """ 261 require_non_none(mapper) 262 263 async def _async_flat_map( 264 current: AsyncJOptional[T], flat_mapper: Function[T, AsyncJOptional[R]] 265 ) -> Optional[R]: 266 if await current.is_present(): 267 new_async_joptional: AsyncJOptional[R] = require_non_none(flat_mapper(await current.get())) 268 return await new_async_joptional.or_else_get() 269 return None 270 271 return AsyncJOptional.of_noneable(_async_flat_map(self, mapper))
If a value is present, returns the result of applying the given AsyncJOptional-bearing mapping function to the value, otherwise returns an empty AsyncJOptional
This method is similar to map(Function), but the mapping function is one whose result is already an AsyncJOptional, and if invoked, flatMap does not wrap it within an additional AsyncJOptional
Arguments:
- mapper: The mapping function to apply to a value, if present
Returns:
AsyncJOptional[R]: The result of applying a AsyncJOptional-bearing mapping function to the value of this AsyncJOptional, if a value is present, otherwise an empty AsyncJOptional
Raises:
- TypeError: if the mapping function is None
273 async def if_present(self, consumer: Consumer[T]) -> None: 274 """ 275 If a value is present, performs the given consumer with the value, otherwise does nothing 276 277 Args: 278 consumer: The consumer to be performed, if a value is present 279 280 Returns: 281 Nothing 282 283 Raises: 284 TypeError: if the consumer is None 285 """ 286 require_non_none(consumer) 287 # pylint: disable=W0106 288 (await self.is_present()) and consumer(cast(T, self._value))
If a value is present, performs the given consumer with the value, otherwise does nothing
Arguments:
- consumer: The consumer to be performed, if a value is present
Returns:
Nothing
Raises:
- TypeError: if the consumer is None
290 async def if_empty(self, empty_action: Runnable) -> None: 291 """ 292 If a value is not present, performs the given runnable, otherwise does nothing 293 294 Args: 295 empty_action: The runnable to be performed, if a value is not present 296 297 Returns: 298 Nothing 299 300 Raises: 301 TypeError: if the runnable is None 302 """ 303 require_non_none(empty_action) 304 # pylint: disable=W0106 305 (await self.is_empty()) and empty_action()
If a value is not present, performs the given runnable, otherwise does nothing
Arguments:
- empty_action: The runnable to be performed, if a value is not present
Returns:
Nothing
Raises:
- TypeError: if the runnable is None
307 async def if_present_or_else(self, consumer: Consumer[T], empty_action: Runnable) -> None: 308 """ 309 If a value is present, performs the given consumer with the value, otherwise performs the given empty_action 310 311 Args: 312 consumer: The consumer to be performed, if a value is present 313 empty_action: The runnable to be performed, if a value is not 314 315 Returns: 316 Nothing 317 318 Raises: 319 TypeError: if the consumer is None or if the runnable is None 320 """ 321 require_non_none(consumer) 322 require_non_none(empty_action) 323 # pylint: disable=W0106 324 consumer(cast(T, self._value)) if await self.is_present() else empty_action()
If a value is present, performs the given consumer with the value, otherwise performs the given empty_action
Arguments:
- consumer: The consumer to be performed, if a value is present
- empty_action: The runnable to be performed, if a value is not
Returns:
Nothing
Raises:
- TypeError: if the consumer is None or if the runnable is None
326 def filter(self, predicate: Predicate[T]) -> AsyncJOptional[T]: 327 """ 328 If a value is present, and the value matches the given predicate, returns an AsyncJOptional describing the 329 value, otherwise returns an empty AsyncJOptional 330 331 Args: 332 predicate: The predicate to apply to a value, if present 333 334 Returns: 335 AsyncJOptional[T]: An AsyncJOptional describing the value of this AsyncJOptional, if a value is present and 336 the value matches the given predicate, otherwise an empty AsyncJOptional 337 338 Raises: 339 TypeError: if the predicate is None 340 """ 341 require_non_none(predicate) 342 343 async def _async_filter(current: AsyncJOptional[T]) -> Optional[T]: 344 return await current.or_else_get() if await current.is_empty() or predicate(await current.get()) else None 345 346 return AsyncJOptional.of_noneable(_async_filter(self))
If a value is present, and the value matches the given predicate, returns an AsyncJOptional describing the value, otherwise returns an empty AsyncJOptional
Arguments:
- predicate: The predicate to apply to a value, if present
Returns:
AsyncJOptional[T]: An AsyncJOptional describing the value of this AsyncJOptional, if a value is present and the value matches the given predicate, otherwise an empty AsyncJOptional
Raises:
- TypeError: if the predicate is None
348 def peek(self, consumer: Consumer[T]) -> AsyncJOptional[T]: 349 """ 350 If a value is present, performs the given consumer with the value, otherwise does nothing and returns the 351 current equivalent of AsyncJOptional 352 353 Args: 354 consumer: The consumer to be performed, if a value is present 355 356 Returns: 357 AsyncJOptional[T]: The current equivalent of AsyncJOptional 358 359 Raises: 360 TypeError: if the consumer is None 361 """ 362 require_non_none(consumer) 363 364 async def _async_peek(current: AsyncJOptional[T], cons: Consumer[T]) -> Optional[T]: 365 await current.if_present(cons) 366 return await current.or_else_get() 367 368 return AsyncJOptional.of_noneable(_async_peek(self, consumer))
If a value is present, performs the given consumer with the value, otherwise does nothing and returns the current equivalent of AsyncJOptional
Arguments:
- consumer: The consumer to be performed, if a value is present
Returns:
AsyncJOptional[T]: The current equivalent of AsyncJOptional
Raises:
- TypeError: if the consumer is None
370 def to_joptional(self) -> JOptional[Awaitable[Optional[T]]]: 371 """ 372 Convert the current AsyncJOptional to a JOptional 373 374 Note: the returned JOptional will contain an Awaitable[Optional[T]] value 375 376 Returns: 377 JOptional[Awaitable[Optional[T]]]: The corresponding JOptional 378 """ 379 return JOptional.of_noneable(cast(Awaitable[Optional[T]], self._get_value()))
Convert the current AsyncJOptional to a JOptional
Note: the returned JOptional will contain an Awaitable[Optional[T]] value
Returns:
JOptional[Awaitable[Optional[T]]]: The corresponding JOptional