Skip to main content

A set of Python regularly used classes/functions

Project description

Dev4py-utils

A set of Python regularly used classes/functions

ci
Last release
Weekly checks
Python >= 3.11 (See: Older Python versions compatibility)
Maintainer
Maintenance
License: Apache-2.0

Table of contents

Quickstart

pip install dev4py-utils

Project template

This project is based on pymsdl_template

Project links

Older Python versions compatibility

Dev4py-utils modules

dev4py.utils.AsyncJOptional

AsyncJOptional documentation

Note: AsyncJOptional class is designed in order to simplify JOptional with async mapper.

Note: AsyncJOptional support T or Awaitable[T] values. That's why some checks are done when terminal operation is called with await.

Examples:

import asyncio
from dev4py.utils import AsyncJOptional

def sync_mapper(i: int) -> int:
  return i * 2

async def async_mapper(i: int) -> str:
  return f"The value is {i}"

async def async_sample() -> None:
  value: int = 1
  await AsyncJOptional.of_noneable(value) \
    .map(sync_mapper) \
    .map(async_mapper) \
    .if_present(print)  # The value is 2

asyncio.run(async_sample())

dev4py.utils.awaitables

Awaitables documentation

Note: awaitables module provides a set of utility functions to simplify Awaitable operations.

Examples:

import asyncio
from dev4py.utils import awaitables, JOptional

# is_awaitable sample
awaitables.is_awaitable(asyncio.sleep(2))  # True
awaitables.is_awaitable(print('Hello'))  # False


# to_sync_or_async_param_function sample
def mapper(s: str) -> str:
    return s + '_suffix'

async def async_mapper(s: str) -> str:
    await asyncio.sleep(1)
    return s + '_async_suffix'

async def async_test():
    # Note: mapper parameter is str and async_mapper returns an Awaitable[str] so we have to manage it
    # Note: !WARNING! Since 3.0.0 see AsyncJOptional / JOptional to_async_joptional method
    result: str = await JOptional.of("A value") \
      .map(async_mapper) \
      .map(awaitables.to_sync_or_async_param_function(mapper)) \
      .get()
    print(result)  # A value_async_suffix_suffix

asyncio.run(async_test())

dev4py.utils.collectors

Collectors documentation

Note: The collectors class is inspired by java.util.stream.Collectors

Examples:

from dev4py.utils import Stream, collectors

Stream.of('a', 'b', 'c').collect(collectors.to_list())  # ['a', 'b', 'c']

dev4py.utils.dicts

Dicts documentation

Note: dicts module provides a set of utility functions to simplify dict operations.

Examples:

from dev4py.utils import dicts
from dev4py.utils.types import Supplier

# is_dict sample
dicts.is_dict("A str")  # False
dicts.is_dict({'key': 'A dict value'})  # True


# get_value sample
int_supplier: Supplier[int] = lambda: 3
dictionary: dict[str, int] = {'key_1': 1, 'key_2': 2}

dicts.get_value(dictionary, 'key_1')  # 1
dicts.get_value(dictionary, 'key_3')  # None
dicts.get_value(dictionary, 'key_3', int_supplier)  # 3


# get_value_from_path sample
str_supplier: Supplier[str] = lambda: "a3"
deep_dictionary: dict[str, dict[int, str]] = { \
  'a': {1: 'a1', 2: 'a2'}, \
  'b': {1: 'b1', 2: 'b2'} \
}

dicts.get_value_from_path(deep_dictionary, ["a", 1])  # 'a1'
dicts.get_value_from_path(deep_dictionary, ["c", 1])  # None
dicts.get_value_from_path(deep_dictionary, ["a", 3])  # None
dicts.get_value_from_path(deep_dictionary, ["a", 3], str_supplier)  # 'a3'

dev4py.utils.iterables

Iterables documentation

Note: The iterables module provides a set of utility functions to simplify iterables operations.

Example:

from typing import Iterator

from dev4py.utils import iterables

values: range = range(0, 10)
chunks: Iterator[list[int]] = iterables.get_chunks(values, 3)
[chunk for chunk in chunks]  # [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

dev4py.utils.JOptional

JOptional documentation

Note: JOptional class is inspired by java.util.Optional class with some adds (like peek method).

Examples:

from dev4py.utils import JOptional

