dycw-utilities 0.125.11__tar.gz → 0.125.12__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.125.11 → dycw_utilities-0.125.12}/PKG-INFO +5 -5
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/pyproject.toml +10 -10
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_asyncio.py +422 -2
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/__init__.py +1 -1
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/asyncio.py +453 -9
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/.gitignore +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/LICENSE +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/README.md +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/__init__.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/conftest.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/modules/__init__.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/modules/package_missing/__init__.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/modules/package_missing/module.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/modules/package_with/__init__.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/modules/package_with/outer_1.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/modules/package_with/outer_2.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/modules/package_without/__init__.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/modules/package_without/module_1.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/modules/package_without/module_2.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/modules/standalone.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/modules/with_imports.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_altair.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_atomicwrites.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_atools.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_cachetools.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_click.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_concurrent.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_contextlib.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_contextvars.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_cryptography.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_cvxpy.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_dataclasses.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_datetime.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_enum.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_errors.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_eventkit.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_fastapi.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_fpdf2.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_functions.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_functools.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_getpass.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_git.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_hashlib.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_http.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_hypothesis.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_importlib.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_ipython.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_iterables.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_jupyter.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_libcst.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_lightweight_charts.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_logging.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_loguru.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_luigi.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_math.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_memory_profiler.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_modules.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_more_itertools.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_numpy.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_operator.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_optuna.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_orjson.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_os.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_parse.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_pathlib.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_period.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_pickle.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_platform.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_polars.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_polars_ols.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_pqdm.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_pydantic.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_pyinstrument.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_pyrsistent.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_pytest.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_pytest_regressions.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_python_dotenv.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_random.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_re.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_redis.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_reprlib.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_rich.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_scipy.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_sentinel.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_shelve.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_slack_sdk.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_socket.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_sqlalchemy.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_statsmodel.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_streamlit.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_sys.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_tempfile.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_tenacity.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_text.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_threading.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_timer.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_traceback.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_traceback_funcs/__init__.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_traceback_funcs/chain.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_traceback_funcs/error_bind.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_traceback_funcs/many.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_traceback_funcs/one.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_traceback_funcs/recursive.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_traceback_funcs/two.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_traceback_funcs/untraced.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_types.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_typing.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_typing_funcs/__init__.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_typing_funcs/no_future.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_typing_funcs/with_future.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_tzdata.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_tzlocal.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_uuid.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_version.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_warnings.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_whenever.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_zipfile.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/tests/test_zoneinfo.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/altair.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/atomicwrites.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/atools.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/cachetools.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/click.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/concurrent.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/contextlib.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/contextvars.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/cryptography.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/cvxpy.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/dataclasses.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/datetime.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/enum.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/errors.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/eventkit.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/fastapi.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/fpdf2.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/functions.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/functools.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/getpass.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/git.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/hashlib.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/http.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/hypothesis.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/importlib.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/ipython.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/iterables.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/jupyter.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/libcst.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/lightweight_charts.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/logging.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/loguru.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/luigi.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/math.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/memory_profiler.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/modules.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/more_itertools.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/numpy.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/operator.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/optuna.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/orjson.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/os.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/parse.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/pathlib.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/period.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/pickle.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/platform.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/polars.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/polars_ols.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/pqdm.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/py.typed +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/pydantic.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/pyinstrument.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/pyrsistent.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/pytest.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/pytest_regressions.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/python_dotenv.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/random.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/re.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/redis.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/reprlib.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/rich.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/scipy.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/sentinel.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/shelve.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/slack_sdk.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/socket.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/sqlalchemy.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/statsmodels.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/streamlit.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/sys.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/tempfile.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/tenacity.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/text.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/threading.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/timer.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/traceback.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/types.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/typing.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/tzdata.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/tzlocal.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/uuid.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/version.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/warnings.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/whenever.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/zipfile.py +0 -0
- {dycw_utilities-0.125.11 → dycw_utilities-0.125.12}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: dycw-utilities
|
3
|
-
Version: 0.125.
|
3
|
+
Version: 0.125.12
|
4
4
|
Author-email: Derek Wan <d.wan@icloud.com>
|
5
5
|
License-File: LICENSE
|
6
6
|
Requires-Python: >=3.12
|
@@ -25,7 +25,7 @@ Requires-Dist: altair<5.6,>=5.5.0; extra == 'zzz-test-altair'
|
|
25
25
|
Requires-Dist: atomicwrites<1.5,>=1.4.1; extra == 'zzz-test-altair'
|
26
26
|
Requires-Dist: img2pdf<0.7,>=0.6.0; extra == 'zzz-test-altair'
|
27
27
|
Requires-Dist: polars-lts-cpu<1.31,>=1.30.0; extra == 'zzz-test-altair'
|
28
|
-
Requires-Dist: vl-convert-python<1.
|
28
|
+
Requires-Dist: vl-convert-python<1.9,>=1.8.0; extra == 'zzz-test-altair'
|
29
29
|
Requires-Dist: whenever<0.9,>=0.8.4; extra == 'zzz-test-altair'
|
30
30
|
Provides-Extra: zzz-test-asyncio
|
31
31
|
Provides-Extra: zzz-test-atomicwrites
|
@@ -82,7 +82,7 @@ Requires-Dist: hypothesis<6.132,>=6.131.30; extra == 'zzz-test-hypothesis'
|
|
82
82
|
Requires-Dist: luigi<3.7,>=3.6.0; extra == 'zzz-test-hypothesis'
|
83
83
|
Requires-Dist: numpy<2.3,>=2.2.6; extra == 'zzz-test-hypothesis'
|
84
84
|
Requires-Dist: pathvalidate<3.3,>=3.2.3; extra == 'zzz-test-hypothesis'
|
85
|
-
Requires-Dist: redis<6.
|
85
|
+
Requires-Dist: redis<6.3,>=6.2.0; extra == 'zzz-test-hypothesis'
|
86
86
|
Requires-Dist: sqlalchemy<2.1,>=2.0.41; extra == 'zzz-test-hypothesis'
|
87
87
|
Requires-Dist: tenacity<9.0,>=8.5.0; extra == 'zzz-test-hypothesis'
|
88
88
|
Requires-Dist: tzlocal<5.4,>=5.3.1; extra == 'zzz-test-hypothesis'
|
@@ -162,7 +162,7 @@ Provides-Extra: zzz-test-re
|
|
162
162
|
Provides-Extra: zzz-test-redis
|
163
163
|
Requires-Dist: orjson<3.11,>=3.10.15; extra == 'zzz-test-redis'
|
164
164
|
Requires-Dist: polars-lts-cpu<1.31,>=1.30.0; extra == 'zzz-test-redis'
|
165
|
-
Requires-Dist: redis<6.
|
165
|
+
Requires-Dist: redis<6.3,>=6.2.0; extra == 'zzz-test-redis'
|
166
166
|
Requires-Dist: rich<14.1,>=14.0.0; extra == 'zzz-test-redis'
|
167
167
|
Requires-Dist: tenacity<9.0,>=8.5.0; extra == 'zzz-test-redis'
|
168
168
|
Requires-Dist: tzlocal<5.4,>=5.3.1; extra == 'zzz-test-redis'
|
@@ -174,7 +174,7 @@ Requires-Dist: scipy<1.16,>=1.15.3; extra == 'zzz-test-scipy'
|
|
174
174
|
Provides-Extra: zzz-test-sentinel
|
175
175
|
Provides-Extra: zzz-test-shelve
|
176
176
|
Provides-Extra: zzz-test-slack-sdk
|
177
|
-
Requires-Dist: aiohttp<3.12.
|
177
|
+
Requires-Dist: aiohttp<3.12.5,>=3.12.4; extra == 'zzz-test-slack-sdk'
|
178
178
|
Requires-Dist: slack-sdk<3.36,>=3.35.0; extra == 'zzz-test-slack-sdk'
|
179
179
|
Provides-Extra: zzz-test-socket
|
180
180
|
Provides-Extra: zzz-test-sqlalchemy
|
@@ -8,7 +8,7 @@ requires = ["hatchling"]
|
|
8
8
|
# dependency groups
|
9
9
|
[dependency-groups]
|
10
10
|
dev = [
|
11
|
-
"aiohttp >= 3.12.
|
11
|
+
"aiohttp >= 3.12.4, < 3.12.5", # for slack
|
12
12
|
"aiosqlite >= 0.21.0, < 0.22",
|
13
13
|
"altair >= 5.5.0, < 5.6",
|
14
14
|
"asyncpg >= 0.30.0, < 0.31", # for sqlalchemy async
|
@@ -35,7 +35,7 @@ dev = [
|
|
35
35
|
"nest-asyncio >= 1.6.0, < 1.7", # for sqlalchemy async
|
36
36
|
"nox >= 2025.2.9, < 2025.3",
|
37
37
|
"numpy >= 2.2.6, < 2.3",
|
38
|
-
"libcst >= 1.
|
38
|
+
"libcst >= 1.8.0, < 1.9",
|
39
39
|
"optuna >= 4.3.0, < 4.4",
|
40
40
|
"orjson >= 3.10.18, < 3.11",
|
41
41
|
"pathvalidate >= 3.2.3, < 3.3",
|
@@ -50,7 +50,7 @@ dev = [
|
|
50
50
|
"pytest >= 8.3.5, < 8.4",
|
51
51
|
"pytest-regressions >= 2.7.0, < 2.8",
|
52
52
|
"python-dotenv >= 1.1.0, < 1.2",
|
53
|
-
"redis >= 6.
|
53
|
+
"redis >= 6.2.0, < 6.3",
|
54
54
|
"rich >= 14.0.0, < 14.1",
|
55
55
|
"scikit-learn >= 1.6.1, < 1.7",
|
56
56
|
"scipy >= 1.15.3, < 1.16",
|
@@ -65,7 +65,7 @@ dev = [
|
|
65
65
|
"uvicorn >= 0.34.1, < 0.35",
|
66
66
|
"vegafusion >= 2.0.2, < 2.1",
|
67
67
|
"vegafusion-python-embed >= 1.6.9, < 1.7",
|
68
|
-
"vl-convert-python >= 1.
|
68
|
+
"vl-convert-python >= 1.8.0, < 1.9",
|
69
69
|
"whenever >= 0.8.4, < 0.9",
|
70
70
|
# test
|
71
71
|
"coverage-conditional-plugin >= 0.9.0, < 0.10",
|
@@ -93,7 +93,7 @@ dependencies = [
|
|
93
93
|
name = "dycw-utilities"
|
94
94
|
readme = "README.md"
|
95
95
|
requires-python = ">= 3.12"
|
96
|
-
version = "0.125.
|
96
|
+
version = "0.125.12"
|
97
97
|
|
98
98
|
[project.optional-dependencies]
|
99
99
|
test = [
|
@@ -117,7 +117,7 @@ zzz-test-altair = [
|
|
117
117
|
"atomicwrites >= 1.4.1, < 1.5",
|
118
118
|
"img2pdf >= 0.6.0, < 0.7",
|
119
119
|
"polars-lts-cpu >= 1.30.0, < 1.31",
|
120
|
-
"vl-convert-python >= 1.
|
120
|
+
"vl-convert-python >= 1.8.0, < 1.9",
|
121
121
|
"whenever >= 0.8.4, < 0.9",
|
122
122
|
]
|
123
123
|
zzz-test-asyncio = []
|
@@ -178,7 +178,7 @@ zzz-test-hypothesis = [
|
|
178
178
|
"luigi >= 3.6.0, < 3.7",
|
179
179
|
"numpy >= 2.2.6, < 2.3",
|
180
180
|
"pathvalidate >= 3.2.3, < 3.3",
|
181
|
-
"redis >= 6.
|
181
|
+
"redis >= 6.2.0, < 6.3",
|
182
182
|
"sqlalchemy >= 2.0.41, < 2.1",
|
183
183
|
"tenacity >= 8.5.0, < 9.0", # limited by luigi
|
184
184
|
"tzlocal >= 5.3.1, < 5.4",
|
@@ -259,7 +259,7 @@ zzz-test-re = []
|
|
259
259
|
zzz-test-redis = [
|
260
260
|
"orjson >= 3.10.15, < 3.11",
|
261
261
|
"polars-lts-cpu >= 1.30.0, < 1.31",
|
262
|
-
"redis >= 6.
|
262
|
+
"redis >= 6.2.0, < 6.3",
|
263
263
|
"rich >= 14.0.0, < 14.1",
|
264
264
|
"tenacity >= 8.5.0, < 9.0", # limited by luigi
|
265
265
|
"tzlocal >= 5.3.1, < 5.4",
|
@@ -270,7 +270,7 @@ zzz-test-scipy = ["scipy >= 1.15.3, < 1.16"]
|
|
270
270
|
zzz-test-sentinel = []
|
271
271
|
zzz-test-shelve = []
|
272
272
|
zzz-test-slack-sdk = [
|
273
|
-
"aiohttp >= 3.12.
|
273
|
+
"aiohttp >= 3.12.4, < 3.12.5", # for slack
|
274
274
|
"slack-sdk >= 3.35.0, < 3.36",
|
275
275
|
]
|
276
276
|
zzz-test-socket = []
|
@@ -334,7 +334,7 @@ zzz-test-zoneinfo = [
|
|
334
334
|
# bump-my-version
|
335
335
|
[tool.bumpversion]
|
336
336
|
allow_dirty = true
|
337
|
-
current_version = "0.125.
|
337
|
+
current_version = "0.125.12"
|
338
338
|
|
339
339
|
[[tool.bumpversion.files]]
|
340
340
|
filename = "src/utilities/__init__.py"
|
@@ -21,17 +21,21 @@ from hypothesis.strategies import (
|
|
21
21
|
permutations,
|
22
22
|
sampled_from,
|
23
23
|
)
|
24
|
-
from pytest import LogCaptureFixture, mark, param, raises
|
24
|
+
from pytest import LogCaptureFixture, approx, mark, param, raises
|
25
25
|
|
26
26
|
from utilities.asyncio import (
|
27
27
|
EnhancedQueue,
|
28
28
|
EnhancedTaskGroup,
|
29
29
|
InfiniteLooper,
|
30
30
|
InfiniteQueueLooper,
|
31
|
+
Looper,
|
32
|
+
LooperTimeoutError,
|
31
33
|
UniquePriorityQueue,
|
32
34
|
UniqueQueue,
|
33
35
|
_InfiniteLooperDefaultEventError,
|
34
36
|
_InfiniteLooperNoSuchEventError,
|
37
|
+
_LooperNoTaskError,
|
38
|
+
_LooperStats,
|
35
39
|
get_event,
|
36
40
|
get_items,
|
37
41
|
get_items_nowait,
|
@@ -47,6 +51,7 @@ from utilities.dataclasses import replace_non_sentinel
|
|
47
51
|
from utilities.datetime import (
|
48
52
|
MILLISECOND,
|
49
53
|
MINUTE,
|
54
|
+
SECOND,
|
50
55
|
datetime_duration_to_timedelta,
|
51
56
|
get_now,
|
52
57
|
)
|
@@ -817,7 +822,7 @@ class TestInfiniteQueueLooper:
|
|
817
822
|
assert len(looper) == 0
|
818
823
|
assert looper.empty()
|
819
824
|
looper.put_right_nowait(*range(n))
|
820
|
-
assert len(looper) == n
|
825
|
+
assert len(looper) == looper.qsize() == n
|
821
826
|
assert not looper.empty()
|
822
827
|
|
823
828
|
async def test_run_until_empty_no_stop(self) -> None:
|
@@ -872,6 +877,421 @@ class TestInfiniteQueueLooper:
|
|
872
877
|
assert message == expected
|
873
878
|
|
874
879
|
|
880
|
+
class _ExampleLooperError(Exception): ...
|
881
|
+
|
882
|
+
|
883
|
+
@dataclass(kw_only=True)
|
884
|
+
class _ExampleLooper(Looper[Any]):
|
885
|
+
freq: Duration = field(default=10 * MILLISECOND, repr=False)
|
886
|
+
backoff: Duration = field(default=100 * MILLISECOND, repr=False)
|
887
|
+
_debug: bool = field(default=True, repr=False)
|
888
|
+
count: int = 0
|
889
|
+
max_count: int = 10
|
890
|
+
|
891
|
+
@override
|
892
|
+
async def _initialize_core(self) -> None:
|
893
|
+
self.count = 0
|
894
|
+
|
895
|
+
@override
|
896
|
+
async def core(self) -> None:
|
897
|
+
self.count += 1
|
898
|
+
if self.count >= self.max_count:
|
899
|
+
raise _ExampleLooperError
|
900
|
+
|
901
|
+
|
902
|
+
@dataclass(kw_only=True)
|
903
|
+
class _ExampleOuterLooper(_ExampleLooper):
|
904
|
+
inner: _ExampleLooper = field(init=False, repr=False)
|
905
|
+
|
906
|
+
@override
|
907
|
+
def __post_init__(self) -> None:
|
908
|
+
super().__post_init__()
|
909
|
+
self.inner = _ExampleLooper(
|
910
|
+
freq=self.freq / 2,
|
911
|
+
backoff=self.backoff / 2,
|
912
|
+
logger=self.logger,
|
913
|
+
timeout=self.timeout,
|
914
|
+
timeout_error=self.timeout_error,
|
915
|
+
max_count=round(self.max_count / 2),
|
916
|
+
)
|
917
|
+
|
918
|
+
@override
|
919
|
+
def _yield_sub_loopers(self) -> Iterator[Looper]:
|
920
|
+
yield self.inner
|
921
|
+
|
922
|
+
|
923
|
+
class TestLooper:
|
924
|
+
async def test_main_with_nothing(self) -> None:
|
925
|
+
looper = _ExampleLooper()
|
926
|
+
async with looper:
|
927
|
+
...
|
928
|
+
assert looper.stats == _LooperStats(entries=1, stops=1)
|
929
|
+
|
930
|
+
@mark.flaky
|
931
|
+
async def test_main_with_explicit_start(self) -> None:
|
932
|
+
looper = _ExampleLooper()
|
933
|
+
with raises(TimeoutError):
|
934
|
+
async with timeout(1.0), looper:
|
935
|
+
await looper
|
936
|
+
self._assert_stats(looper, stops=1)
|
937
|
+
|
938
|
+
async def test_main_with_auto_start(self) -> None:
|
939
|
+
looper = _ExampleLooper(auto_start=True)
|
940
|
+
with raises(TimeoutError):
|
941
|
+
async with timeout(1.0), looper:
|
942
|
+
...
|
943
|
+
self._assert_stats(looper)
|
944
|
+
|
945
|
+
@mark.flaky
|
946
|
+
async def test_main_with_timeout(self) -> None:
|
947
|
+
looper = _ExampleLooper(timeout=SECOND)
|
948
|
+
async with looper:
|
949
|
+
with raises(LooperTimeoutError, match="Timeout"):
|
950
|
+
await looper
|
951
|
+
self._assert_stats(looper, stops=1)
|
952
|
+
|
953
|
+
async def test_main_with_auto_start_and_timeout(self) -> None:
|
954
|
+
looper = _ExampleLooper(auto_start=True, timeout=SECOND)
|
955
|
+
async with looper:
|
956
|
+
...
|
957
|
+
self._assert_stats(looper, stops=1)
|
958
|
+
|
959
|
+
async def test_await_without_task(self) -> None:
|
960
|
+
looper = _ExampleLooper()
|
961
|
+
with raises(_LooperNoTaskError, match=".* has no running task"):
|
962
|
+
await looper
|
963
|
+
|
964
|
+
async def test_context_manager_already_entered(
|
965
|
+
self, *, caplog: LogCaptureFixture
|
966
|
+
) -> None:
|
967
|
+
looper = _ExampleLooper(auto_start=True, timeout=SECOND)
|
968
|
+
async with looper, looper:
|
969
|
+
...
|
970
|
+
_ = one(m for m in caplog.messages if search(": already entered$", m))
|
971
|
+
|
972
|
+
def test_empty(self) -> None:
|
973
|
+
looper = _ExampleLooper()
|
974
|
+
assert looper.empty()
|
975
|
+
looper.put_left_nowait(None)
|
976
|
+
assert not looper.empty()
|
977
|
+
|
978
|
+
async def test_initialize_already_initializing(
|
979
|
+
self, *, caplog: LogCaptureFixture
|
980
|
+
) -> None:
|
981
|
+
class Example(_ExampleLooper):
|
982
|
+
@override
|
983
|
+
async def _initialize_core(self) -> None:
|
984
|
+
if self._initialization_attempts == 1:
|
985
|
+
_ = await super().initialize()
|
986
|
+
await super()._initialize_core()
|
987
|
+
|
988
|
+
looper = Example()
|
989
|
+
_ = await looper.initialize()
|
990
|
+
_ = one(m for m in caplog.messages if search(": already initializing$", m))
|
991
|
+
|
992
|
+
async def test_initialize_failure(self, *, caplog: LogCaptureFixture) -> None:
|
993
|
+
class Example(_ExampleLooper):
|
994
|
+
@override
|
995
|
+
async def _initialize_core(self) -> None:
|
996
|
+
if self._initialization_attempts == 1:
|
997
|
+
raise _ExampleLooperError
|
998
|
+
await super()._initialize_core()
|
999
|
+
|
1000
|
+
looper = Example()
|
1001
|
+
_ = await looper.initialize()
|
1002
|
+
_ = one(
|
1003
|
+
m
|
1004
|
+
for m in caplog.messages
|
1005
|
+
if search(r": encountered _ExampleLooperError\(\) whilst initializing$", m)
|
1006
|
+
)
|
1007
|
+
|
1008
|
+
def test_len_and_qsize(self) -> None:
|
1009
|
+
looper = _ExampleLooper()
|
1010
|
+
assert len(looper) == looper.qsize() == 0
|
1011
|
+
looper.put_left_nowait(None)
|
1012
|
+
assert len(looper) == looper.qsize() == 1
|
1013
|
+
|
1014
|
+
def test_replace(self) -> None:
|
1015
|
+
looper = _ExampleLooper().replace(freq=SECOND)
|
1016
|
+
assert looper.freq == SECOND
|
1017
|
+
|
1018
|
+
async def test_request_restart(self) -> None:
|
1019
|
+
class Example(_ExampleLooper):
|
1020
|
+
@override
|
1021
|
+
async def core(self) -> None:
|
1022
|
+
await super().core()
|
1023
|
+
if (self._initialization_attempts >= 2) and (
|
1024
|
+
self.count >= (self.max_count / 2)
|
1025
|
+
):
|
1026
|
+
self.request_restart()
|
1027
|
+
|
1028
|
+
looper = Example(auto_start=True, timeout=SECOND)
|
1029
|
+
async with looper:
|
1030
|
+
...
|
1031
|
+
self._assert_stats(
|
1032
|
+
looper,
|
1033
|
+
core_successes=79,
|
1034
|
+
core_failures=1,
|
1035
|
+
initialization_successes=16,
|
1036
|
+
tear_down_successes=15,
|
1037
|
+
restart_successes=15,
|
1038
|
+
stops=1,
|
1039
|
+
)
|
1040
|
+
|
1041
|
+
def test_request_restart_already_requested(
|
1042
|
+
self, *, caplog: LogCaptureFixture
|
1043
|
+
) -> None:
|
1044
|
+
looper = _ExampleLooper()
|
1045
|
+
for _ in range(2):
|
1046
|
+
looper.request_restart()
|
1047
|
+
_ = one(
|
1048
|
+
m for m in caplog.messages if search(r": already requested restart$", m)
|
1049
|
+
)
|
1050
|
+
|
1051
|
+
async def test_request_stop(self) -> None:
|
1052
|
+
class Example(_ExampleLooper):
|
1053
|
+
@override
|
1054
|
+
async def core(self) -> None:
|
1055
|
+
await super().core()
|
1056
|
+
if (self._initialization_attempts >= 2) and (
|
1057
|
+
self.count >= (self.max_count / 2)
|
1058
|
+
):
|
1059
|
+
self.request_stop()
|
1060
|
+
|
1061
|
+
looper = Example(auto_start=True, timeout=SECOND)
|
1062
|
+
async with looper:
|
1063
|
+
...
|
1064
|
+
self._assert_stats(
|
1065
|
+
looper,
|
1066
|
+
core_successes=14,
|
1067
|
+
core_failures=1,
|
1068
|
+
initialization_successes=2,
|
1069
|
+
tear_down_successes=1,
|
1070
|
+
restart_successes=1,
|
1071
|
+
stops=1,
|
1072
|
+
)
|
1073
|
+
|
1074
|
+
def test_request_stop_already_requested(self, *, caplog: LogCaptureFixture) -> None:
|
1075
|
+
looper = _ExampleLooper()
|
1076
|
+
for _ in range(2):
|
1077
|
+
looper.request_stop()
|
1078
|
+
_ = one(m for m in caplog.messages if search(r": already requested stop$", m))
|
1079
|
+
|
1080
|
+
async def test_request_stop_when_empty(self) -> None:
|
1081
|
+
class Example(_ExampleLooper):
|
1082
|
+
@override
|
1083
|
+
async def core(self) -> None:
|
1084
|
+
await super().core()
|
1085
|
+
if self.empty():
|
1086
|
+
await self.stop()
|
1087
|
+
match self.qsize() % 2 == 0:
|
1088
|
+
case True:
|
1089
|
+
_ = self.get_left_nowait()
|
1090
|
+
case False:
|
1091
|
+
_ = self.get_right_nowait()
|
1092
|
+
self.request_stop_when_empty()
|
1093
|
+
|
1094
|
+
looper = Example(auto_start=True, timeout=SECOND)
|
1095
|
+
for i in range(25):
|
1096
|
+
match i % 2 == 0:
|
1097
|
+
case True:
|
1098
|
+
looper.put_left_nowait(i)
|
1099
|
+
case False:
|
1100
|
+
looper.put_right_nowait(i)
|
1101
|
+
async with looper:
|
1102
|
+
...
|
1103
|
+
self._assert_stats(
|
1104
|
+
looper,
|
1105
|
+
core_successes=25,
|
1106
|
+
core_failures=2,
|
1107
|
+
initialization_successes=3,
|
1108
|
+
tear_down_successes=2,
|
1109
|
+
restart_successes=2,
|
1110
|
+
stops=1,
|
1111
|
+
)
|
1112
|
+
|
1113
|
+
def test_request_stop_when_empty_already_requested(
|
1114
|
+
self, *, caplog: LogCaptureFixture
|
1115
|
+
) -> None:
|
1116
|
+
looper = _ExampleLooper()
|
1117
|
+
for _ in range(2):
|
1118
|
+
looper.request_stop_when_empty()
|
1119
|
+
_ = one(
|
1120
|
+
m
|
1121
|
+
for m in caplog.messages
|
1122
|
+
if search(r": already requested stop when empty$", m)
|
1123
|
+
)
|
1124
|
+
|
1125
|
+
async def test_restart_failure_during_initialization(
|
1126
|
+
self, *, caplog: LogCaptureFixture
|
1127
|
+
) -> None:
|
1128
|
+
class Example(_ExampleLooper):
|
1129
|
+
@override
|
1130
|
+
async def _initialize_core(self) -> None:
|
1131
|
+
if self._initialization_attempts == 1:
|
1132
|
+
raise _ExampleLooperError
|
1133
|
+
await super()._initialize_core()
|
1134
|
+
|
1135
|
+
looper = Example()
|
1136
|
+
await looper.restart()
|
1137
|
+
_ = one(
|
1138
|
+
m
|
1139
|
+
for m in caplog.messages
|
1140
|
+
if search(
|
1141
|
+
r": encountered _ExampleLooperError\(\) whilst restarting, during initialization$",
|
1142
|
+
m,
|
1143
|
+
)
|
1144
|
+
)
|
1145
|
+
|
1146
|
+
async def test_restart_failure_during_tear_down(
|
1147
|
+
self, *, caplog: LogCaptureFixture
|
1148
|
+
) -> None:
|
1149
|
+
class Example(_ExampleLooper):
|
1150
|
+
@override
|
1151
|
+
async def _tear_down_core(self) -> None:
|
1152
|
+
if self._tear_down_attempts == 1:
|
1153
|
+
raise _ExampleLooperError
|
1154
|
+
await super()._tear_down_core()
|
1155
|
+
|
1156
|
+
looper = Example()
|
1157
|
+
await looper.restart()
|
1158
|
+
_ = one(
|
1159
|
+
m
|
1160
|
+
for m in caplog.messages
|
1161
|
+
if search(
|
1162
|
+
r": encountered _ExampleLooperError\(\) whilst restarting, during tear down$",
|
1163
|
+
m,
|
1164
|
+
)
|
1165
|
+
)
|
1166
|
+
|
1167
|
+
async def test_restart_failure_during_tear_down_and_initialization(
|
1168
|
+
self, *, caplog: LogCaptureFixture
|
1169
|
+
) -> None:
|
1170
|
+
class Example(_ExampleLooper):
|
1171
|
+
@override
|
1172
|
+
async def _initialize_core(self) -> None:
|
1173
|
+
if self._initialization_attempts == 1:
|
1174
|
+
raise _ExampleLooperError
|
1175
|
+
await super()._initialize_core()
|
1176
|
+
|
1177
|
+
@override
|
1178
|
+
async def _tear_down_core(self) -> None:
|
1179
|
+
if self._tear_down_attempts == 1:
|
1180
|
+
raise _ExampleLooperError
|
1181
|
+
await super()._tear_down_core()
|
1182
|
+
|
1183
|
+
looper = Example()
|
1184
|
+
await looper.restart()
|
1185
|
+
_ = one(
|
1186
|
+
m
|
1187
|
+
for m in caplog.messages
|
1188
|
+
if search(
|
1189
|
+
r": encountered _ExampleLooperError\(\) \(tear down\) and then _ExampleLooperError\(\) \(initialization\) whilst restarting$",
|
1190
|
+
m,
|
1191
|
+
)
|
1192
|
+
)
|
1193
|
+
|
1194
|
+
async def test_sub_looper(self) -> None:
|
1195
|
+
looper = _ExampleOuterLooper(auto_start=True, timeout=SECOND)
|
1196
|
+
looper.inner.auto_start = True
|
1197
|
+
async with looper:
|
1198
|
+
...
|
1199
|
+
self._assert_stats(looper, stops=1)
|
1200
|
+
self._assert_stats(
|
1201
|
+
looper.inner,
|
1202
|
+
core_successes=56,
|
1203
|
+
core_failures=13,
|
1204
|
+
initialization_successes=14,
|
1205
|
+
tear_down_successes=13,
|
1206
|
+
restart_successes=13,
|
1207
|
+
stops=1,
|
1208
|
+
)
|
1209
|
+
|
1210
|
+
async def test_sub_looper_changing_to_auto_start(
|
1211
|
+
self, *, caplog: LogCaptureFixture
|
1212
|
+
) -> None:
|
1213
|
+
looper = _ExampleOuterLooper(auto_start=True, timeout=SECOND)
|
1214
|
+
async with looper:
|
1215
|
+
...
|
1216
|
+
_ = one(
|
1217
|
+
m
|
1218
|
+
for m in caplog.messages
|
1219
|
+
if search(
|
1220
|
+
r": changing sub-looper _ExampleLooper\(.*?\) to auto-start...$", m
|
1221
|
+
)
|
1222
|
+
)
|
1223
|
+
|
1224
|
+
async def test_tear_down_already_initializing(
|
1225
|
+
self, *, caplog: LogCaptureFixture
|
1226
|
+
) -> None:
|
1227
|
+
class Example(_ExampleLooper):
|
1228
|
+
@override
|
1229
|
+
async def _tear_down_core(self) -> None:
|
1230
|
+
if self._tear_down_attempts == 1:
|
1231
|
+
_ = await super().tear_down()
|
1232
|
+
await super()._tear_down_core()
|
1233
|
+
|
1234
|
+
looper = Example()
|
1235
|
+
_ = await looper.tear_down()
|
1236
|
+
_ = one(m for m in caplog.messages if search(": already tearing down$", m))
|
1237
|
+
|
1238
|
+
async def test_tear_down_failure(self, *, caplog: LogCaptureFixture) -> None:
|
1239
|
+
class Example(_ExampleLooper):
|
1240
|
+
@override
|
1241
|
+
async def _tear_down_core(self) -> None:
|
1242
|
+
if self._tear_down_attempts == 1:
|
1243
|
+
raise _ExampleLooperError
|
1244
|
+
await super()._tear_down_core()
|
1245
|
+
|
1246
|
+
looper = Example()
|
1247
|
+
_ = await looper.tear_down()
|
1248
|
+
_ = one(
|
1249
|
+
m
|
1250
|
+
for m in caplog.messages
|
1251
|
+
if search(r": encountered _ExampleLooperError\(\) whilst tearing down$", m)
|
1252
|
+
)
|
1253
|
+
|
1254
|
+
def _assert_stats(
|
1255
|
+
self,
|
1256
|
+
looper: _ExampleLooper,
|
1257
|
+
/,
|
1258
|
+
*,
|
1259
|
+
entries: int = 1,
|
1260
|
+
core_successes: int = 45,
|
1261
|
+
core_failures: int = 5,
|
1262
|
+
initialization_successes: int = 6,
|
1263
|
+
initialization_failures: int = 0,
|
1264
|
+
tear_down_successes: int = 5,
|
1265
|
+
tear_down_failures: int = 0,
|
1266
|
+
restart_successes: int = 5,
|
1267
|
+
restart_failures: int = 0,
|
1268
|
+
stops: int = 0,
|
1269
|
+
) -> None:
|
1270
|
+
stats = looper.stats
|
1271
|
+
assert stats.entries == entries
|
1272
|
+
assert stats.core_attempts == (stats.core_successes + stats.core_failures)
|
1273
|
+
assert stats.core_successes == approx(core_successes, rel=0.5)
|
1274
|
+
assert stats.core_failures == approx(core_failures, rel=0.5)
|
1275
|
+
assert stats.initialization_attempts == (
|
1276
|
+
stats.initialization_successes + stats.initialization_failures
|
1277
|
+
)
|
1278
|
+
assert stats.initialization_successes == approx(
|
1279
|
+
initialization_successes, rel=0.5
|
1280
|
+
)
|
1281
|
+
assert stats.initialization_failures == approx(initialization_failures, rel=0.5)
|
1282
|
+
assert stats.tear_down_attempts == (
|
1283
|
+
stats.tear_down_successes + stats.tear_down_failures
|
1284
|
+
)
|
1285
|
+
assert stats.tear_down_successes == approx(tear_down_successes, rel=0.5)
|
1286
|
+
assert stats.tear_down_failures == approx(tear_down_failures, rel=0.5)
|
1287
|
+
assert stats.restart_attempts == (
|
1288
|
+
stats.restart_successes + stats.restart_failures
|
1289
|
+
)
|
1290
|
+
assert stats.restart_successes == approx(restart_successes, rel=0.5)
|
1291
|
+
assert stats.restart_failures == approx(restart_failures, rel=0.5)
|
1292
|
+
assert stats.stops == stops
|
1293
|
+
|
1294
|
+
|
875
1295
|
class TestPutItems:
|
876
1296
|
@given(xs=lists(integers(), min_size=1), wait=booleans())
|
877
1297
|
async def test_main(self, *, xs: list[int], wait: bool) -> None:
|