dycw-utilities 0.131.7__tar.gz → 0.131.9__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.7 → dycw_utilities-0.131.9}/PKG-INFO +1 -1
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/pyproject.toml +2 -2
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_aiolimiter.py +2 -1
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_asyncio.py +14 -10
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_re.py +12 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_timer.py +27 -35
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/__init__.py +1 -1
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/asyncio.py +6 -2
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/re.py +51 -20
- dycw_utilities-0.131.9/src/utilities/timer.py +97 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/types.py +6 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/whenever2.py +1 -1
- dycw_utilities-0.131.7/src/utilities/timer.py +0 -131
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/.gitignore +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/LICENSE +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/README.md +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/__init__.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/conftest.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/modules/__init__.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/modules/package_missing/__init__.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/modules/package_missing/module.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/modules/package_with/__init__.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/modules/package_with/outer_1.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/modules/package_with/outer_2.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/modules/package_without/__init__.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/modules/package_without/module_1.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/modules/package_without/module_2.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/modules/standalone.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/modules/with_imports.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_altair.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_asyncio_classes/__init__.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_asyncio_classes/loopers.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_asyncio_classes/redis.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_atomicwrites.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_atools.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_cachetools.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_click.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_concurrent.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_contextlib.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_contextvars.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_cryptography.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_cvxpy.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_dataclasses.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_datetime.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_enum.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_errors.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_eventkit.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_fastapi.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_fpdf2.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_functions.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_functools.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_getpass.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_git.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_hashlib.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_http.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_hypothesis.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_importlib.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_inflect.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_ipython.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_iterables.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_jupyter.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_libcst.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_lightweight_charts.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_logging.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_luigi.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_math.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_memory_profiler.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_modules.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_more_itertools.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_numpy.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_operator.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_optuna.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_orjson.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_os.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_parse.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_pathlib.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_period.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_pickle.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_platform.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_polars.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_polars_ols.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_pottery.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_pqdm.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_psutil.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_pydantic.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_pyinstrument.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_pyrsistent.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_pytest.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_pytest_regressions.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_python_dotenv.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_random.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_redis.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_reprlib.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_scipy.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_sentinel.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_shelve.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_slack_sdk.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_socket.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_sqlalchemy.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_statsmodel.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_streamlit.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_string.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_tempfile.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_tenacity.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_text.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_threading.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_traceback.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_types.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_typing.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_typing_funcs/__init__.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_typing_funcs/no_future.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_typing_funcs/with_future.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_tzdata.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_tzlocal.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_uuid.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_version.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_warnings.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_whenever.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_whenever2.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_zipfile.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/tests/test_zoneinfo.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/aiolimiter.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/altair.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/atomicwrites.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/atools.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/cachetools.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/click.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/concurrent.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/contextlib.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/contextvars.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/cryptography.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/cvxpy.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/dataclasses.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/datetime.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/enum.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/errors.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/eventkit.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/fastapi.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/fpdf2.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/functions.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/functools.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/getpass.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/git.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/hashlib.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/http.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/hypothesis.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/importlib.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/inflect.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/ipython.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/iterables.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/jupyter.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/libcst.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/lightweight_charts.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/logging.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/luigi.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/math.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/memory_profiler.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/modules.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/more_itertools.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/numpy.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/operator.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/optuna.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/orjson.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/os.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/parse.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/pathlib.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/period.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/pickle.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/platform.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/polars.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/polars_ols.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/pottery.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/pqdm.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/psutil.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/py.typed +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/pydantic.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/pyinstrument.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/pyrsistent.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/pytest.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/pytest_regressions.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/python_dotenv.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/random.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/redis.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/reprlib.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/scipy.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/sentinel.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/shelve.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/slack_sdk.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/socket.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/sqlalchemy.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/statsmodels.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/streamlit.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/string.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/tempfile.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/tenacity.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/text.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/threading.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/traceback.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/typing.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/tzdata.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/tzlocal.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/uuid.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/version.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/warnings.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/whenever.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/src/utilities/zipfile.py +0 -0
- {dycw_utilities-0.131.7 → dycw_utilities-0.131.9}/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.131.
|
97
|
+
version = "0.131.9"
|
98
98
|
|
99
99
|
[project.optional-dependencies]
|
100
100
|
logging = [
|
@@ -121,7 +121,7 @@ test = [
|
|
121
121
|
# bump-my-version
|
122
122
|
[tool.bumpversion]
|
123
123
|
allow_dirty = true
|
124
|
-
current_version = "0.131.
|
124
|
+
current_version = "0.131.9"
|
125
125
|
|
126
126
|
[[tool.bumpversion.files]]
|
127
127
|
filename = "src/utilities/__init__.py"
|
@@ -6,6 +6,7 @@ from typing import ClassVar
|
|
6
6
|
from utilities.aiolimiter import get_async_limiter
|
7
7
|
from utilities.text import unique_str
|
8
8
|
from utilities.timer import Timer
|
9
|
+
from utilities.whenever2 import SECOND
|
9
10
|
|
10
11
|
|
11
12
|
class TestGetAsyncLimiter:
|
@@ -22,7 +23,7 @@ class TestGetAsyncLimiter:
|
|
22
23
|
for _ in range(2):
|
23
24
|
async with get_async_limiter(name, rate=0.5):
|
24
25
|
await increment()
|
25
|
-
assert timer >= 0.48
|
26
|
+
assert timer >= 0.48 * SECOND
|
26
27
|
|
27
28
|
shared: ClassVar[str] = unique_str()
|
28
29
|
|
@@ -177,14 +177,14 @@ class TestEnhancedTaskGroup:
|
|
177
177
|
async with EnhancedTaskGroup() as tg:
|
178
178
|
for _ in range(10):
|
179
179
|
_ = tg.create_task(sleep(0.01))
|
180
|
-
assert timer <= 0.05
|
180
|
+
assert timer.timedelta.in_seconds() <= 0.05
|
181
181
|
|
182
182
|
async def test_max_tasks_enabled(self) -> None:
|
183
183
|
with Timer() as timer:
|
184
184
|
async with EnhancedTaskGroup(max_tasks=2) as tg:
|
185
185
|
for _ in range(10):
|
186
186
|
_ = tg.create_task(sleep(0.01))
|
187
|
-
assert timer >= 0.05
|
187
|
+
assert timer.timedelta.in_seconds() >= 0.05
|
188
188
|
|
189
189
|
async def test_timeout_pass(self) -> None:
|
190
190
|
async with EnhancedTaskGroup(timeout=0.2) as tg:
|
@@ -610,7 +610,7 @@ class TestLooper:
|
|
610
610
|
looper = Example()
|
611
611
|
with Timer() as timer:
|
612
612
|
await looper.restart()
|
613
|
-
assert timer.timedelta >= self._restart_min_elapsed
|
613
|
+
assert timer.timedelta.py_timedelta() >= self._restart_min_elapsed
|
614
614
|
pattern = rf": encountered {get_class_name(CountingLooperError)}\(\) whilst restarting \(initialize\); sleeping for .*\.\.\.$"
|
615
615
|
_ = one(m for m in caplog.messages if search(pattern, m))
|
616
616
|
|
@@ -627,7 +627,7 @@ class TestLooper:
|
|
627
627
|
looper = Example()
|
628
628
|
with Timer() as timer:
|
629
629
|
await looper.restart()
|
630
|
-
assert timer.timedelta >= self._restart_min_elapsed
|
630
|
+
assert timer.timedelta.py_timedelta() >= self._restart_min_elapsed
|
631
631
|
pattern = rf": encountered {get_class_name(CountingLooperError)}\(\) whilst restarting \(tear down\); sleeping for .*\.\.\.$"
|
632
632
|
_ = one(m for m in caplog.messages if search(pattern, m))
|
633
633
|
|
@@ -650,7 +650,7 @@ class TestLooper:
|
|
650
650
|
looper = Example()
|
651
651
|
with Timer() as timer:
|
652
652
|
await looper.restart()
|
653
|
-
assert timer.timedelta >= self._restart_min_elapsed
|
653
|
+
assert timer.timedelta.py_timedelta() >= self._restart_min_elapsed
|
654
654
|
pattern = rf": encountered {get_class_name(CountingLooperError)}\(\) \(tear down\) and then {get_class_name(CountingLooperError)}\(\) \(initialization\) whilst restarting; sleeping for .*\.\.\.$"
|
655
655
|
_ = one(m for m in caplog.messages if search(pattern, m))
|
656
656
|
|
@@ -658,7 +658,7 @@ class TestLooper:
|
|
658
658
|
looper = CountingLooper()
|
659
659
|
with Timer() as timer:
|
660
660
|
await looper.restart()
|
661
|
-
assert timer.timedelta <= self._restart_max_elapsed
|
661
|
+
assert timer.timedelta.py_timedelta() <= self._restart_max_elapsed
|
662
662
|
pattern = r": finished restarting$"
|
663
663
|
_ = one(m for m in caplog.messages if search(pattern, m))
|
664
664
|
|
@@ -911,12 +911,14 @@ class TestSleepDur:
|
|
911
911
|
async def test_main(self, *, duration: Duration) -> None:
|
912
912
|
with Timer() as timer:
|
913
913
|
await sleep_dur(duration=duration)
|
914
|
-
assert timer <= datetime_duration_to_timedelta(
|
914
|
+
assert timer.timedelta.py_timedelta() <= datetime_duration_to_timedelta(
|
915
|
+
2 * duration
|
916
|
+
)
|
915
917
|
|
916
918
|
async def test_none(self) -> None:
|
917
919
|
with Timer() as timer:
|
918
920
|
await sleep_dur()
|
919
|
-
assert timer <= 0.01
|
921
|
+
assert timer.timedelta.in_seconds() <= 0.01
|
920
922
|
|
921
923
|
|
922
924
|
class TestSleepMaxDur:
|
@@ -925,12 +927,14 @@ class TestSleepMaxDur:
|
|
925
927
|
async def test_main(self, *, duration: Duration) -> None:
|
926
928
|
with Timer() as timer:
|
927
929
|
await sleep_max_dur(duration=duration)
|
928
|
-
assert timer <= datetime_duration_to_timedelta(
|
930
|
+
assert timer.timedelta.py_timedelta() <= datetime_duration_to_timedelta(
|
931
|
+
2 * duration
|
932
|
+
)
|
929
933
|
|
930
934
|
async def test_none(self) -> None:
|
931
935
|
with Timer() as timer:
|
932
936
|
await sleep_max_dur()
|
933
|
-
assert timer <= 0.01
|
937
|
+
assert timer.timedelta.in_seconds() <= 0.01
|
934
938
|
|
935
939
|
|
936
940
|
class TestSleepUntil:
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
import re
|
3
4
|
from re import DOTALL
|
4
5
|
from typing import TYPE_CHECKING
|
5
6
|
|
@@ -13,6 +14,7 @@ from utilities.re import (
|
|
13
14
|
_ExtractGroupsMultipleMatchesError,
|
14
15
|
_ExtractGroupsNoCaptureGroupsError,
|
15
16
|
_ExtractGroupsNoMatchesError,
|
17
|
+
ensure_pattern,
|
16
18
|
extract_group,
|
17
19
|
extract_groups,
|
18
20
|
)
|
@@ -21,6 +23,16 @@ if TYPE_CHECKING:
|
|
21
23
|
from collections.abc import Sequence
|
22
24
|
|
23
25
|
|
26
|
+
class TestEnsurePattern:
|
27
|
+
def test_pattern(self) -> None:
|
28
|
+
pattern = re.compile(r"\d")
|
29
|
+
assert ensure_pattern(pattern) == pattern
|
30
|
+
|
31
|
+
def test_str(self) -> None:
|
32
|
+
pattern = r"\d"
|
33
|
+
assert ensure_pattern(pattern) == re.compile(pattern)
|
34
|
+
|
35
|
+
|
24
36
|
class TestExtractGroup:
|
25
37
|
def test_main(self) -> None:
|
26
38
|
assert extract_group(r"(\d)", "A0A") == "0"
|
@@ -1,15 +1,16 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
import datetime as dt
|
4
3
|
from operator import add, eq, ge, gt, le, lt, mul, ne, sub, truediv
|
5
4
|
from re import search
|
6
5
|
from time import sleep
|
7
6
|
from typing import TYPE_CHECKING, Any
|
8
7
|
|
9
8
|
from pytest import mark, param, raises
|
9
|
+
from whenever import TimeDelta
|
10
10
|
|
11
|
-
from utilities.
|
11
|
+
from utilities.asyncio import sleep_dur
|
12
12
|
from utilities.timer import Timer
|
13
|
+
from utilities.whenever2 import SECOND, ZERO_TIME
|
13
14
|
|
14
15
|
if TYPE_CHECKING:
|
15
16
|
from collections.abc import Callable
|
@@ -17,32 +18,27 @@ if TYPE_CHECKING:
|
|
17
18
|
|
18
19
|
class TestTimer:
|
19
20
|
@mark.parametrize(
|
20
|
-
("op", "other"
|
21
|
+
("op", "other"),
|
21
22
|
[
|
22
|
-
param(add,
|
23
|
-
param(
|
24
|
-
param(
|
25
|
-
param(
|
26
|
-
param(
|
27
|
-
param(
|
28
|
-
param(mul, 1, dt.timedelta),
|
29
|
-
param(mul, 1.0, dt.timedelta),
|
30
|
-
param(truediv, 1, dt.timedelta),
|
31
|
-
param(truediv, 1.0, dt.timedelta),
|
32
|
-
param(truediv, SECOND, float),
|
23
|
+
param(add, ZERO_TIME),
|
24
|
+
param(sub, ZERO_TIME),
|
25
|
+
param(mul, 1),
|
26
|
+
param(mul, 1.0),
|
27
|
+
param(truediv, 1),
|
28
|
+
param(truediv, 1.0),
|
33
29
|
],
|
34
30
|
ids=str,
|
35
31
|
)
|
36
32
|
def test_arithmetic_against_numbers_or_timedeltas(
|
37
|
-
self, *, op: Callable[[Any, Any], Any], other: Any
|
33
|
+
self, *, op: Callable[[Any, Any], Any], other: Any
|
38
34
|
) -> None:
|
39
35
|
with Timer() as timer:
|
40
36
|
pass
|
41
|
-
assert isinstance(op(timer, other),
|
37
|
+
assert isinstance(op(timer, other), TimeDelta)
|
42
38
|
|
43
39
|
@mark.parametrize(
|
44
40
|
("op", "cls"),
|
45
|
-
[param(add,
|
41
|
+
[param(add, TimeDelta), param(sub, TimeDelta), param(truediv, float)],
|
46
42
|
ids=str,
|
47
43
|
)
|
48
44
|
def test_arithmetic_against_another_timer(
|
@@ -83,15 +79,12 @@ class TestTimer:
|
|
83
79
|
],
|
84
80
|
ids=str,
|
85
81
|
)
|
86
|
-
@mark.parametrize(
|
87
|
-
"dur", [param(1), param(1.0), param(dt.timedelta(seconds=1))], ids=str
|
88
|
-
)
|
89
82
|
def test_comparison(
|
90
|
-
self, *, op: Callable[[Any, Any], bool],
|
83
|
+
self, *, op: Callable[[Any, Any], bool], expected: bool
|
91
84
|
) -> None:
|
92
85
|
with Timer() as timer:
|
93
86
|
pass
|
94
|
-
assert op(timer,
|
87
|
+
assert op(timer, SECOND) is expected
|
95
88
|
|
96
89
|
@mark.parametrize(
|
97
90
|
"op",
|
@@ -120,28 +113,27 @@ class TestTimer:
|
|
120
113
|
with raises(TypeError):
|
121
114
|
_ = op(timer, "")
|
122
115
|
|
123
|
-
def test_context_manager(self) -> None:
|
124
|
-
|
116
|
+
async def test_context_manager(self) -> None:
|
117
|
+
delta = 0.01 * SECOND
|
125
118
|
with Timer() as timer:
|
126
|
-
|
127
|
-
|
128
|
-
assert timer >= duration
|
119
|
+
await sleep_dur(duration=2 * delta)
|
120
|
+
assert timer >= delta
|
129
121
|
|
130
122
|
@mark.parametrize("func", [param(repr), param(str)], ids=str)
|
131
123
|
def test_repr_and_str(self, *, func: Callable[[Timer], str]) -> None:
|
132
124
|
with Timer() as timer:
|
133
125
|
sleep(0.01)
|
134
126
|
as_str = func(timer)
|
135
|
-
assert search(r"
|
127
|
+
assert search(r"^PT0\.\d+S$", as_str)
|
136
128
|
|
137
|
-
def test_running(self) -> None:
|
138
|
-
|
129
|
+
async def test_running(self) -> None:
|
130
|
+
delta = 0.01 * SECOND
|
139
131
|
timer = Timer()
|
140
|
-
|
141
|
-
assert timer >=
|
142
|
-
|
143
|
-
assert timer >= 2 *
|
132
|
+
await sleep_dur(duration=2 * delta)
|
133
|
+
assert timer >= delta
|
134
|
+
await sleep_dur(duration=2 * delta)
|
135
|
+
assert timer >= 2 * delta
|
144
136
|
|
145
137
|
def test_timedelta(self) -> None:
|
146
138
|
timer = Timer()
|
147
|
-
assert isinstance(timer.timedelta,
|
139
|
+
assert isinstance(timer.timedelta, TimeDelta)
|
@@ -43,6 +43,7 @@ from typing import (
|
|
43
43
|
)
|
44
44
|
|
45
45
|
from typing_extensions import deprecated
|
46
|
+
from whenever import TimeDelta
|
46
47
|
|
47
48
|
from utilities.dataclasses import replace_non_sentinel
|
48
49
|
from utilities.datetime import (
|
@@ -961,11 +962,14 @@ def put_items_nowait(items: Iterable[_T], queue: Queue[_T], /) -> None:
|
|
961
962
|
##
|
962
963
|
|
963
964
|
|
964
|
-
async def sleep_dur(*, duration: Duration | None = None) -> None:
|
965
|
+
async def sleep_dur(*, duration: Duration | TimeDelta | None = None) -> None:
|
965
966
|
"""Sleep which accepts durations."""
|
966
967
|
if duration is None:
|
967
968
|
return
|
968
|
-
|
969
|
+
if isinstance(duration, TimeDelta):
|
970
|
+
await sleep(duration.in_seconds())
|
971
|
+
else:
|
972
|
+
await sleep(datetime_duration_to_float(duration))
|
969
973
|
|
970
974
|
|
971
975
|
##
|
@@ -2,37 +2,59 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import re
|
4
4
|
from dataclasses import dataclass
|
5
|
-
from
|
5
|
+
from re import Pattern
|
6
|
+
from typing import TYPE_CHECKING, assert_never, override
|
6
7
|
|
7
8
|
from utilities.iterables import OneEmptyError, OneNonUniqueError, one
|
8
9
|
|
10
|
+
if TYPE_CHECKING:
|
11
|
+
from utilities.types import PatternLike
|
9
12
|
|
10
|
-
|
13
|
+
|
14
|
+
def ensure_pattern(pattern: PatternLike, /, *, flags: int = 0) -> Pattern[str]:
|
15
|
+
"""Ensure a pattern is returned."""
|
16
|
+
match pattern:
|
17
|
+
case Pattern():
|
18
|
+
return pattern
|
19
|
+
case str():
|
20
|
+
return re.compile(pattern, flags=flags)
|
21
|
+
case _ as never:
|
22
|
+
assert_never(never)
|
23
|
+
|
24
|
+
|
25
|
+
##
|
26
|
+
|
27
|
+
|
28
|
+
def extract_group(pattern: PatternLike, text: str, /, *, flags: int = 0) -> str:
|
11
29
|
"""Extract a group.
|
12
30
|
|
13
31
|
The regex must have 1 capture group, and this must match exactly once.
|
14
32
|
"""
|
15
|
-
|
16
|
-
match
|
33
|
+
pattern_use = ensure_pattern(pattern, flags=flags)
|
34
|
+
match pattern_use.groups:
|
17
35
|
case 0:
|
18
|
-
raise _ExtractGroupNoCaptureGroupsError(pattern=
|
36
|
+
raise _ExtractGroupNoCaptureGroupsError(pattern=pattern_use, text=text)
|
19
37
|
case 1:
|
20
|
-
matches: list[str] =
|
38
|
+
matches: list[str] = pattern_use.findall(text)
|
21
39
|
try:
|
22
40
|
return one(matches)
|
23
41
|
except OneEmptyError:
|
24
|
-
raise _ExtractGroupNoMatchesError(
|
42
|
+
raise _ExtractGroupNoMatchesError(
|
43
|
+
pattern=pattern_use, text=text
|
44
|
+
) from None
|
25
45
|
except OneNonUniqueError:
|
26
46
|
raise _ExtractGroupMultipleMatchesError(
|
27
|
-
pattern=
|
47
|
+
pattern=pattern_use, text=text, matches=matches
|
28
48
|
) from None
|
29
49
|
case _:
|
30
|
-
raise _ExtractGroupMultipleCaptureGroupsError(
|
50
|
+
raise _ExtractGroupMultipleCaptureGroupsError(
|
51
|
+
pattern=pattern_use, text=text
|
52
|
+
)
|
31
53
|
|
32
54
|
|
33
55
|
@dataclass(kw_only=True, slots=True)
|
34
56
|
class ExtractGroupError(Exception):
|
35
|
-
pattern: str
|
57
|
+
pattern: Pattern[str]
|
36
58
|
text: str
|
37
59
|
|
38
60
|
|
@@ -68,32 +90,35 @@ class _ExtractGroupNoMatchesError(ExtractGroupError):
|
|
68
90
|
return f"Pattern {self.pattern} must match against {self.text}"
|
69
91
|
|
70
92
|
|
71
|
-
|
93
|
+
##
|
94
|
+
|
95
|
+
|
96
|
+
def extract_groups(pattern: PatternLike, text: str, /, *, flags: int = 0) -> list[str]:
|
72
97
|
"""Extract multiple groups.
|
73
98
|
|
74
99
|
The regex may have any number of capture groups, and they must collectively
|
75
100
|
match exactly once.
|
76
101
|
"""
|
77
|
-
|
78
|
-
if (n_groups :=
|
79
|
-
raise _ExtractGroupsNoCaptureGroupsError(pattern=
|
80
|
-
matches: list[str] =
|
102
|
+
pattern_use = ensure_pattern(pattern, flags=flags)
|
103
|
+
if (n_groups := pattern_use.groups) == 0:
|
104
|
+
raise _ExtractGroupsNoCaptureGroupsError(pattern=pattern_use, text=text)
|
105
|
+
matches: list[str] = pattern_use.findall(text)
|
81
106
|
match len(matches), n_groups:
|
82
107
|
case 0, _:
|
83
|
-
raise _ExtractGroupsNoMatchesError(pattern=
|
108
|
+
raise _ExtractGroupsNoMatchesError(pattern=pattern_use, text=text)
|
84
109
|
case 1, 1:
|
85
110
|
return matches
|
86
111
|
case 1, _:
|
87
112
|
return list(one(matches))
|
88
113
|
case _:
|
89
114
|
raise _ExtractGroupsMultipleMatchesError(
|
90
|
-
pattern=
|
115
|
+
pattern=pattern_use, text=text, matches=matches
|
91
116
|
)
|
92
117
|
|
93
118
|
|
94
119
|
@dataclass(kw_only=True, slots=True)
|
95
120
|
class ExtractGroupsError(Exception):
|
96
|
-
pattern: str
|
121
|
+
pattern: Pattern[str]
|
97
122
|
text: str
|
98
123
|
|
99
124
|
|
@@ -108,7 +133,7 @@ class _ExtractGroupsMultipleMatchesError(ExtractGroupsError):
|
|
108
133
|
|
109
134
|
@dataclass(kw_only=True, slots=True)
|
110
135
|
class _ExtractGroupsNoCaptureGroupsError(ExtractGroupsError):
|
111
|
-
pattern: str
|
136
|
+
pattern: Pattern[str]
|
112
137
|
text: str
|
113
138
|
|
114
139
|
@override
|
@@ -123,4 +148,10 @@ class _ExtractGroupsNoMatchesError(ExtractGroupsError):
|
|
123
148
|
return f"Pattern {self.pattern} must match against {self.text}"
|
124
149
|
|
125
150
|
|
126
|
-
__all__ = [
|
151
|
+
__all__ = [
|
152
|
+
"ExtractGroupError",
|
153
|
+
"ExtractGroupsError",
|
154
|
+
"ensure_pattern",
|
155
|
+
"extract_group",
|
156
|
+
"extract_groups",
|
157
|
+
]
|
@@ -0,0 +1,97 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from operator import add, eq, ge, gt, le, lt, mul, ne, sub, truediv
|
4
|
+
from typing import TYPE_CHECKING, Any, Self, override
|
5
|
+
|
6
|
+
from utilities.whenever2 import get_now_local
|
7
|
+
|
8
|
+
if TYPE_CHECKING:
|
9
|
+
from collections.abc import Callable
|
10
|
+
|
11
|
+
from whenever import TimeDelta, ZonedDateTime
|
12
|
+
|
13
|
+
|
14
|
+
class Timer:
|
15
|
+
"""Context manager for timing blocks of code."""
|
16
|
+
|
17
|
+
def __init__(self) -> None:
|
18
|
+
super().__init__()
|
19
|
+
self._start: ZonedDateTime = get_now_local()
|
20
|
+
self._end: ZonedDateTime | None = None
|
21
|
+
|
22
|
+
# arithmetic
|
23
|
+
|
24
|
+
def __add__(self, other: Any) -> TimeDelta:
|
25
|
+
return self._apply_op(add, other)
|
26
|
+
|
27
|
+
def __float__(self) -> float:
|
28
|
+
return self.timedelta.in_seconds()
|
29
|
+
|
30
|
+
def __sub__(self, other: Any) -> TimeDelta:
|
31
|
+
return self._apply_op(sub, other)
|
32
|
+
|
33
|
+
def __mul__(self, other: Any) -> TimeDelta:
|
34
|
+
return self._apply_op(mul, other)
|
35
|
+
|
36
|
+
def __truediv__(self, other: Any) -> TimeDelta:
|
37
|
+
return self._apply_op(truediv, other)
|
38
|
+
|
39
|
+
# context manager
|
40
|
+
|
41
|
+
def __enter__(self) -> Self:
|
42
|
+
self._start = get_now_local()
|
43
|
+
return self
|
44
|
+
|
45
|
+
def __exit__(self, *_: object) -> bool:
|
46
|
+
self._end = get_now_local()
|
47
|
+
return False
|
48
|
+
|
49
|
+
# repr
|
50
|
+
|
51
|
+
@override
|
52
|
+
def __repr__(self) -> str:
|
53
|
+
return self.timedelta.format_common_iso()
|
54
|
+
|
55
|
+
@override
|
56
|
+
def __str__(self) -> str:
|
57
|
+
return self.timedelta.format_common_iso()
|
58
|
+
|
59
|
+
# comparison
|
60
|
+
|
61
|
+
@override
|
62
|
+
def __eq__(self, other: object) -> bool:
|
63
|
+
return self._apply_op(eq, other)
|
64
|
+
|
65
|
+
def __ge__(self, other: Any) -> bool:
|
66
|
+
return self._apply_op(ge, other)
|
67
|
+
|
68
|
+
def __gt__(self, other: Any) -> bool:
|
69
|
+
return self._apply_op(gt, other)
|
70
|
+
|
71
|
+
def __le__(self, other: Any) -> bool:
|
72
|
+
return self._apply_op(le, other)
|
73
|
+
|
74
|
+
def __lt__(self, other: Any) -> bool:
|
75
|
+
return self._apply_op(lt, other)
|
76
|
+
|
77
|
+
@override
|
78
|
+
def __ne__(self, other: object) -> bool:
|
79
|
+
return self._apply_op(ne, other)
|
80
|
+
|
81
|
+
# properties
|
82
|
+
|
83
|
+
@property
|
84
|
+
def timedelta(self) -> TimeDelta:
|
85
|
+
"""The elapsed time, as a `timedelta` object."""
|
86
|
+
end_use = get_now_local() if (end := self._end) is None else end
|
87
|
+
return end_use - self._start
|
88
|
+
|
89
|
+
# private
|
90
|
+
|
91
|
+
def _apply_op(self, op: Callable[[Any, Any], Any], other: Any, /) -> Any:
|
92
|
+
if isinstance(other, Timer):
|
93
|
+
return op(self.timedelta, other.timedelta)
|
94
|
+
return op(self.timedelta, other)
|
95
|
+
|
96
|
+
|
97
|
+
__all__ = ["Timer"]
|
@@ -7,6 +7,7 @@ from enum import Enum
|
|
7
7
|
from logging import Logger
|
8
8
|
from pathlib import Path
|
9
9
|
from random import Random
|
10
|
+
from re import Pattern
|
10
11
|
from types import TracebackType
|
11
12
|
from typing import (
|
12
13
|
Any,
|
@@ -249,6 +250,10 @@ type PathLike = MaybeStr[Path]
|
|
249
250
|
type Seed = int | float | str | bytes | bytearray | Random
|
250
251
|
|
251
252
|
|
253
|
+
# re
|
254
|
+
type PatternLike = MaybeStr[Pattern[str]]
|
255
|
+
|
256
|
+
|
252
257
|
# traceback
|
253
258
|
type ExcInfo = tuple[type[BaseException], BaseException, TracebackType]
|
254
259
|
type OptExcInfo = ExcInfo | tuple[None, None, None]
|
@@ -294,6 +299,7 @@ __all__ = [
|
|
294
299
|
"Parallelism",
|
295
300
|
"ParseObjectExtra",
|
296
301
|
"PathLike",
|
302
|
+
"PatternLike",
|
297
303
|
"RoundMode",
|
298
304
|
"Seed",
|
299
305
|
"SerializeObjectExtra",
|