value: int = 1
JOptional.of_noneable(value) \
  .map(lambda v: f"The value is {v}") \
  .if_present(print)  # The value is 1

dev4py.utils.lists

Lists documentation

Note: lists module provides a set of utility functions to simplify lists operations.

Examples:

from dev4py.utils import lists

# empty sample
lst: list[int] = lists.empty_list()  # []

# append sample
lst: list[int] = [1, 2, 3, 4]
app_lst: list[int] = lists.append(lst, 5)  # [1, 2, 3, 4, 5]
# - Note: lst == app_lst

# extend sample
lst: list[int] = [1, 2, 3, 4]
lst2: list[int] = [5, 6, 7, 8]
ext_lst: list[int] = lists.extend(lst, lst2)  # [1, 2, 3, 4, 5, 6, 7, 8]
# - Note: lst == ext_lst

dev4py.utils.objects

Objects documentation

Note: The objects module is inspired by java.util.Objects class.

Examples:

from dev4py.utils import objects

# non_none sample
value = None
objects.non_none(value)  # False

# require_non_none sample
value = "A value"
objects.require_non_none(value)  # 'A value'

# to_string sample
value = None
default_value: str = "A default value"
objects.to_string(value, default_value)  # 'A default value'

dev4py.utils.pipeline

Pipeline documentation

Note: The pipeline package provides a set of Pipeline class describing different kind of pipelines.

Examples:

from dev4py.utils.pipeline import SimplePipeline, StepPipeline, StepResult

# SimplePipeline sample
pipeline: SimplePipeline[int, str] = SimplePipeline.of(lambda i: i * i) \
    .add_handler(str) \
    .add_handler(lambda s: f"Result: {s} | Type: {type(s)}")

pipeline.execute(10)  # "Result: 100 | Type: <class 'str'>"


# StepPipeline sample
# Note: StepPipeline can be stopped at each step by setting `go_next` value to False
pipeline: StepPipeline[int, str] = StepPipeline.of(lambda i: StepResult(i * i)) \
    .add_handler(lambda i: StepResult(value=str(i), go_next=i < 150)) \
    .add_handler(lambda s: StepResult(f"Result: {s} | Type: {type(s)}"))

pipeline.execute(10)  # StepResult(value="Result: 100 | Type: <class 'str'>", go_next=True)
# - Note: When the pipeline is fully completed, `go_next` is True
pipeline.execute(15)  # StepResult(value='225', go_next=False)
# - Note: Even if the pipeline is not fully completed, the last StepResult is returned with `go_next=False`

dev4py.utils.retry

Retry documentation

Note: The retry module provides provides function to create retryable callable from simple sync or async callables using exponential backoff

Usage idea: network requests (HTTP, AMQP, MQTT, etc.) with retry on error

Examples:

import asyncio
from time import time
from typing import Awaitable

from dev4py.utils.retry import RetryConfiguration, to_retryable, to_async_retryable, retryable, async_retryable
from dev4py.utils.types import BiFunction

# RetryConfiguration:
# Note: exponential backoff used formula is 'delay * (exponent^retry_number)'
#
#   => Example: For the following RetryConfiguration, waiting times in case of error are:
#       * first try:                    0 sec (always 0 for the first try)
#       * second try (/first retry):    1 sec ('0.5 * (2^1)')
#       * third try (/second retry):    2 sec ('0.5 * (2^2)')
#       * max_tries=3 => no fourth try (/third retry)
retry_config: RetryConfiguration = RetryConfiguration(
    delay=0.5,  # the exponential backoff delay in second (default: 0.1)
    exponent=2,  # the exponential backoff exponent to determine delay between each try (default: 2)
    max_tries=3  # max try number (first try included) (default: 3, i.e.: first try and 2 retry)
)


# to_retryable sample:
# -> SUCCESSFUL CALL SAMPLE
def callable_sample(j: int, start_time: float) -> int:
    print("callable_sample - call time: '%.2f'" % (time() - start_time))
    return j ** 2

retryable_sample: BiFunction[int, float, int] = to_retryable(sync_callable=callable_sample, retry_config=retry_config)
# Note: Since 3.5.0 you can also use `retryable(sync_callable=callable_sample, retry_config=retry_config)`

result: int = retryable_sample(3, time())  # result = 9
# outputs:
#  callable_sample - call time: '0.00'


