dycw-utilities 0.131.16__tar.gz → 0.131.17__tar.gz
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.
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/PKG-INFO +1 -1
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/pyproject.toml +2 -3
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_asyncio.py +95 -96
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_asyncio_classes/loopers.py +13 -12
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_asyncio_classes/redis.py +7 -7
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_atools.py +3 -3
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_cachetools.py +2 -2
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_fastapi.py +2 -1
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pottery.py +33 -26
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_psutil.py +3 -3
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_redis.py +40 -35
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_slack_sdk.py +17 -8
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_sqlalchemy.py +11 -9
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_timer.py +17 -35
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/__init__.py +1 -1
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/asyncio.py +47 -60
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pottery.py +16 -19
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/psutil.py +8 -7
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/redis.py +108 -116
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/slack_sdk.py +17 -18
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/sqlalchemy.py +36 -30
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/sqlalchemy_polars.py +12 -27
- dycw_utilities-0.131.16/src/tests/test_tenacity.py +0 -113
- dycw_utilities-0.131.16/src/utilities/tenacity.py +0 -145
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/.gitignore +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/LICENSE +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/README.md +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/__init__.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/conftest.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/__init__.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_missing/__init__.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_missing/module.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_with/__init__.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_with/outer_1.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_with/outer_2.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_without/__init__.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_without/module_1.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/package_without/module_2.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/standalone.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/modules/with_imports.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_aiolimiter.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_altair.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_asyncio_classes/__init__.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_atomicwrites.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_click.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_concurrent.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_contextlib.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_contextvars.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_cryptography.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_cvxpy.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_dataclasses.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_datetime.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_enum.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_errors.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_eventkit.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_fpdf2.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_functions.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_functools.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_getpass.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_git.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_hashlib.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_http.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_hypothesis.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_importlib.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_inflect.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_ipython.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_iterables.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_jupyter.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_libcst.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_lightweight_charts.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_logging.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_luigi.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_math.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_memory_profiler.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_modules.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_more_itertools.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_numpy.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_operator.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_optuna.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_orjson.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_os.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_parse.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pathlib.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_period.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pickle.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_platform.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_polars.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_polars_ols.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pqdm.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pydantic.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pyinstrument.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pyrsistent.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pytest.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_pytest_regressions.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_python_dotenv.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_random.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_re.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_reprlib.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_scipy.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_sentinel.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_shelve.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_socket.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_statsmodel.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_streamlit.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_string.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_tempfile.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_text.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_threading.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_traceback.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_typed_settings.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_types.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_typing.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_typing_funcs/__init__.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_typing_funcs/no_future.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_typing_funcs/with_future.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_tzdata.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_tzlocal.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_uuid.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_version.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_warnings.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_whenever.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_whenever2.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_zipfile.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_zoneinfo.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/aiolimiter.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/altair.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/atomicwrites.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/atools.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/cachetools.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/click.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/concurrent.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/contextlib.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/contextvars.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/cryptography.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/cvxpy.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/dataclasses.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/datetime.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/enum.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/errors.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/eventkit.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/fastapi.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/fpdf2.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/functions.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/functools.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/getpass.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/git.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/hashlib.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/http.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/hypothesis.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/importlib.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/inflect.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/ipython.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/iterables.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/jupyter.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/libcst.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/lightweight_charts.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/logging.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/luigi.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/math.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/memory_profiler.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/modules.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/more_itertools.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/numpy.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/operator.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/optuna.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/orjson.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/os.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/parse.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pathlib.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/period.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pickle.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/platform.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/polars.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/polars_ols.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pqdm.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/py.typed +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pydantic.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pyinstrument.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pyrsistent.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pytest.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/pytest_regressions.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/python_dotenv.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/random.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/re.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/reprlib.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/scipy.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/sentinel.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/shelve.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/socket.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/statsmodels.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/streamlit.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/string.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/tempfile.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/text.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/threading.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/timer.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/traceback.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/typed_settings.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/types.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/typing.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/tzdata.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/tzlocal.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/uuid.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/version.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/warnings.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/whenever.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/whenever2.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/zipfile.py +0 -0
- {dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/utilities/zoneinfo.py +0 -0
@@ -59,7 +59,6 @@ dev = [
|
|
59
59
|
"sqlalchemy >= 2.0.41, < 2.1",
|
60
60
|
"statsmodels >= 0.14.4, < 0.15",
|
61
61
|
"streamlit >= 1.45.0, < 1.46",
|
62
|
-
"tenacity >= 8.5.0, < 9.0", # limited by luigi
|
63
62
|
"tomlkit >= 0.13.2, < 0.14",
|
64
63
|
"typed-settings >= 24.6.0, < 24.7",
|
65
64
|
"tzdata >= 2025.2, < 2025.3",
|
@@ -95,7 +94,7 @@ dependencies = [
|
|
95
94
|
name = "dycw-utilities"
|
96
95
|
readme = "README.md"
|
97
96
|
requires-python = ">= 3.12"
|
98
|
-
version = "0.131.
|
97
|
+
version = "0.131.17"
|
99
98
|
|
100
99
|
[project.optional-dependencies]
|
101
100
|
logging = [
|
@@ -122,7 +121,7 @@ test = [
|
|
122
121
|
# bump-my-version
|
123
122
|
[tool.bumpversion]
|
124
123
|
allow_dirty = true
|
125
|
-
current_version = "0.131.
|
124
|
+
current_version = "0.131.17"
|
126
125
|
|
127
126
|
[[tool.bumpversion.files]]
|
128
127
|
filename = "src/utilities/__init__.py"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
from asyncio import Event, Queue, run
|
3
|
+
from asyncio import Event, Queue, run
|
4
4
|
from collections import deque
|
5
5
|
from contextlib import asynccontextmanager
|
6
6
|
from dataclasses import dataclass, field
|
@@ -8,7 +8,7 @@ from itertools import chain
|
|
8
8
|
from re import search
|
9
9
|
from typing import TYPE_CHECKING, Any, ClassVar, Self, override
|
10
10
|
|
11
|
-
from hypothesis import
|
11
|
+
from hypothesis import assume, given
|
12
12
|
from hypothesis.strategies import (
|
13
13
|
DataObject,
|
14
14
|
booleans,
|
@@ -49,27 +49,28 @@ from utilities.asyncio import (
|
|
49
49
|
get_items_nowait,
|
50
50
|
put_items,
|
51
51
|
put_items_nowait,
|
52
|
-
|
53
|
-
|
52
|
+
sleep_max,
|
53
|
+
sleep_rounded,
|
54
|
+
sleep_td,
|
54
55
|
sleep_until,
|
55
|
-
sleep_until_rounded,
|
56
56
|
stream_command,
|
57
|
-
|
57
|
+
timeout_td,
|
58
58
|
)
|
59
59
|
from utilities.dataclasses import replace_non_sentinel
|
60
|
-
from utilities.datetime import MILLISECOND, datetime_duration_to_timedelta, get_now
|
61
60
|
from utilities.functions import get_class_name
|
62
61
|
from utilities.hypothesis import sentinels, text_ascii
|
63
62
|
from utilities.iterables import one, unique_everseen
|
64
63
|
from utilities.pytest import skipif_windows
|
65
64
|
from utilities.sentinel import Sentinel, sentinel
|
66
65
|
from utilities.timer import Timer
|
66
|
+
from utilities.whenever2 import SECOND, get_now
|
67
67
|
|
68
68
|
if TYPE_CHECKING:
|
69
|
-
import datetime as dt
|
70
69
|
from collections.abc import AsyncIterator
|
71
70
|
|
72
|
-
from
|
71
|
+
from whenever import TimeDelta
|
72
|
+
|
73
|
+
from utilities.types import MaybeCallableEvent
|
73
74
|
|
74
75
|
|
75
76
|
class TestEnhancedQueue:
|
@@ -144,6 +145,8 @@ class TestEnhancedQueue:
|
|
144
145
|
|
145
146
|
|
146
147
|
class TestEnhancedTaskGroup:
|
148
|
+
delta: ClassVar[TimeDelta] = 0.05 * SECOND
|
149
|
+
|
147
150
|
async def test_create_task_context_coroutine(self) -> None:
|
148
151
|
flag: bool = False
|
149
152
|
|
@@ -157,43 +160,43 @@ class TestEnhancedTaskGroup:
|
|
157
160
|
flag = False
|
158
161
|
|
159
162
|
assert not flag
|
160
|
-
async with EnhancedTaskGroup(timeout=
|
163
|
+
async with EnhancedTaskGroup(timeout=2 * self.delta) as tg:
|
161
164
|
_ = tg.create_task_context(yield_true())
|
162
|
-
await
|
165
|
+
await sleep_td(self.delta)
|
163
166
|
assert flag
|
164
167
|
assert not flag
|
165
168
|
|
166
169
|
async def test_create_task_context_looper(self) -> None:
|
167
|
-
looper = CountingLooper().replace(timeout=
|
170
|
+
looper = CountingLooper().replace(timeout=10 * self.delta)
|
168
171
|
assert looper._core_attempts == 0
|
169
|
-
async with EnhancedTaskGroup(timeout=
|
172
|
+
async with EnhancedTaskGroup(timeout=2 * self.delta) as tg:
|
170
173
|
assert looper._core_attempts == 0
|
171
174
|
_ = tg.create_task_context(looper)
|
172
|
-
await
|
175
|
+
await sleep_td(self.delta)
|
173
176
|
assert looper._core_attempts >= 1
|
174
177
|
|
175
178
|
async def test_max_tasks_disabled(self) -> None:
|
176
179
|
with Timer() as timer:
|
177
180
|
async with EnhancedTaskGroup() as tg:
|
178
181
|
for _ in range(10):
|
179
|
-
_ = tg.create_task(
|
180
|
-
assert timer
|
182
|
+
_ = tg.create_task(sleep_td(self.delta))
|
183
|
+
assert timer <= 2 * self.delta
|
181
184
|
|
182
185
|
async def test_max_tasks_enabled(self) -> None:
|
183
186
|
with Timer() as timer:
|
184
187
|
async with EnhancedTaskGroup(max_tasks=2) as tg:
|
185
188
|
for _ in range(10):
|
186
|
-
_ = tg.create_task(
|
187
|
-
assert timer
|
189
|
+
_ = tg.create_task(sleep_td(self.delta))
|
190
|
+
assert timer >= self.delta
|
188
191
|
|
189
192
|
async def test_timeout_pass(self) -> None:
|
190
|
-
async with EnhancedTaskGroup(timeout=
|
191
|
-
_ = tg.create_task(
|
193
|
+
async with EnhancedTaskGroup(timeout=2 * self.delta) as tg:
|
194
|
+
_ = tg.create_task(sleep_td(self.delta))
|
192
195
|
|
193
196
|
async def test_timeout_fail(self) -> None:
|
194
197
|
with raises(ExceptionGroup) as exc_info:
|
195
|
-
async with EnhancedTaskGroup(timeout=
|
196
|
-
_ = tg.create_task(
|
198
|
+
async with EnhancedTaskGroup(timeout=self.delta) as tg:
|
199
|
+
_ = tg.create_task(sleep_td(2 * self.delta))
|
197
200
|
assert len(exc_info.value.exceptions) == 1
|
198
201
|
error = one(exc_info.value.exceptions)
|
199
202
|
assert isinstance(error, TimeoutError)
|
@@ -202,8 +205,8 @@ class TestEnhancedTaskGroup:
|
|
202
205
|
class CustomError(Exception): ...
|
203
206
|
|
204
207
|
with raises(ExceptionGroup) as exc_info:
|
205
|
-
async with EnhancedTaskGroup(timeout=
|
206
|
-
_ = tg.create_task(
|
208
|
+
async with EnhancedTaskGroup(timeout=self.delta, error=CustomError) as tg:
|
209
|
+
_ = tg.create_task(sleep_td(2 * self.delta))
|
207
210
|
assert len(exc_info.value.exceptions) == 1
|
208
211
|
error = one(exc_info.value.exceptions)
|
209
212
|
assert isinstance(error, CustomError)
|
@@ -259,12 +262,8 @@ class TestGetItems:
|
|
259
262
|
|
260
263
|
|
261
264
|
class TestLooper:
|
262
|
-
_restart_min_elapsed: ClassVar[
|
263
|
-
|
264
|
-
)
|
265
|
-
_restart_max_elapsed: ClassVar[dt.timedelta] = datetime_duration_to_timedelta(
|
266
|
-
(1.2 if IS_CI else 1.0) * _FREQ
|
267
|
-
)
|
265
|
+
_restart_min_elapsed: ClassVar[TimeDelta] = (0.8 if IS_CI else 1.0) * _BACKOFF
|
266
|
+
_restart_max_elapsed: ClassVar[TimeDelta] = (1.2 if IS_CI else 1.0) * _FREQ
|
268
267
|
skip_sleep_if_failure_cases: ClassVar[list[Any]] = [
|
269
268
|
param(True, ""),
|
270
269
|
param(False, "; sleeping for .*"),
|
@@ -279,12 +278,12 @@ class TestLooper:
|
|
279
278
|
async def test_auto_start(self) -> None:
|
280
279
|
looper = CountingLooper(auto_start=True)
|
281
280
|
with raises(TimeoutError):
|
282
|
-
async with
|
281
|
+
async with timeout_td(SECOND), looper:
|
283
282
|
...
|
284
283
|
self._assert_stats_full(looper)
|
285
284
|
|
286
285
|
async def test_auto_start_and_timeout(self) -> None:
|
287
|
-
looper = CountingLooper(auto_start=True, timeout=
|
286
|
+
looper = CountingLooper(auto_start=True, timeout=SECOND)
|
288
287
|
async with looper:
|
289
288
|
...
|
290
289
|
self._assert_stats_full(looper, stops=1)
|
@@ -298,7 +297,7 @@ class TestLooper:
|
|
298
297
|
async def test_context_manager_already_entered(
|
299
298
|
self, *, caplog: LogCaptureFixture
|
300
299
|
) -> None:
|
301
|
-
looper = CountingLooper(timeout=
|
300
|
+
looper = CountingLooper(timeout=SECOND)
|
302
301
|
async with looper, looper:
|
303
302
|
...
|
304
303
|
_ = one(m for m in caplog.messages if search(": already entered$", m))
|
@@ -311,10 +310,10 @@ class TestLooper:
|
|
311
310
|
assert not looper.empty()
|
312
311
|
|
313
312
|
async def test_empty_upon_exit(self) -> None:
|
314
|
-
looper = QueueLooper(freq=0.05, empty_upon_exit=True)
|
313
|
+
looper = QueueLooper(freq=0.05 * SECOND, empty_upon_exit=True)
|
315
314
|
looper.put_right_nowait(0)
|
316
315
|
assert not looper.empty()
|
317
|
-
async with
|
316
|
+
async with timeout_td(SECOND), looper:
|
318
317
|
...
|
319
318
|
self._assert_stats_no_runs(looper, entries=1, stops=1)
|
320
319
|
assert looper.empty()
|
@@ -322,7 +321,7 @@ class TestLooper:
|
|
322
321
|
async def test_explicit_start(self) -> None:
|
323
322
|
looper = CountingLooper()
|
324
323
|
with raises(TimeoutError):
|
325
|
-
async with
|
324
|
+
async with timeout_td(SECOND), looper:
|
326
325
|
await looper
|
327
326
|
self._assert_stats_full(looper, stops=1)
|
328
327
|
|
@@ -373,11 +372,11 @@ class TestLooper:
|
|
373
372
|
@mark.parametrize("counter_auto_start", [param(True), param(False)])
|
374
373
|
async def test_mixin(self, *, counter_auto_start: bool) -> None:
|
375
374
|
looper = LooperWithCounterMixin(
|
376
|
-
auto_start=True, timeout=
|
375
|
+
auto_start=True, timeout=SECOND, counter_auto_start=counter_auto_start
|
377
376
|
)
|
378
377
|
if counter_auto_start:
|
379
378
|
with raises(TimeoutError):
|
380
|
-
async with
|
379
|
+
async with timeout_td(SECOND), looper:
|
381
380
|
...
|
382
381
|
self._assert_stats_half(looper._counter)
|
383
382
|
else:
|
@@ -388,7 +387,7 @@ class TestLooper:
|
|
388
387
|
@mark.parametrize("counter_auto_start", [param(True), param(False)])
|
389
388
|
async def test_mixin_in_task_group(self, *, counter_auto_start: bool) -> None:
|
390
389
|
looper = LooperWithCounterMixin(
|
391
|
-
auto_start=True, timeout=
|
390
|
+
auto_start=True, timeout=SECOND, counter_auto_start=counter_auto_start
|
392
391
|
)
|
393
392
|
with raises(ExceptionGroup) as exc_info:
|
394
393
|
async with EnhancedTaskGroup(timeout=looper.timeout) as tg:
|
@@ -404,21 +403,21 @@ class TestLooper:
|
|
404
403
|
) -> None:
|
405
404
|
looper = LooperWithCounterMixins(
|
406
405
|
auto_start=True,
|
407
|
-
timeout=
|
406
|
+
timeout=SECOND,
|
408
407
|
counter1_auto_start=counter1_auto_start,
|
409
408
|
counter2_auto_start=counter2_auto_start,
|
410
409
|
)
|
411
410
|
match counter1_auto_start, counter2_auto_start:
|
412
411
|
case _, True:
|
413
412
|
with raises(TimeoutError):
|
414
|
-
async with
|
413
|
+
async with timeout_td(SECOND), looper:
|
415
414
|
...
|
416
415
|
assert_looper_full(looper)
|
417
416
|
self._assert_stats_no_runs(looper._counter1)
|
418
417
|
self._assert_stats_third(looper._counter2)
|
419
418
|
case True, False:
|
420
419
|
with raises(TimeoutError):
|
421
|
-
async with
|
420
|
+
async with timeout_td(SECOND), looper:
|
422
421
|
...
|
423
422
|
assert_looper_full(looper)
|
424
423
|
self._assert_stats_half(looper._counter1)
|
@@ -433,13 +432,13 @@ class TestLooper:
|
|
433
432
|
@mark.parametrize("counter_auto_start", [param(True), param(False)])
|
434
433
|
async def test_mixins_in_task_group(self, *, counter_auto_start: bool) -> None:
|
435
434
|
looper1 = LooperWithCounterMixin(
|
436
|
-
auto_start=True, timeout=
|
435
|
+
auto_start=True, timeout=SECOND, counter_auto_start=counter_auto_start
|
437
436
|
)
|
438
437
|
looper2 = LooperWithCounterMixin(
|
439
|
-
auto_start=True, timeout=
|
438
|
+
auto_start=True, timeout=SECOND, counter_auto_start=counter_auto_start
|
440
439
|
)
|
441
440
|
with raises(ExceptionGroup) as exc_info: # noqa: PT012
|
442
|
-
async with EnhancedTaskGroup(timeout=
|
441
|
+
async with EnhancedTaskGroup(timeout=SECOND) as tg:
|
443
442
|
_ = tg.create_task_context(looper1)
|
444
443
|
_ = tg.create_task_context(looper2)
|
445
444
|
errors = exc_info.value.exceptions
|
@@ -450,8 +449,8 @@ class TestLooper:
|
|
450
449
|
self._assert_stats_half(looper2._counter)
|
451
450
|
|
452
451
|
def test_replace(self) -> None:
|
453
|
-
looper = CountingLooper().replace(freq=10
|
454
|
-
assert looper.freq == 10
|
452
|
+
looper = CountingLooper().replace(freq=10 * SECOND)
|
453
|
+
assert looper.freq == 10 * SECOND
|
455
454
|
|
456
455
|
async def test_request_back_off(self) -> None:
|
457
456
|
class Example(CountingLooper):
|
@@ -463,7 +462,7 @@ class TestLooper:
|
|
463
462
|
):
|
464
463
|
self.request_back_off()
|
465
464
|
|
466
|
-
looper = Example(auto_start=True, timeout=
|
465
|
+
looper = Example(auto_start=True, timeout=SECOND)
|
467
466
|
async with looper:
|
468
467
|
...
|
469
468
|
assert_looper_stats(
|
@@ -497,7 +496,7 @@ class TestLooper:
|
|
497
496
|
):
|
498
497
|
self.request_restart()
|
499
498
|
|
500
|
-
looper = Example(auto_start=True, timeout=
|
499
|
+
looper = Example(auto_start=True, timeout=SECOND)
|
501
500
|
async with looper:
|
502
501
|
...
|
503
502
|
assert_looper_stats(
|
@@ -531,7 +530,7 @@ class TestLooper:
|
|
531
530
|
):
|
532
531
|
self.request_stop()
|
533
532
|
|
534
|
-
looper = Example(auto_start=True, timeout=
|
533
|
+
looper = Example(auto_start=True, timeout=SECOND)
|
535
534
|
async with looper:
|
536
535
|
...
|
537
536
|
assert_looper_stats(
|
@@ -565,7 +564,7 @@ class TestLooper:
|
|
565
564
|
_ = self.get_right_nowait()
|
566
565
|
self.request_stop_when_empty()
|
567
566
|
|
568
|
-
looper = Example(auto_start=True, timeout=
|
567
|
+
looper = Example(auto_start=True, timeout=SECOND)
|
569
568
|
for i in range(25):
|
570
569
|
match i % 2 == 0:
|
571
570
|
case True:
|
@@ -610,7 +609,7 @@ class TestLooper:
|
|
610
609
|
looper = Example()
|
611
610
|
with Timer() as timer:
|
612
611
|
await looper.restart()
|
613
|
-
assert timer
|
612
|
+
assert timer >= self._restart_min_elapsed
|
614
613
|
pattern = rf": encountered {get_class_name(CountingLooperError)}\(\) whilst restarting \(initialize\); sleeping for .*\.\.\.$"
|
615
614
|
_ = one(m for m in caplog.messages if search(pattern, m))
|
616
615
|
|
@@ -627,7 +626,7 @@ class TestLooper:
|
|
627
626
|
looper = Example()
|
628
627
|
with Timer() as timer:
|
629
628
|
await looper.restart()
|
630
|
-
assert timer
|
629
|
+
assert timer >= self._restart_min_elapsed
|
631
630
|
pattern = rf": encountered {get_class_name(CountingLooperError)}\(\) whilst restarting \(tear down\); sleeping for .*\.\.\.$"
|
632
631
|
_ = one(m for m in caplog.messages if search(pattern, m))
|
633
632
|
|
@@ -650,7 +649,7 @@ class TestLooper:
|
|
650
649
|
looper = Example()
|
651
650
|
with Timer() as timer:
|
652
651
|
await looper.restart()
|
653
|
-
assert timer
|
652
|
+
assert timer >= self._restart_min_elapsed
|
654
653
|
pattern = rf": encountered {get_class_name(CountingLooperError)}\(\) \(tear down\) and then {get_class_name(CountingLooperError)}\(\) \(initialization\) whilst restarting; sleeping for .*\.\.\.$"
|
655
654
|
_ = one(m for m in caplog.messages if search(pattern, m))
|
656
655
|
|
@@ -658,26 +657,26 @@ class TestLooper:
|
|
658
657
|
looper = CountingLooper()
|
659
658
|
with Timer() as timer:
|
660
659
|
await looper.restart()
|
661
|
-
assert timer
|
660
|
+
assert timer <= self._restart_max_elapsed
|
662
661
|
pattern = r": finished restarting$"
|
663
662
|
_ = one(m for m in caplog.messages if search(pattern, m))
|
664
663
|
|
665
664
|
@mark.parametrize("n", [param(0), param(1), param(2)])
|
666
665
|
async def test_run_until_empty(self, *, n: int) -> None:
|
667
|
-
looper = QueueLooper(freq=0.05)
|
666
|
+
looper = QueueLooper(freq=0.05 * SECOND)
|
668
667
|
looper.put_right_nowait(*range(n))
|
669
|
-
async with
|
668
|
+
async with timeout_td(SECOND), looper:
|
670
669
|
await looper.run_until_empty()
|
671
670
|
assert looper.empty()
|
672
671
|
|
673
672
|
@mark.parametrize("inner_auto_start", [param(True), param(False)])
|
674
673
|
async def test_sub_looper_one(self, *, inner_auto_start: bool) -> None:
|
675
674
|
looper = OuterCountingLooper(
|
676
|
-
auto_start=True, timeout=
|
675
|
+
auto_start=True, timeout=SECOND, inner_auto_start=inner_auto_start
|
677
676
|
)
|
678
677
|
if inner_auto_start:
|
679
678
|
with raises(TimeoutError):
|
680
|
-
async with
|
679
|
+
async with timeout_td(SECOND), looper:
|
681
680
|
...
|
682
681
|
self._assert_stats_full(looper)
|
683
682
|
self._assert_stats_half(looper.inner)
|
@@ -694,21 +693,21 @@ class TestLooper:
|
|
694
693
|
) -> None:
|
695
694
|
looper = MultipleSubLoopers(
|
696
695
|
auto_start=True,
|
697
|
-
timeout=
|
696
|
+
timeout=SECOND,
|
698
697
|
inner1_auto_start=inner1_auto_start,
|
699
698
|
inner2_auto_start=inner2_auto_start,
|
700
699
|
)
|
701
700
|
match inner1_auto_start, inner2_auto_start:
|
702
701
|
case True, _:
|
703
702
|
with raises(TimeoutError):
|
704
|
-
async with
|
703
|
+
async with timeout_td(SECOND), looper:
|
705
704
|
...
|
706
705
|
self._assert_stats_full(looper)
|
707
706
|
self._assert_stats_half(looper.inner1)
|
708
707
|
self._assert_stats_no_runs(looper.inner2)
|
709
708
|
case False, True:
|
710
709
|
with raises(TimeoutError):
|
711
|
-
async with
|
710
|
+
async with timeout_td(SECOND), looper:
|
712
711
|
...
|
713
712
|
self._assert_stats_full(looper)
|
714
713
|
self._assert_stats_half(looper.inner1)
|
@@ -727,7 +726,7 @@ class TestLooper:
|
|
727
726
|
) -> None:
|
728
727
|
looper = Outer2CountingLooper(
|
729
728
|
auto_start=True,
|
730
|
-
timeout=
|
729
|
+
timeout=SECOND,
|
731
730
|
middle_auto_start=middle_auto_start,
|
732
731
|
inner_auto_start=inner_auto_start,
|
733
732
|
)
|
@@ -740,7 +739,7 @@ class TestLooper:
|
|
740
739
|
self._assert_stats_quarter(looper.middle.inner, stops=1)
|
741
740
|
case _, _:
|
742
741
|
with raises(TimeoutError):
|
743
|
-
async with
|
742
|
+
async with timeout_td(SECOND), looper:
|
744
743
|
...
|
745
744
|
self._assert_stats_full(looper)
|
746
745
|
self._assert_stats_half(looper.middle)
|
@@ -777,7 +776,7 @@ class TestLooper:
|
|
777
776
|
_ = one(m for m in caplog.messages if search(pattern, m))
|
778
777
|
|
779
778
|
async def test_timeout(self) -> None:
|
780
|
-
looper = CountingLooper(timeout=
|
779
|
+
looper = CountingLooper(timeout=SECOND)
|
781
780
|
with Timer() as timer:
|
782
781
|
async with looper:
|
783
782
|
await looper
|
@@ -905,55 +904,53 @@ class TestUniqueQueue:
|
|
905
904
|
assert queue._set == set()
|
906
905
|
|
907
906
|
|
908
|
-
class
|
909
|
-
|
910
|
-
|
911
|
-
async def test_main(self
|
907
|
+
class TestSleepMaxDur:
|
908
|
+
delta: ClassVar[TimeDelta] = 0.05 * SECOND
|
909
|
+
|
910
|
+
async def test_main(self) -> None:
|
912
911
|
with Timer() as timer:
|
913
|
-
await
|
914
|
-
assert timer
|
915
|
-
2 * duration
|
916
|
-
)
|
912
|
+
await sleep_max(self.delta)
|
913
|
+
assert timer <= 2 * self.delta
|
917
914
|
|
918
915
|
async def test_none(self) -> None:
|
919
916
|
with Timer() as timer:
|
920
|
-
await
|
921
|
-
assert timer
|
917
|
+
await sleep_max()
|
918
|
+
assert timer <= self.delta
|
922
919
|
|
923
920
|
|
924
|
-
class
|
925
|
-
|
926
|
-
|
927
|
-
async def test_main(self
|
921
|
+
class TestSleepTD:
|
922
|
+
delta: ClassVar[TimeDelta] = 0.05 * SECOND
|
923
|
+
|
924
|
+
async def test_main(self) -> None:
|
928
925
|
with Timer() as timer:
|
929
|
-
await
|
930
|
-
assert timer
|
931
|
-
2 * duration
|
932
|
-
)
|
926
|
+
await sleep_td(self.delta)
|
927
|
+
assert timer <= 2 * self.delta
|
933
928
|
|
934
929
|
async def test_none(self) -> None:
|
935
930
|
with Timer() as timer:
|
936
|
-
await
|
937
|
-
assert timer
|
931
|
+
await sleep_td()
|
932
|
+
assert timer <= self.delta
|
938
933
|
|
939
934
|
|
940
935
|
class TestSleepUntil:
|
941
936
|
async def test_main(self) -> None:
|
942
|
-
await sleep_until(get_now() +
|
937
|
+
await sleep_until(get_now() + 0.05 * SECOND)
|
943
938
|
|
944
939
|
|
945
940
|
class TestSleepUntilRounded:
|
946
941
|
async def test_main(self) -> None:
|
947
|
-
await
|
942
|
+
await sleep_rounded(unit="millisecond", increment=10)
|
948
943
|
|
949
944
|
|
950
945
|
class TestStreamCommand:
|
946
|
+
delta: ClassVar[TimeDelta] = 0.05 * SECOND
|
947
|
+
|
951
948
|
@skipif_windows
|
952
949
|
async def test_main(self) -> None:
|
953
950
|
output = await stream_command(
|
954
951
|
'echo "stdout message" && sleep 0.1 && echo "stderr message" >&2'
|
955
952
|
)
|
956
|
-
await
|
953
|
+
await sleep_td(self.delta)
|
957
954
|
assert output.return_code == 0
|
958
955
|
assert output.stdout == "stdout message\n"
|
959
956
|
assert output.stderr == "stderr message\n"
|
@@ -961,7 +958,7 @@ class TestStreamCommand:
|
|
961
958
|
@skipif_windows
|
962
959
|
async def test_error(self) -> None:
|
963
960
|
output = await stream_command("this-is-an-error")
|
964
|
-
await
|
961
|
+
await sleep_td(self.delta)
|
965
962
|
assert output.return_code == 127
|
966
963
|
assert output.stdout == ""
|
967
964
|
assert search(
|
@@ -969,22 +966,24 @@ class TestStreamCommand:
|
|
969
966
|
)
|
970
967
|
|
971
968
|
|
972
|
-
class
|
969
|
+
class TestTimeoutTD:
|
970
|
+
delta: ClassVar[TimeDelta] = 0.05 * SECOND
|
971
|
+
|
973
972
|
async def test_pass(self) -> None:
|
974
|
-
async with
|
975
|
-
await
|
973
|
+
async with timeout_td(2 * self.delta):
|
974
|
+
await sleep_td(self.delta)
|
976
975
|
|
977
976
|
async def test_fail(self) -> None:
|
978
977
|
with raises(TimeoutError):
|
979
|
-
async with
|
980
|
-
await
|
978
|
+
async with timeout_td(self.delta):
|
979
|
+
await sleep_td(2 * self.delta)
|
981
980
|
|
982
981
|
async def test_custom_error(self) -> None:
|
983
982
|
class CustomError(Exception): ...
|
984
983
|
|
985
984
|
with raises(CustomError):
|
986
|
-
async with
|
987
|
-
await
|
985
|
+
async with timeout_td(self.delta, error=CustomError):
|
986
|
+
await sleep_td(2 * self.delta)
|
988
987
|
|
989
988
|
|
990
989
|
if __name__ == "__main__":
|
{dycw_utilities-0.131.16 → dycw_utilities-0.131.17}/src/tests/test_asyncio_classes/loopers.py
RENAMED
@@ -8,15 +8,16 @@ from pytest import approx
|
|
8
8
|
from tests.conftest import IS_CI
|
9
9
|
from utilities.asyncio import Looper
|
10
10
|
from utilities.contextlib import suppress_super_object_attribute_error
|
11
|
-
from utilities.
|
11
|
+
from utilities.whenever2 import SECOND
|
12
12
|
|
13
13
|
if TYPE_CHECKING:
|
14
14
|
from collections.abc import Iterator
|
15
15
|
|
16
|
-
from
|
16
|
+
from whenever import TimeDelta
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
|
19
|
+
_FREQ: TimeDelta = 0.01 * SECOND
|
20
|
+
_BACKOFF: TimeDelta = 0.1 * SECOND
|
20
21
|
_REL: float = 2.0 if IS_CI else 0.25
|
21
22
|
|
22
23
|
|
@@ -102,8 +103,8 @@ def assert_looper_full(
|
|
102
103
|
|
103
104
|
@dataclass(kw_only=True)
|
104
105
|
class CountingLooper(Looper[Any]):
|
105
|
-
freq:
|
106
|
-
backoff:
|
106
|
+
freq: TimeDelta = field(default=_FREQ, repr=False)
|
107
|
+
backoff: TimeDelta = field(default=_BACKOFF, repr=False)
|
107
108
|
_debug: bool = field(default=True, repr=False)
|
108
109
|
count: int = 0
|
109
110
|
max_count: int = 10
|
@@ -212,8 +213,8 @@ class Outer2CountingLooper(CountingLooper):
|
|
212
213
|
|
213
214
|
@dataclass(kw_only=True)
|
214
215
|
class CounterMixin:
|
215
|
-
freq:
|
216
|
-
backoff:
|
216
|
+
freq: TimeDelta = field(default=_FREQ, repr=False)
|
217
|
+
backoff: TimeDelta = field(default=_BACKOFF, repr=False)
|
217
218
|
_debug: bool = field(default=True, repr=False)
|
218
219
|
count: int = 0
|
219
220
|
max_count: int = 10
|
@@ -245,8 +246,8 @@ class LooperWithCounterMixin(CounterMixin, Looper): ...
|
|
245
246
|
|
246
247
|
@dataclass(kw_only=True)
|
247
248
|
class CounterMixin1:
|
248
|
-
freq:
|
249
|
-
backoff:
|
249
|
+
freq: TimeDelta = field(default=_FREQ, repr=False)
|
250
|
+
backoff: TimeDelta = field(default=_BACKOFF, repr=False)
|
250
251
|
_debug: bool = field(default=True, repr=False)
|
251
252
|
count: int = 0
|
252
253
|
max_count: int = 10
|
@@ -271,8 +272,8 @@ class CounterMixin1:
|
|
271
272
|
|
272
273
|
@dataclass(kw_only=True)
|
273
274
|
class CounterMixin2:
|
274
|
-
freq:
|
275
|
-
backoff:
|
275
|
+
freq: TimeDelta = field(default=_FREQ, repr=False)
|
276
|
+
backoff: TimeDelta = field(default=_BACKOFF, repr=False)
|
276
277
|
_debug: bool = field(default=True, repr=False)
|
277
278
|
count: int = 0
|
278
279
|
max_count: int = 10
|
@@ -9,20 +9,20 @@ from utilities.redis import PublishServiceMixin, SubscribeServiceMixin
|
|
9
9
|
from utilities.text import unique_str
|
10
10
|
|
11
11
|
if TYPE_CHECKING:
|
12
|
-
from
|
12
|
+
from whenever import TimeDelta
|
13
13
|
|
14
14
|
|
15
15
|
@dataclass(kw_only=True)
|
16
16
|
class LooperWithPublishAndSubscribeMixins(
|
17
17
|
PublishServiceMixin[Any], SubscribeServiceMixin[Any], Looper[Any]
|
18
18
|
):
|
19
|
-
freq:
|
20
|
-
backoff:
|
19
|
+
freq: TimeDelta = field(default=_FREQ, repr=False)
|
20
|
+
backoff: TimeDelta = field(default=_BACKOFF, repr=False)
|
21
21
|
_debug: bool = field(default=True, repr=False)
|
22
|
-
publish_service_freq:
|
23
|
-
publish_service_backoff:
|
22
|
+
publish_service_freq: TimeDelta = field(default=_FREQ, repr=False)
|
23
|
+
publish_service_backoff: TimeDelta = field(default=_BACKOFF, repr=False)
|
24
24
|
publish_service_debug: bool = field(default=True, repr=False)
|
25
|
-
subscribe_service_freq:
|
26
|
-
subscribe_service_backoff:
|
25
|
+
subscribe_service_freq: TimeDelta = field(default=_FREQ, repr=False)
|
26
|
+
subscribe_service_backoff: TimeDelta = field(default=_BACKOFF, repr=False)
|
27
27
|
subscribe_service_debug: bool = field(default=True, repr=False)
|
28
28
|
subscribe_service_channel: str = field(default_factory=unique_str)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
from utilities.asyncio import
|
3
|
+
from utilities.asyncio import sleep_td
|
4
4
|
from utilities.atools import call_memoized
|
5
5
|
from utilities.whenever2 import SECOND
|
6
6
|
|
@@ -20,7 +20,7 @@ class TestCallMemoized:
|
|
20
20
|
|
21
21
|
async def test_refresh(self) -> None:
|
22
22
|
counter = 0
|
23
|
-
delta = 0.
|
23
|
+
delta = 0.1 * SECOND
|
24
24
|
|
25
25
|
async def increment() -> int:
|
26
26
|
nonlocal counter
|
@@ -30,7 +30,7 @@ class TestCallMemoized:
|
|
30
30
|
for _ in range(2):
|
31
31
|
assert (await call_memoized(increment, delta)) == 1
|
32
32
|
assert counter == 1
|
33
|
-
await
|
33
|
+
await sleep_td(2 * delta)
|
34
34
|
for _ in range(2):
|
35
35
|
assert (await call_memoized(increment, delta)) == 2
|
36
36
|
assert counter == 2
|