dycw-utilities 0.126.10__tar.gz → 0.126.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.126.10 → dycw_utilities-0.126.12}/PKG-INFO +1 -1
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/pyproject.toml +2 -2
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_asyncio.py +86 -57
- dycw_utilities-0.126.12/src/tests/test_asyncio_classes/loopers.py +310 -0
- dycw_utilities-0.126.12/src/tests/test_asyncio_classes/redis.py +28 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_redis.py +140 -37
- dycw_utilities-0.126.12/src/tests/test_reprlib.py +87 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_sqlalchemy.py +32 -1
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/__init__.py +1 -1
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/redis.py +115 -5
- dycw_utilities-0.126.12/src/utilities/reprlib.py +158 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/sqlalchemy.py +65 -1
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/traceback.py +3 -5
- dycw_utilities-0.126.10/src/tests/test_asyncio_classes/loopers.py +0 -168
- dycw_utilities-0.126.10/src/tests/test_reprlib.py +0 -38
- dycw_utilities-0.126.10/src/tests/test_rich.py +0 -24
- dycw_utilities-0.126.10/src/utilities/reprlib.py +0 -74
- dycw_utilities-0.126.10/src/utilities/rich.py +0 -74
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/.gitignore +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/LICENSE +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/README.md +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/__init__.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/conftest.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/modules/__init__.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/modules/package_missing/__init__.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/modules/package_missing/module.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/modules/package_with/__init__.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/modules/package_with/outer_1.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/modules/package_with/outer_2.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/modules/package_without/__init__.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/modules/package_without/module_1.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/modules/package_without/module_2.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/modules/standalone.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/modules/with_imports.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_altair.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_asyncio_classes/__init__.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_atomicwrites.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_atools.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_cachetools.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_click.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_concurrent.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_contextlib.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_contextvars.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_cryptography.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_cvxpy.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_dataclasses.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_datetime.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_enum.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_errors.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_eventkit.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_fastapi.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_fpdf2.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_functions.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_functools.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_getpass.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_git.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_hashlib.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_http.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_hypothesis.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_importlib.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_ipython.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_iterables.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_jupyter.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_libcst.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_lightweight_charts.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_logging.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_loguru.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_luigi.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_math.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_memory_profiler.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_modules.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_more_itertools.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_numpy.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_operator.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_optuna.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_orjson.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_os.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_parse.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_pathlib.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_period.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_pickle.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_platform.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_polars.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_polars_ols.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_pottery.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_pqdm.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_psutil.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_pydantic.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_pyinstrument.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_pyrsistent.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_pytest.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_pytest_regressions.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_python_dotenv.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_random.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_re.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_scipy.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_sentinel.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_shelve.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_slack_sdk.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_socket.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_statsmodel.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_streamlit.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_string.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_sys.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_tempfile.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_tenacity.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_text.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_threading.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_timer.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_traceback.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_traceback_funcs/__init__.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_traceback_funcs/chain.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_traceback_funcs/error_bind.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_traceback_funcs/many.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_traceback_funcs/one.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_traceback_funcs/recursive.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_traceback_funcs/two.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_traceback_funcs/untraced.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_types.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_typing.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_typing_funcs/__init__.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_typing_funcs/no_future.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_typing_funcs/with_future.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_tzdata.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_tzlocal.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_uuid.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_version.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_warnings.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_whenever.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_zipfile.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/tests/test_zoneinfo.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/altair.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/asyncio.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/atomicwrites.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/atools.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/cachetools.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/click.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/concurrent.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/contextlib.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/contextvars.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/cryptography.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/cvxpy.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/dataclasses.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/datetime.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/enum.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/errors.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/eventkit.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/fastapi.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/fpdf2.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/functions.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/functools.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/getpass.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/git.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/hashlib.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/http.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/hypothesis.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/importlib.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/ipython.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/iterables.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/jupyter.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/libcst.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/lightweight_charts.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/logging.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/loguru.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/luigi.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/math.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/memory_profiler.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/modules.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/more_itertools.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/numpy.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/operator.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/optuna.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/orjson.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/os.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/parse.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/pathlib.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/period.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/pickle.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/platform.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/polars.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/polars_ols.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/pottery.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/pqdm.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/psutil.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/py.typed +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/pydantic.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/pyinstrument.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/pyrsistent.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/pytest.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/pytest_regressions.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/python_dotenv.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/random.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/re.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/scipy.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/sentinel.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/shelve.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/slack_sdk.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/socket.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/statsmodels.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/streamlit.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/string.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/sys.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/tempfile.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/tenacity.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/text.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/threading.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/timer.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/types.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/typing.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/tzdata.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/tzlocal.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/uuid.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/version.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/warnings.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/whenever.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/zipfile.py +0 -0
- {dycw_utilities-0.126.10 → dycw_utilities-0.126.12}/src/utilities/zoneinfo.py +0 -0
@@ -94,7 +94,7 @@ dependencies = [
|
|
94
94
|
name = "dycw-utilities"
|
95
95
|
readme = "README.md"
|
96
96
|
requires-python = ">= 3.12"
|
97
|
-
version = "0.126.
|
97
|
+
version = "0.126.12"
|
98
98
|
|
99
99
|
[project.optional-dependencies]
|
100
100
|
test = [
|
@@ -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.126.
|
337
|
+
current_version = "0.126.12"
|
338
338
|
|
339
339
|
[[tool.bumpversion.files]]
|
340
340
|
filename = "src/utilities/__init__.py"
|
@@ -21,16 +21,20 @@ from hypothesis.strategies import (
|
|
21
21
|
permutations,
|
22
22
|
sampled_from,
|
23
23
|
)
|
24
|
-
from pytest import LogCaptureFixture,
|
24
|
+
from pytest import LogCaptureFixture, mark, param, raises
|
25
25
|
|
26
26
|
from tests.test_asyncio_classes.loopers import (
|
27
|
+
_REL,
|
27
28
|
CountingLooper,
|
28
29
|
CountingLooperError,
|
29
30
|
LooperWithCounterMixin,
|
31
|
+
LooperWithCounterMixins,
|
30
32
|
MultipleSubLoopers,
|
31
33
|
Outer2CountingLooper,
|
32
34
|
OuterCountingLooper,
|
33
35
|
QueueLooper,
|
36
|
+
assert_looper_full,
|
37
|
+
assert_looper_stats,
|
34
38
|
)
|
35
39
|
from utilities.asyncio import (
|
36
40
|
EnhancedQueue,
|
@@ -195,6 +199,7 @@ class TestEnhancedTaskGroup:
|
|
195
199
|
assert looper.running
|
196
200
|
assert not looper.running
|
197
201
|
|
202
|
+
@mark.flaky
|
198
203
|
async def test_max_tasks_disabled(self) -> None:
|
199
204
|
with Timer() as timer:
|
200
205
|
async with EnhancedTaskGroup() as tg:
|
@@ -607,8 +612,8 @@ class TestInfiniteLooper:
|
|
607
612
|
|
608
613
|
async with timeout(1.0), Parent(sleep_core=0.05) as parent:
|
609
614
|
...
|
610
|
-
assert
|
611
|
-
assert
|
615
|
+
assert 12 <= parent.counter <= 25
|
616
|
+
assert 12 <= parent.child.counter <= 25
|
612
617
|
|
613
618
|
async def test_error_default_event(self) -> None:
|
614
619
|
@dataclass(kw_only=True)
|
@@ -864,6 +869,7 @@ class TestInfiniteQueueLooper:
|
|
864
869
|
assert looper.empty()
|
865
870
|
|
866
871
|
@given(logger=just("logger") | none())
|
872
|
+
@mark.flaky
|
867
873
|
@settings(suppress_health_check={HealthCheck.function_scoped_fixture})
|
868
874
|
async def test_error_process_items(
|
869
875
|
self, *, logger: str | None, caplog: LogCaptureFixture
|
@@ -1007,6 +1013,70 @@ class TestLooper:
|
|
1007
1013
|
...
|
1008
1014
|
self._assert_stats_half(looper._counter, stops=1)
|
1009
1015
|
|
1016
|
+
@mark.parametrize("counter_auto_start", [param(True), param(False)])
|
1017
|
+
async def test_mixin_in_task_group(self, *, counter_auto_start: bool) -> None:
|
1018
|
+
looper = LooperWithCounterMixin(
|
1019
|
+
auto_start=True, timeout=1.0, counter_auto_start=counter_auto_start
|
1020
|
+
)
|
1021
|
+
with raises(ExceptionGroup) as exc_info:
|
1022
|
+
async with EnhancedTaskGroup(timeout=looper.timeout) as tg:
|
1023
|
+
_ = tg.create_task_context(looper)
|
1024
|
+
error = one(exc_info.value.exceptions)
|
1025
|
+
assert isinstance(error, TimeoutError)
|
1026
|
+
self._assert_stats_half(looper._counter)
|
1027
|
+
|
1028
|
+
@mark.parametrize("counter1_auto_start", [param(True), param(False)])
|
1029
|
+
@mark.parametrize("counter2_auto_start", [param(True), param(False)])
|
1030
|
+
async def test_mixins(
|
1031
|
+
self, *, counter1_auto_start: bool, counter2_auto_start: bool
|
1032
|
+
) -> None:
|
1033
|
+
looper = LooperWithCounterMixins(
|
1034
|
+
auto_start=True,
|
1035
|
+
timeout=1.0,
|
1036
|
+
counter1_auto_start=counter1_auto_start,
|
1037
|
+
counter2_auto_start=counter2_auto_start,
|
1038
|
+
)
|
1039
|
+
match counter1_auto_start, counter2_auto_start:
|
1040
|
+
case _, True:
|
1041
|
+
with raises(TimeoutError):
|
1042
|
+
async with timeout(1.0), looper:
|
1043
|
+
...
|
1044
|
+
assert_looper_full(looper)
|
1045
|
+
self._assert_stats_no_runs(looper._counter1)
|
1046
|
+
self._assert_stats_third(looper._counter2)
|
1047
|
+
case True, False:
|
1048
|
+
with raises(TimeoutError):
|
1049
|
+
async with timeout(1.0), looper:
|
1050
|
+
...
|
1051
|
+
assert_looper_full(looper)
|
1052
|
+
self._assert_stats_half(looper._counter1)
|
1053
|
+
self._assert_stats_third(looper._counter2)
|
1054
|
+
case False, False:
|
1055
|
+
async with looper:
|
1056
|
+
...
|
1057
|
+
assert_looper_full(looper, stops=1)
|
1058
|
+
self._assert_stats_half(looper._counter1, stops=1)
|
1059
|
+
self._assert_stats_third(looper._counter2, stops=1)
|
1060
|
+
|
1061
|
+
@mark.parametrize("counter_auto_start", [param(True), param(False)])
|
1062
|
+
async def test_mixins_in_task_group(self, *, counter_auto_start: bool) -> None:
|
1063
|
+
looper1 = LooperWithCounterMixin(
|
1064
|
+
auto_start=True, timeout=1.0, counter_auto_start=counter_auto_start
|
1065
|
+
)
|
1066
|
+
looper2 = LooperWithCounterMixin(
|
1067
|
+
auto_start=True, timeout=1.0, counter_auto_start=counter_auto_start
|
1068
|
+
)
|
1069
|
+
with raises(ExceptionGroup) as exc_info: # noqa: PT012
|
1070
|
+
async with EnhancedTaskGroup(timeout=1.0) as tg:
|
1071
|
+
_ = tg.create_task_context(looper1)
|
1072
|
+
_ = tg.create_task_context(looper2)
|
1073
|
+
errors = exc_info.value.exceptions
|
1074
|
+
assert 1 <= len(errors) <= 2
|
1075
|
+
for error in errors:
|
1076
|
+
assert isinstance(error, TimeoutError)
|
1077
|
+
self._assert_stats_half(looper1._counter)
|
1078
|
+
self._assert_stats_half(looper2._counter)
|
1079
|
+
|
1010
1080
|
def test_replace(self) -> None:
|
1011
1081
|
looper = CountingLooper().replace(freq=10.0)
|
1012
1082
|
assert looper.freq == 10.0
|
@@ -1024,7 +1094,7 @@ class TestLooper:
|
|
1024
1094
|
looper = Example(auto_start=True, timeout=1.0)
|
1025
1095
|
async with looper:
|
1026
1096
|
...
|
1027
|
-
|
1097
|
+
assert_looper_stats(
|
1028
1098
|
looper,
|
1029
1099
|
entries=1,
|
1030
1100
|
core_successes=79,
|
@@ -1058,7 +1128,7 @@ class TestLooper:
|
|
1058
1128
|
looper = Example(auto_start=True, timeout=1.0)
|
1059
1129
|
async with looper:
|
1060
1130
|
...
|
1061
|
-
|
1131
|
+
assert_looper_stats(
|
1062
1132
|
looper,
|
1063
1133
|
entries=1,
|
1064
1134
|
core_successes=14,
|
@@ -1098,7 +1168,7 @@ class TestLooper:
|
|
1098
1168
|
looper.put_right_nowait(i)
|
1099
1169
|
async with looper:
|
1100
1170
|
...
|
1101
|
-
|
1171
|
+
assert_looper_stats(
|
1102
1172
|
looper,
|
1103
1173
|
entries=1,
|
1104
1174
|
core_successes=25,
|
@@ -1301,47 +1371,6 @@ class TestLooper:
|
|
1301
1371
|
assert not looper.auto_start
|
1302
1372
|
assert looper.with_auto_start.auto_start
|
1303
1373
|
|
1304
|
-
def _assert_stats(
|
1305
|
-
self,
|
1306
|
-
looper: Looper[Any],
|
1307
|
-
/,
|
1308
|
-
*,
|
1309
|
-
entries: int = 0,
|
1310
|
-
core_successes: int = 0,
|
1311
|
-
core_failures: int = 0,
|
1312
|
-
initialization_successes: int = 0,
|
1313
|
-
initialization_failures: int = 0,
|
1314
|
-
tear_down_successes: int = 0,
|
1315
|
-
tear_down_failures: int = 0,
|
1316
|
-
restart_successes: int = 0,
|
1317
|
-
restart_failures: int = 0,
|
1318
|
-
stops: int = 0,
|
1319
|
-
rel: float = 0.5,
|
1320
|
-
) -> None:
|
1321
|
-
stats = looper.stats
|
1322
|
-
assert stats.entries == entries
|
1323
|
-
assert stats.core_attempts == (stats.core_successes + stats.core_failures)
|
1324
|
-
assert stats.core_successes == approx(core_successes, rel=rel)
|
1325
|
-
assert stats.core_failures == approx(core_failures, rel=rel)
|
1326
|
-
assert stats.initialization_attempts == (
|
1327
|
-
stats.initialization_successes + stats.initialization_failures
|
1328
|
-
)
|
1329
|
-
assert stats.initialization_successes == approx(
|
1330
|
-
initialization_successes, rel=rel
|
1331
|
-
)
|
1332
|
-
assert stats.initialization_failures == approx(initialization_failures, rel=rel)
|
1333
|
-
assert stats.tear_down_attempts == (
|
1334
|
-
stats.tear_down_successes + stats.tear_down_failures
|
1335
|
-
)
|
1336
|
-
assert stats.tear_down_successes == approx(tear_down_successes, rel=rel)
|
1337
|
-
assert stats.tear_down_failures == approx(tear_down_failures, rel=rel)
|
1338
|
-
assert stats.restart_attempts == (
|
1339
|
-
stats.restart_successes + stats.restart_failures
|
1340
|
-
)
|
1341
|
-
assert stats.restart_successes == approx(restart_successes, rel=rel)
|
1342
|
-
assert stats.restart_failures == approx(restart_failures, rel=rel)
|
1343
|
-
assert stats.stops == stops
|
1344
|
-
|
1345
1374
|
def _assert_stats_no_runs(
|
1346
1375
|
self,
|
1347
1376
|
looper: Looper[Any],
|
@@ -1349,14 +1378,14 @@ class TestLooper:
|
|
1349
1378
|
*,
|
1350
1379
|
entries: int = 0,
|
1351
1380
|
stops: int = 0,
|
1352
|
-
rel: float =
|
1381
|
+
rel: float = _REL,
|
1353
1382
|
) -> None:
|
1354
|
-
|
1383
|
+
assert_looper_stats(looper, entries=entries, stops=stops, rel=rel)
|
1355
1384
|
|
1356
1385
|
def _assert_stats_full(
|
1357
|
-
self, looper: Looper[Any], /, *, stops: int = 0, rel: float =
|
1386
|
+
self, looper: Looper[Any], /, *, stops: int = 0, rel: float = _REL
|
1358
1387
|
) -> None:
|
1359
|
-
|
1388
|
+
assert_looper_stats(
|
1360
1389
|
looper,
|
1361
1390
|
entries=1,
|
1362
1391
|
core_successes=45,
|
@@ -1369,9 +1398,9 @@ class TestLooper:
|
|
1369
1398
|
)
|
1370
1399
|
|
1371
1400
|
def _assert_stats_half(
|
1372
|
-
self, looper: Looper[Any], /, *, stops: int = 0, rel: float =
|
1401
|
+
self, looper: Looper[Any], /, *, stops: int = 0, rel: float = _REL
|
1373
1402
|
) -> None:
|
1374
|
-
|
1403
|
+
assert_looper_stats(
|
1375
1404
|
looper,
|
1376
1405
|
entries=1,
|
1377
1406
|
core_successes=56,
|
@@ -1384,9 +1413,9 @@ class TestLooper:
|
|
1384
1413
|
)
|
1385
1414
|
|
1386
1415
|
def _assert_stats_third(
|
1387
|
-
self, looper: Looper[Any], /, *, stops: int = 0, rel: float =
|
1416
|
+
self, looper: Looper[Any], /, *, stops: int = 0, rel: float = _REL
|
1388
1417
|
) -> None:
|
1389
|
-
|
1418
|
+
assert_looper_stats(
|
1390
1419
|
looper,
|
1391
1420
|
entries=1,
|
1392
1421
|
core_successes=49,
|
@@ -1399,9 +1428,9 @@ class TestLooper:
|
|
1399
1428
|
)
|
1400
1429
|
|
1401
1430
|
def _assert_stats_quarter(
|
1402
|
-
self, looper: Looper[Any], /, *, stops: int = 0, rel: float =
|
1431
|
+
self, looper: Looper[Any], /, *, stops: int = 0, rel: float = _REL
|
1403
1432
|
) -> None:
|
1404
|
-
|
1433
|
+
assert_looper_stats(
|
1405
1434
|
looper,
|
1406
1435
|
entries=1,
|
1407
1436
|
core_successes=35,
|
@@ -0,0 +1,310 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from dataclasses import dataclass, field
|
4
|
+
from typing import TYPE_CHECKING, Any, Literal, override
|
5
|
+
|
6
|
+
from pytest import approx
|
7
|
+
|
8
|
+
from utilities.asyncio import Looper
|
9
|
+
from utilities.contextlib import suppress_super_object_attribute_error
|
10
|
+
from utilities.datetime import MILLISECOND
|
11
|
+
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from collections.abc import Iterator
|
14
|
+
|
15
|
+
from utilities.types import Duration
|
16
|
+
|
17
|
+
_FREQ: Duration = 10 * MILLISECOND
|
18
|
+
_BACKOFF: Duration = 100 * MILLISECOND
|
19
|
+
_REL: float = 0.75
|
20
|
+
|
21
|
+
|
22
|
+
# assert
|
23
|
+
|
24
|
+
|
25
|
+
def assert_looper_stats(
|
26
|
+
looper: Looper[Any],
|
27
|
+
/,
|
28
|
+
*,
|
29
|
+
entries: int = 0,
|
30
|
+
core_successes: int | tuple[Literal[">="], int] = 0,
|
31
|
+
core_failures: int = 0,
|
32
|
+
initialization_successes: int = 0,
|
33
|
+
initialization_failures: int = 0,
|
34
|
+
tear_down_successes: int = 0,
|
35
|
+
tear_down_failures: int = 0,
|
36
|
+
restart_successes: int = 0,
|
37
|
+
restart_failures: int = 0,
|
38
|
+
stops: int = 0,
|
39
|
+
rel: float = _REL,
|
40
|
+
) -> None:
|
41
|
+
stats = looper.stats
|
42
|
+
assert stats.entries == entries, f"{stats=}, {entries=}"
|
43
|
+
assert stats.core_attempts == (stats.core_successes + stats.core_failures), (
|
44
|
+
f"{stats=}"
|
45
|
+
)
|
46
|
+
match core_successes:
|
47
|
+
case int():
|
48
|
+
assert stats.core_successes == approx(core_successes, rel=rel), (
|
49
|
+
f"{stats=}, {core_successes=}"
|
50
|
+
)
|
51
|
+
case ">=", int() as min_successes:
|
52
|
+
assert stats.core_successes >= min_successes, f"{stats=}, {min_successes=}"
|
53
|
+
assert stats.core_failures == approx(core_failures, rel=rel), (
|
54
|
+
f"{stats=}, {core_failures=}"
|
55
|
+
)
|
56
|
+
assert stats.initialization_attempts == (
|
57
|
+
stats.initialization_successes + stats.initialization_failures
|
58
|
+
), f"{stats=}"
|
59
|
+
assert stats.initialization_successes == approx(
|
60
|
+
initialization_successes, rel=rel
|
61
|
+
), f"{stats=}, {initialization_successes=}"
|
62
|
+
assert stats.initialization_failures == approx(initialization_failures, rel=rel), (
|
63
|
+
f"{stats=}, {initialization_failures=}"
|
64
|
+
)
|
65
|
+
assert stats.tear_down_attempts == (
|
66
|
+
stats.tear_down_successes + stats.tear_down_failures
|
67
|
+
), f"{stats=}"
|
68
|
+
assert stats.tear_down_successes == approx(tear_down_successes, rel=rel), (
|
69
|
+
f"{stats=}, {tear_down_successes=}"
|
70
|
+
)
|
71
|
+
assert stats.tear_down_failures == approx(tear_down_failures, rel=rel), (
|
72
|
+
f"{stats=}, {initialization_failures=}"
|
73
|
+
)
|
74
|
+
assert stats.restart_attempts == (
|
75
|
+
stats.restart_successes + stats.restart_failures
|
76
|
+
), f"{stats=}"
|
77
|
+
assert stats.restart_successes == approx(restart_successes, rel=rel), (
|
78
|
+
f"{stats=}, {restart_successes=}"
|
79
|
+
)
|
80
|
+
assert stats.restart_failures == approx(restart_failures, rel=rel), (
|
81
|
+
f"{stats=}, {restart_failures=}"
|
82
|
+
)
|
83
|
+
assert stats.stops == stops, f"{stats=}, {stops=}"
|
84
|
+
|
85
|
+
|
86
|
+
def assert_looper_full(
|
87
|
+
looper: Looper[Any], /, *, stops: int = 0, rel: float = _REL
|
88
|
+
) -> None:
|
89
|
+
assert_looper_stats(
|
90
|
+
looper,
|
91
|
+
entries=1,
|
92
|
+
core_successes=99,
|
93
|
+
initialization_successes=1,
|
94
|
+
stops=stops,
|
95
|
+
rel=rel,
|
96
|
+
)
|
97
|
+
|
98
|
+
|
99
|
+
# counting looper
|
100
|
+
|
101
|
+
|
102
|
+
@dataclass(kw_only=True)
|
103
|
+
class CountingLooper(Looper[Any]):
|
104
|
+
freq: Duration = field(default=_FREQ, repr=False)
|
105
|
+
backoff: Duration = field(default=_BACKOFF, repr=False)
|
106
|
+
_debug: bool = field(default=True, repr=False)
|
107
|
+
count: int = 0
|
108
|
+
max_count: int = 10
|
109
|
+
|
110
|
+
@override
|
111
|
+
async def _initialize_core(self) -> None:
|
112
|
+
await super()._initialize_core()
|
113
|
+
self.count = 0
|
114
|
+
|
115
|
+
@override
|
116
|
+
async def core(self) -> None:
|
117
|
+
await super().core()
|
118
|
+
self.count += 1
|
119
|
+
if self.count >= self.max_count:
|
120
|
+
raise CountingLooperError
|
121
|
+
|
122
|
+
|
123
|
+
class CountingLooperError(Exception): ...
|
124
|
+
|
125
|
+
|
126
|
+
# one sub looper
|
127
|
+
|
128
|
+
|
129
|
+
@dataclass(kw_only=True)
|
130
|
+
class OuterCountingLooper(CountingLooper):
|
131
|
+
inner: CountingLooper = field(init=False, repr=False)
|
132
|
+
inner_auto_start: bool = False
|
133
|
+
|
134
|
+
@override
|
135
|
+
def __post_init__(self) -> None:
|
136
|
+
super().__post_init__()
|
137
|
+
self.inner = CountingLooper(
|
138
|
+
auto_start=self.inner_auto_start,
|
139
|
+
freq=self.freq / 2,
|
140
|
+
backoff=self.backoff / 2,
|
141
|
+
max_count=round(self.max_count / 2),
|
142
|
+
)
|
143
|
+
|
144
|
+
@override
|
145
|
+
def _yield_sub_loopers(self) -> Iterator[Looper]:
|
146
|
+
yield from super()._yield_sub_loopers()
|
147
|
+
yield self.inner
|
148
|
+
|
149
|
+
|
150
|
+
# two sub loopers
|
151
|
+
|
152
|
+
|
153
|
+
@dataclass(kw_only=True)
|
154
|
+
class MultipleSubLoopers(CountingLooper):
|
155
|
+
inner1: CountingLooper = field(init=False, repr=False)
|
156
|
+
inner2: CountingLooper = field(init=False, repr=False)
|
157
|
+
inner1_auto_start: bool = False
|
158
|
+
inner2_auto_start: bool = False
|
159
|
+
|
160
|
+
@override
|
161
|
+
def __post_init__(self) -> None:
|
162
|
+
super().__post_init__()
|
163
|
+
self.inner1 = CountingLooper(
|
164
|
+
auto_start=self.inner1_auto_start,
|
165
|
+
freq=self.freq / 2,
|
166
|
+
backoff=self.backoff / 2,
|
167
|
+
max_count=round(self.max_count / 2),
|
168
|
+
)
|
169
|
+
self.inner2 = CountingLooper(
|
170
|
+
auto_start=self.inner2_auto_start,
|
171
|
+
freq=self.freq / 3,
|
172
|
+
backoff=self.backoff / 3,
|
173
|
+
max_count=round(self.max_count / 3),
|
174
|
+
)
|
175
|
+
|
176
|
+
@override
|
177
|
+
def _yield_sub_loopers(self) -> Iterator[Looper]:
|
178
|
+
yield from super()._yield_sub_loopers()
|
179
|
+
yield self.inner1
|
180
|
+
yield self.inner2
|
181
|
+
|
182
|
+
|
183
|
+
# nested sub loopers
|
184
|
+
|
185
|
+
|
186
|
+
@dataclass(kw_only=True)
|
187
|
+
class Outer2CountingLooper(CountingLooper):
|
188
|
+
middle: OuterCountingLooper = field(init=False, repr=False)
|
189
|
+
middle_auto_start: bool = False
|
190
|
+
inner_auto_start: bool = False
|
191
|
+
|
192
|
+
@override
|
193
|
+
def __post_init__(self) -> None:
|
194
|
+
super().__post_init__()
|
195
|
+
self.middle = OuterCountingLooper(
|
196
|
+
auto_start=self.middle_auto_start,
|
197
|
+
freq=self.freq / 2,
|
198
|
+
backoff=self.backoff / 2,
|
199
|
+
max_count=round(self.max_count / 2),
|
200
|
+
inner_auto_start=self.inner_auto_start,
|
201
|
+
)
|
202
|
+
|
203
|
+
@override
|
204
|
+
def _yield_sub_loopers(self) -> Iterator[Looper]:
|
205
|
+
yield from super()._yield_sub_loopers()
|
206
|
+
yield self.middle
|
207
|
+
|
208
|
+
|
209
|
+
# one mixin
|
210
|
+
|
211
|
+
|
212
|
+
@dataclass(kw_only=True)
|
213
|
+
class CounterMixin:
|
214
|
+
freq: Duration = field(default=_FREQ, repr=False)
|
215
|
+
backoff: Duration = field(default=_BACKOFF, repr=False)
|
216
|
+
_debug: bool = field(default=True, repr=False)
|
217
|
+
count: int = 0
|
218
|
+
max_count: int = 10
|
219
|
+
counter_auto_start: bool = False
|
220
|
+
_counter: CountingLooper = field(init=False, repr=False)
|
221
|
+
|
222
|
+
def __post_init__(self) -> None:
|
223
|
+
with suppress_super_object_attribute_error():
|
224
|
+
super().__post_init__() # pyright: ignore[reportAttributeAccessIssue]
|
225
|
+
self._counter = CountingLooper(
|
226
|
+
auto_start=self.counter_auto_start,
|
227
|
+
freq=self.freq / 2,
|
228
|
+
backoff=self.backoff / 2,
|
229
|
+
max_count=round(self.max_count / 2),
|
230
|
+
)
|
231
|
+
|
232
|
+
def _yield_sub_loopers(self) -> Iterator[Looper[Any]]:
|
233
|
+
with suppress_super_object_attribute_error():
|
234
|
+
yield from super()._yield_sub_loopers() # pyright: ignore[reportAttributeAccessIssue]
|
235
|
+
yield self._counter
|
236
|
+
|
237
|
+
|
238
|
+
@dataclass(kw_only=True)
|
239
|
+
class LooperWithCounterMixin(CounterMixin, Looper): ...
|
240
|
+
|
241
|
+
|
242
|
+
# two mixins
|
243
|
+
|
244
|
+
|
245
|
+
@dataclass(kw_only=True)
|
246
|
+
class CounterMixin1:
|
247
|
+
freq: Duration = field(default=_FREQ, repr=False)
|
248
|
+
backoff: Duration = field(default=_BACKOFF, repr=False)
|
249
|
+
_debug: bool = field(default=True, repr=False)
|
250
|
+
count: int = 0
|
251
|
+
max_count: int = 10
|
252
|
+
counter1_auto_start: bool = False
|
253
|
+
_counter1: CountingLooper = field(init=False, repr=False)
|
254
|
+
|
255
|
+
def __post_init__(self) -> None:
|
256
|
+
with suppress_super_object_attribute_error():
|
257
|
+
super().__post_init__() # pyright: ignore[reportAttributeAccessIssue]
|
258
|
+
self._counter1 = CountingLooper(
|
259
|
+
auto_start=self.counter1_auto_start,
|
260
|
+
freq=self.freq / 2,
|
261
|
+
backoff=self.backoff / 2,
|
262
|
+
max_count=round(self.max_count / 2),
|
263
|
+
)
|
264
|
+
|
265
|
+
def _yield_sub_loopers(self) -> Iterator[Looper[Any]]:
|
266
|
+
with suppress_super_object_attribute_error():
|
267
|
+
yield from super()._yield_sub_loopers() # pyright: ignore[reportAttributeAccessIssue]
|
268
|
+
yield self._counter1
|
269
|
+
|
270
|
+
|
271
|
+
@dataclass(kw_only=True)
|
272
|
+
class CounterMixin2:
|
273
|
+
freq: Duration = field(default=_FREQ, repr=False)
|
274
|
+
backoff: Duration = field(default=_BACKOFF, repr=False)
|
275
|
+
_debug: bool = field(default=True, repr=False)
|
276
|
+
count: int = 0
|
277
|
+
max_count: int = 10
|
278
|
+
counter2_auto_start: bool = False
|
279
|
+
_counter2: CountingLooper = field(init=False, repr=False)
|
280
|
+
|
281
|
+
def __post_init__(self) -> None:
|
282
|
+
with suppress_super_object_attribute_error():
|
283
|
+
super().__post_init__() # pyright: ignore[reportAttributeAccessIssue]
|
284
|
+
self._counter2 = CountingLooper(
|
285
|
+
auto_start=self.counter2_auto_start,
|
286
|
+
freq=self.freq / 3,
|
287
|
+
backoff=self.backoff / 3,
|
288
|
+
max_count=round(self.max_count / 3),
|
289
|
+
)
|
290
|
+
|
291
|
+
def _yield_sub_loopers(self) -> Iterator[Looper[Any]]:
|
292
|
+
with suppress_super_object_attribute_error():
|
293
|
+
yield from super()._yield_sub_loopers() # pyright: ignore[reportAttributeAccessIssue]
|
294
|
+
yield self._counter2
|
295
|
+
|
296
|
+
|
297
|
+
@dataclass(kw_only=True)
|
298
|
+
class LooperWithCounterMixins(CounterMixin1, CounterMixin2, Looper): ...
|
299
|
+
|
300
|
+
|
301
|
+
# queue looper
|
302
|
+
|
303
|
+
|
304
|
+
@dataclass(kw_only=True)
|
305
|
+
class QueueLooper(Looper[int]):
|
306
|
+
@override
|
307
|
+
async def core(self) -> None:
|
308
|
+
await super().core()
|
309
|
+
if not self.empty():
|
310
|
+
_ = self.get_left_nowait()
|
@@ -0,0 +1,28 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from dataclasses import dataclass, field
|
4
|
+
from typing import TYPE_CHECKING, Any
|
5
|
+
|
6
|
+
from tests.test_asyncio_classes.loopers import _BACKOFF, _FREQ
|
7
|
+
from utilities.asyncio import Looper
|
8
|
+
from utilities.redis import PublishServiceMixin, SubscribeServiceMixin
|
9
|
+
from utilities.text import unique_str
|
10
|
+
|
11
|
+
if TYPE_CHECKING:
|
12
|
+
from utilities.types import Duration
|
13
|
+
|
14
|
+
|
15
|
+
@dataclass(kw_only=True)
|
16
|
+
class LooperWithPublishAndSubscribeMixins(
|
17
|
+
PublishServiceMixin[Any], SubscribeServiceMixin[Any], Looper[Any]
|
18
|
+
):
|
19
|
+
freq: Duration = field(default=_FREQ, repr=False)
|
20
|
+
backoff: Duration = field(default=_BACKOFF, repr=False)
|
21
|
+
_debug: bool = field(default=True, repr=False)
|
22
|
+
publish_service_freq: Duration = field(default=_FREQ, repr=False)
|
23
|
+
publish_service_backoff: Duration = field(default=_BACKOFF, repr=False)
|
24
|
+
publish_service_debug: bool = field(default=True, repr=False)
|
25
|
+
subscribe_service_freq: Duration = field(default=_FREQ, repr=False)
|
26
|
+
subscribe_service_backoff: Duration = field(default=_BACKOFF, repr=False)
|
27
|
+
subscribe_service_debug: bool = field(default=True, repr=False)
|
28
|
+
subscribe_service_channel: str = field(default_factory=unique_str)
|