# -> IN ERROR CALL SAMPLE
def in_error_callable_sample(j: int, start_time: float) -> int:
    print("in_error_callable_sample - call time: '%.2f'" % (time() - start_time))
    raise ValueError(j)

in_error_retryable_sample: BiFunction[int, float, int] = \
    to_retryable(sync_callable=in_error_callable_sample, retry_config=retry_config)
# Note: Since 3.5.0 you can also use `retryable(sync_callable=in_error_callable_sample, retry_config=retry_config)`
# Note: By default the last raised exception is raised if max_tries is reach. You can change this behavior by setting
#       the `on_failure` parameter
result: int = in_error_retryable_sample(3, time())
# outputs:
#  in_error_callable_sample - call time: '0.00'
#  in_error_callable_sample - call time: '1.00'
#  in_error_callable_sample - call time: '3.00'
#  ValueError: 3
#
# Note: By default the last raised exception is raised if max_tries is reached. You can change this behavior by setting
#       the `on_failure` parameter

# -> DECORATOR SAMPLE
@retryable(retry_config=retry_config)
def decorated_in_error_callable_sample(j: int, start_time: float) -> int:
    print("decorated_in_error_callable_sample - call time: '%.2f'" % (time() - start_time))
    raise ValueError(j)

result: int = decorated_in_error_callable_sample(3, time())
# outputs:
#  decorated_in_error_callable_sample - call time: '0.00'
#  decorated_in_error_callable_sample - call time: '1.00'
#  decorated_in_error_callable_sample - call time: '3.00'
#  ValueError: 3
#
# Note: By default the last raised exception is raised if max_tries is reached. You can change this behavior by setting
#       the `on_failure` parameter


# to_async_retryable sample:
# -> IN ERROR CALL ASYNC SAMPLE
async def in_error_async_callable_sample(j: int, start_time: float) -> int:
    print("in_error_async_callable_sample - call time: '%.2f'" % (time() - start_time))
    raise ValueError(j)

async def async_retryable_sample() -> None:
    in_error_async_retryable_sample: BiFunction[int, float, Awaitable[int]] = \
        to_async_retryable(async_callable=in_error_async_callable_sample, retry_config=retry_config)
    # Note: Since 3.5.0 you can also use 
    # `async_retryable(async_callable=in_error_async_callable_sample, retry_config=retry_config)`
    result: int = await in_error_async_retryable_sample(2, time())

asyncio.run(async_retryable_sample())
# outputs:
#  in_error_async_callable_sample - call time: '0.00'
#  in_error_async_callable_sample - call time: '1.00'
#  in_error_async_callable_sample - call time: '3.00'
#  ValueError: 2
#
# Note: By default the last raised exception is raised if max_tries is reached. You can change this behavior by setting
#       the `on_failure` parameter

# -> DECORATOR ASYNC SAMPLE
@async_retryable(retry_config=retry_config)
async def decorated_in_error_async_callable_sample(j: int, start_time: float) -> int:
    print("decorated_in_error_async_callable_sample - call time: '%.2f'" % (time() - start_time))
    raise ValueError(j)

async def async_decorated_retryable_sample() -> None:
    result: int = await decorated_in_error_async_callable_sample(2, time())

asyncio.run(async_decorated_retryable_sample())
# outputs:
#  in_error_async_callable_sample - call time: '0.00'
#  in_error_async_callable_sample - call time: '1.00'
#  in_error_async_callable_sample - call time: '3.00'
#  ValueError: 2
#
# Note: By default the last raised exception is raised if max_tries is reached. You can change this behavior by setting
#       the `on_failure` parameter

dev4py.utils.Stream

Stream documentation

Note: Stream class is inspired by java.util.stream.Stream.

Examples:

from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
from time import sleep

from dev4py.utils import Stream, ParallelConfiguration

# Sequential sample
Stream.of(1, 2, 3, 4) \
    .map(str) \
    .peek(lambda s: sleep(0.5)) \
    .map(lambda s: f"Mapped value: {s}") \
    .to_list()  # ['Mapped value: 1', 'Mapped value: 2', 'Mapped value: 3', 'Mapped value: 4']
# - Note: Execution time around 2 sec due to the sleep call


# Multithreading sample
with ThreadPoolExecutor(max_workers=2) as executor:
    Stream.of(1, 2, 3, 4) \
        .parallel(parallel_config=ParallelConfiguration(executor=executor, chunksize=2)) \
        .map(str) \
        .peek(lambda s: sleep(0.5)) \
        .map(lambda s: f"Mapped value: {s}") \
        .to_list()  # ['Mapped value: 3', 'Mapped value: 4', 'Mapped value: 1', 'Mapped value: 2']
# - Note: Execution time around 1 sec due to the given ParallelConfiguration
# - Note: Since this stream is (by default) unordered, results order is random


# Multiprocessing sample
# - Note: Due to use of Multiprocessing:
#       * lambdas cannot be used since they cannot be pickled
#       * This sample should be put in a python file in order to work
def _sleep(s: str) -> None:
    # eq lambda s: sleep(0.5)
    sleep(0.5)

def _mapper(s: str) -> str:
    # eq lambda s: f"Mapped value: {s}"
    return f"Mapped value: {s}"

if __name__ == '__main__':
    with ProcessPoolExecutor(max_workers=2) as executor:
        Stream.of(1, 2, 3, 4) \
            .parallel(parallel_config=ParallelConfiguration(executor=executor, chunksize=2)) \
            .map(str) \
            .peek(_sleep) \
            .map(_mapper) \
            .to_list()

# - Note: Execution time around 1 sec due to the given ParallelConfiguration
#         (Reminder: Use Multiprocessing for CPU-bound tasks. In this case Multithreading is more appropriate)
# - Note: Since this stream is (by default) unordered, results order is random

dev4py.utils.tuples

Tuples documentation

Note: tuples module provides a set of utility functions to simplify tuples operations.

Examples:

from dev4py.utils import tuples

# empty sample
tpl: tuple[int, ...] = tuples.empty_tuple()  # ()

# append sample
tpl: tuple[int, ...] = (1, 2, 3, 4)
app_tpl: tuple[int, ...] = tuples.append(tpl, 5)  # (1, 2, 3, 4, 5)

# extend sample
tpl: tuple[int, ...] = (1, 2, 3, 4)
tpl2: tuple[int, ...] = (5, 6, 7, 8)
ext_tpl: tuple[int, ...] = tuples.extend(tpl, tpl2)  # (1, 2, 3, 4, 5, 6, 7, 8)

dev4py.utils.types

Types documentation

Note: The types module is inspired by java.util.function package.

Examples:

from dev4py.utils.types import Function, Predicate, Consumer

# Function sample
int_to_str: Function[int, str] = lambda i: str(i)
str_result: str = int_to_str(1)  # '1'

# Predicate sample
str_predicate: Predicate[str] = lambda s: s == "A value"
pred_result: bool = str_predicate("Value to test")  # False

# Consumer sample
def sample(consumer: Consumer[str], value: str) -> None:
    consumer(value)

def my_consumer(arg: str) -> None:
    print(arg)

sample(my_consumer, "My value")  # My value

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dev4py_utils-4.1.0.tar.gz (66.9 kB view details)

Uploaded Source

Built Distribution

dev4py_utils-4.1.0-py3-none-any.whl (42.5 kB view details)

Uploaded Python 3

File details

Details for the file dev4py_utils-4.1.0.tar.gz.

File metadata

  • Download URL: dev4py_utils-4.1.0.tar.gz
  • Upload date:
  • Size: 66.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.11.9 Linux/6.5.0-1021-azure

File hashes

Hashes for dev4py_utils-4.1.0.tar.gz
Algorithm Hash digest
SHA256 6c068539e8a2003d4655850659db4ecf1e03c71bda6b183a2fd46909921f40c2
MD5 757968f5f5e736a49097df374f128edc
BLAKE2b-256 952502c90c26635e447f6c680e593a8c7257a1eb22ec2728b7bcd23eb66f5e31

See more details on using hashes here.

File details

Details for the file dev4py_utils-4.1.0-py3-none-any.whl.

File metadata

  • Download URL: dev4py_utils-4.1.0-py3-none-any.whl
  • Upload date:
  • Size: 42.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.11.9 Linux/6.5.0-1021-azure

File hashes

Hashes for dev4py_utils-4.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 98f54a29e46744916759961f9805331af74e2460c7b3c68688377a1b8f13233f
MD5 f48da0a1822ea2a6ba4eca074ba94cc9
BLAKE2b-256 826231e5336a74ec34254f2144f58fbf4fb92a9d5eed9aef89e8925e777bd91e

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page