dycw-utilities 0.113.1__tar.gz → 0.113.3__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.113.1 → dycw_utilities-0.113.3}/PKG-INFO +4 -4
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/pyproject.toml +7 -7
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_asyncio.py +38 -3
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_datetime.py +82 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/__init__.py +1 -1
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/asyncio.py +42 -2
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/datetime.py +98 -1
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/types.py +3 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/.gitignore +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/LICENSE +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/README.md +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/__init__.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/conftest.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/__init__.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_missing/__init__.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_missing/module.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_with/__init__.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_with/outer_1.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_with/outer_2.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_without/__init__.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_without/module_1.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_without/module_2.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/standalone.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/with_imports.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/scripts/__init__.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/scripts/test_async_service/__init__.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/scripts/test_async_service/__main__.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/scripts/test_async_service/run.sh +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/scripts/test_queue_processor/__init__.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/scripts/test_queue_processor/__main__.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/scripts/test_queue_processor/run.sh +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_altair.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_astor.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_atomicwrites.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_atools.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_cachetools.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_click.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_concurrent.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_contextlib.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_contextvars.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_cryptography.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_cvxpy.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_dataclasses.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_enum.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_errors.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_eventkit.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_fastapi.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_fpdf2.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_functions.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_functools.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_getpass.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_git.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_hashlib.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_http.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_hypothesis.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_ipython.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_iterables.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_jupyter.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_lightweight_charts.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_logging.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_loguru.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_luigi.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_math.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_memory_profiler.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_modules.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_more_itertools.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_numpy.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_operator.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_optuna.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_orjson.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_os.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_parse.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_pathlib.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_period.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_pickle.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_platform.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_polars.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_polars_ols.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_pqdm.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_pydantic.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_pyinstrument.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_pyrsistent.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_pytest.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_pytest_regressions.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_python_dotenv.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_random.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_re.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_redis.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_reprlib.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_rich.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_scipy.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_sentinel.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_shelve.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_slack_sdk.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_socket.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_sqlalchemy.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_statsmodel.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_streamlit.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_sys.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_tempfile.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_tenacity.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_text.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_threading.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_timer.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_traceback.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_traceback_funcs/__init__.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_traceback_funcs/chain.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_traceback_funcs/error_bind.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_traceback_funcs/many.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_traceback_funcs/one.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_traceback_funcs/recursive.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_traceback_funcs/two.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_traceback_funcs/untraced.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_types.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_typing.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_typing_funcs/__init__.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_typing_funcs/no_future.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_typing_funcs/with_future.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_tzdata.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_tzlocal.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_uuid.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_version.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_warnings.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_whenever.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_zipfile.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/test_zoneinfo.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/altair.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/astor.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/atomicwrites.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/atools.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/cachetools.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/click.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/concurrent.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/contextlib.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/contextvars.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/cryptography.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/cvxpy.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/dataclasses.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/enum.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/errors.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/eventkit.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/fastapi.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/fpdf2.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/functions.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/functools.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/getpass.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/git.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/hashlib.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/http.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/hypothesis.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/ipython.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/iterables.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/jupyter.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/lightweight_charts.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/logging.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/loguru.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/luigi.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/math.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/memory_profiler.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/modules.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/more_itertools.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/numpy.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/operator.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/optuna.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/orjson.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/os.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/parse.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/pathlib.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/period.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/pickle.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/platform.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/polars.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/polars_ols.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/pqdm.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/py.typed +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/pydantic.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/pyinstrument.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/pyrsistent.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/pytest.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/pytest_regressions.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/python_dotenv.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/random.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/re.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/redis.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/reprlib.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/rich.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/scipy.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/sentinel.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/shelve.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/slack_sdk.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/socket.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/sqlalchemy.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/statsmodels.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/streamlit.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/sys.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/tempfile.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/tenacity.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/text.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/threading.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/timer.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/traceback.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/typing.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/tzdata.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/tzlocal.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/uuid.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/version.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/warnings.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/whenever.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/zipfile.py +0 -0
- {dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/utilities/zoneinfo.py +0 -0
@@ -1,12 +1,12 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: dycw-utilities
|
3
|
-
Version: 0.113.
|
3
|
+
Version: 0.113.3
|
4
4
|
Author-email: Derek Wan <d.wan@icloud.com>
|
5
5
|
License-File: LICENSE
|
6
6
|
Requires-Python: >=3.12
|
7
7
|
Requires-Dist: typing-extensions<4.14,>=4.13.1
|
8
8
|
Provides-Extra: test
|
9
|
-
Requires-Dist: hypothesis<6.132,>=6.131.
|
9
|
+
Requires-Dist: hypothesis<6.132,>=6.131.14; extra == 'test'
|
10
10
|
Requires-Dist: pytest-asyncio<0.27,>=0.26.0; extra == 'test'
|
11
11
|
Requires-Dist: pytest-cov<6.2,>=6.1.1; extra == 'test'
|
12
12
|
Requires-Dist: pytest-instafail<0.6,>=0.5.0; extra == 'test'
|
@@ -16,7 +16,7 @@ Requires-Dist: pytest-randomly<3.17,>=3.16.0; extra == 'test'
|
|
16
16
|
Requires-Dist: pytest-regressions<2.8,>=2.7.0; extra == 'test'
|
17
17
|
Requires-Dist: pytest-rerunfailures<16,>=15.0; extra == 'test'
|
18
18
|
Requires-Dist: pytest-rng<1.1,>=1.0.0; extra == 'test'
|
19
|
-
Requires-Dist: pytest-timeout<2.
|
19
|
+
Requires-Dist: pytest-timeout<2.5,>=2.4.0; extra == 'test'
|
20
20
|
Requires-Dist: pytest-xdist<3.7,>=3.6.1; extra == 'test'
|
21
21
|
Requires-Dist: pytest<8.4,>=8.3.5; extra == 'test'
|
22
22
|
Requires-Dist: setuptools>=78.0.2; extra == 'test'
|
@@ -80,7 +80,7 @@ Provides-Extra: zzz-test-hypothesis
|
|
80
80
|
Requires-Dist: aiosqlite<0.22,>=0.21.0; extra == 'zzz-test-hypothesis'
|
81
81
|
Requires-Dist: asyncpg<0.31,>=0.30.0; extra == 'zzz-test-hypothesis'
|
82
82
|
Requires-Dist: greenlet<3.3,>=3.2.0; extra == 'zzz-test-hypothesis'
|
83
|
-
Requires-Dist: hypothesis<6.132,>=6.131.
|
83
|
+
Requires-Dist: hypothesis<6.132,>=6.131.14; extra == 'zzz-test-hypothesis'
|
84
84
|
Requires-Dist: luigi<3.7,>=3.6.0; extra == 'zzz-test-hypothesis'
|
85
85
|
Requires-Dist: numpy<2.3,>=2.2.5; extra == 'zzz-test-hypothesis'
|
86
86
|
Requires-Dist: pathvalidate<3.3,>=3.2.3; extra == 'zzz-test-hypothesis'
|
@@ -26,7 +26,7 @@ dev = [
|
|
26
26
|
"fpdf2 >= 2.8.3, < 2.9",
|
27
27
|
"greenlet >= 3.2.0, < 3.3", # for sqlalchemy async
|
28
28
|
"httpx >= 0.28.1, < 0.29", # for fastapi
|
29
|
-
"hypothesis >= 6.131.
|
29
|
+
"hypothesis >= 6.131.14, < 6.132",
|
30
30
|
"img2pdf >= 0.6.0, < 0.7",
|
31
31
|
"lightweight-charts >= 2.1, < 2.2",
|
32
32
|
"loguru >= 0.7.3, < 0.8",
|
@@ -76,7 +76,7 @@ dev = [
|
|
76
76
|
"pytest-randomly >= 3.16.0, < 3.17",
|
77
77
|
"pytest-rerunfailures >= 15.0, < 16",
|
78
78
|
"pytest-rng >= 1.0.0, < 1.1",
|
79
|
-
"pytest-timeout >= 2.
|
79
|
+
"pytest-timeout >= 2.4.0, < 2.5",
|
80
80
|
"pytest-xdist >= 3.6.1, < 3.7",
|
81
81
|
# CI
|
82
82
|
"win32_setctime >= 1.2.0, < 1.3", # https://github.com/Delgan/loguru/issues/147
|
@@ -92,11 +92,11 @@ dependencies = [
|
|
92
92
|
name = "dycw-utilities"
|
93
93
|
readme = "README.md"
|
94
94
|
requires-python = ">= 3.12"
|
95
|
-
version = "0.113.
|
95
|
+
version = "0.113.3"
|
96
96
|
|
97
97
|
[project.optional-dependencies]
|
98
98
|
test = [
|
99
|
-
"hypothesis >= 6.131.
|
99
|
+
"hypothesis >= 6.131.14, < 6.132",
|
100
100
|
"pytest >= 8.3.5, < 8.4",
|
101
101
|
"pytest-asyncio >= 0.26.0, < 0.27",
|
102
102
|
"pytest-cov >= 6.1.1, < 6.2",
|
@@ -107,7 +107,7 @@ test = [
|
|
107
107
|
"pytest-regressions >= 2.7.0, < 2.8",
|
108
108
|
"pytest-rerunfailures >= 15.0, < 16",
|
109
109
|
"pytest-rng >= 1.0.0, < 1.1",
|
110
|
-
"pytest-timeout >= 2.
|
110
|
+
"pytest-timeout >= 2.4.0, < 2.5",
|
111
111
|
"pytest-xdist >= 3.6.1, < 3.7",
|
112
112
|
"setuptools >= 78.0.2", # https://github.com/theY4Kman/pytest-only/issues/14
|
113
113
|
]
|
@@ -174,7 +174,7 @@ zzz-test-hypothesis = [
|
|
174
174
|
"aiosqlite >= 0.21.0, < 0.22",
|
175
175
|
"asyncpg >= 0.30.0, < 0.31", # for sqlalchemy async
|
176
176
|
"greenlet >= 3.2.0, < 3.3", # for sqlalchemy async
|
177
|
-
"hypothesis >= 6.131.
|
177
|
+
"hypothesis >= 6.131.14, < 6.132",
|
178
178
|
"luigi >= 3.6.0, < 3.7",
|
179
179
|
"numpy >= 2.2.5, < 2.3",
|
180
180
|
"pathvalidate >= 3.2.3, < 3.3",
|
@@ -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.113.
|
337
|
+
current_version = "0.113.3"
|
338
338
|
|
339
339
|
[[tool.bumpversion.files]]
|
340
340
|
filename = "src/utilities/__init__.py"
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
from asyncio import (
|
4
4
|
CancelledError,
|
5
|
+
Event,
|
5
6
|
Lock,
|
6
7
|
PriorityQueue,
|
7
8
|
Queue,
|
@@ -14,7 +15,7 @@ from collections import Counter
|
|
14
15
|
from dataclasses import dataclass, field
|
15
16
|
from itertools import chain
|
16
17
|
from re import search
|
17
|
-
from typing import TYPE_CHECKING, override
|
18
|
+
from typing import TYPE_CHECKING, Self, override
|
18
19
|
|
19
20
|
from hypothesis import Phase, given, settings
|
20
21
|
from hypothesis.strategies import (
|
@@ -37,20 +38,23 @@ from utilities.asyncio import (
|
|
37
38
|
QueueProcessor,
|
38
39
|
UniquePriorityQueue,
|
39
40
|
UniqueQueue,
|
41
|
+
get_event,
|
40
42
|
get_items,
|
41
43
|
get_items_nowait,
|
42
44
|
sleep_dur,
|
43
45
|
stream_command,
|
44
46
|
timeout_dur,
|
45
47
|
)
|
48
|
+
from utilities.dataclasses import replace_non_sentinel
|
46
49
|
from utilities.datetime import MILLISECOND, datetime_duration_to_timedelta
|
47
|
-
from utilities.hypothesis import text_ascii
|
50
|
+
from utilities.hypothesis import sentinels, text_ascii
|
48
51
|
from utilities.iterables import one, unique_everseen
|
49
52
|
from utilities.pytest import skipif_windows
|
53
|
+
from utilities.sentinel import Sentinel, sentinel
|
50
54
|
from utilities.timer import Timer
|
51
55
|
|
52
56
|
if TYPE_CHECKING:
|
53
|
-
from utilities.types import Duration
|
57
|
+
from utilities.types import Duration, MaybeCallableEvent
|
54
58
|
|
55
59
|
|
56
60
|
class TestAsyncLoopingService:
|
@@ -297,6 +301,37 @@ class TestExceptionProcessor:
|
|
297
301
|
await sleep(0.1)
|
298
302
|
|
299
303
|
|
304
|
+
class TestGetEvent:
|
305
|
+
def test_event(self) -> None:
|
306
|
+
event = Event()
|
307
|
+
assert get_event(event=event) is event
|
308
|
+
|
309
|
+
@given(event=none() | sentinels())
|
310
|
+
def test_none_or_sentinel(self, *, event: None | Sentinel) -> None:
|
311
|
+
assert get_event(event=event) is event
|
312
|
+
|
313
|
+
def test_replace_non_sentinel(self) -> None:
|
314
|
+
@dataclass(kw_only=True, slots=True)
|
315
|
+
class Example:
|
316
|
+
event: Event = field(default_factory=Event)
|
317
|
+
|
318
|
+
def replace(
|
319
|
+
self, *, event: MaybeCallableEvent | Sentinel = sentinel
|
320
|
+
) -> Self:
|
321
|
+
return replace_non_sentinel(self, event=get_event(event=event))
|
322
|
+
|
323
|
+
event1, event2, event3 = Event(), Event(), Event()
|
324
|
+
obj = Example(event=event1)
|
325
|
+
assert obj.event is event1
|
326
|
+
assert obj.replace().event is event1
|
327
|
+
assert obj.replace(event=event2).event is event2
|
328
|
+
assert obj.replace(event=lambda: event3).event is event3
|
329
|
+
|
330
|
+
def test_callable(self) -> None:
|
331
|
+
event = Event()
|
332
|
+
assert get_event(event=lambda: event) is event
|
333
|
+
|
334
|
+
|
300
335
|
class TestGetItems:
|
301
336
|
@given(
|
302
337
|
xs=lists(integers(), min_size=1),
|
@@ -50,6 +50,7 @@ from utilities.datetime import (
|
|
50
50
|
AreEqualDateTimesError,
|
51
51
|
CheckDateNotDateTimeError,
|
52
52
|
EnsureMonthError,
|
53
|
+
GetMinMaxDateError,
|
53
54
|
MeanDateTimeError,
|
54
55
|
MeanTimeDeltaError,
|
55
56
|
MillisecondsSinceEpochError,
|
@@ -67,6 +68,11 @@ from utilities.datetime import (
|
|
67
68
|
_DateDurationToIntTimeDeltaError,
|
68
69
|
_DateDurationToTimeDeltaFloatError,
|
69
70
|
_DateDurationToTimeDeltaTimeDeltaError,
|
71
|
+
_GetMinMaxDateMaxAgeError,
|
72
|
+
_GetMinMaxDateMaxDateError,
|
73
|
+
_GetMinMaxDateMinAgeError,
|
74
|
+
_GetMinMaxDateMinDateError,
|
75
|
+
_GetMinMaxDatePeriodError,
|
70
76
|
_ParseTwoDigitYearInvalidIntegerError,
|
71
77
|
_ParseTwoDigitYearInvalidStringError,
|
72
78
|
add_duration,
|
@@ -91,6 +97,7 @@ from utilities.datetime import (
|
|
91
97
|
get_date,
|
92
98
|
get_datetime,
|
93
99
|
get_half_years,
|
100
|
+
get_min_max_date,
|
94
101
|
get_months,
|
95
102
|
get_now,
|
96
103
|
get_quarters,
|
@@ -129,6 +136,7 @@ from utilities.datetime import (
|
|
129
136
|
from utilities.functions import not_func
|
130
137
|
from utilities.hypothesis import (
|
131
138
|
assume_does_not_raise,
|
139
|
+
date_durations,
|
132
140
|
int32s,
|
133
141
|
months,
|
134
142
|
pairs,
|
@@ -148,6 +156,7 @@ if TYPE_CHECKING:
|
|
148
156
|
from utilities.sentinel import Sentinel
|
149
157
|
from utilities.types import (
|
150
158
|
DateOrDateTime,
|
159
|
+
Duration,
|
151
160
|
MaybeCallableDate,
|
152
161
|
MaybeCallableDateTime,
|
153
162
|
Number,
|
@@ -675,6 +684,79 @@ class TestGetDateTime:
|
|
675
684
|
assert get_datetime(datetime=lambda: datetime) == datetime
|
676
685
|
|
677
686
|
|
687
|
+
class TestGetMinMaxDate:
|
688
|
+
@given(
|
689
|
+
min_date=dates(max_value=TODAY_UTC) | none(),
|
690
|
+
max_date=dates(max_value=TODAY_UTC) | none(),
|
691
|
+
min_age=date_durations(min_int=0, min_timedelta=ZERO_TIME) | none(),
|
692
|
+
max_age=date_durations(min_int=0, min_timedelta=ZERO_TIME) | none(),
|
693
|
+
)
|
694
|
+
def test_main(
|
695
|
+
self,
|
696
|
+
*,
|
697
|
+
min_date: dt.date | None,
|
698
|
+
max_date: dt.date | None,
|
699
|
+
min_age: Duration | None,
|
700
|
+
max_age: Duration | None,
|
701
|
+
) -> None:
|
702
|
+
with assume_does_not_raise(GetMinMaxDateError, OverflowError):
|
703
|
+
min_date_use, max_date_use = get_min_max_date(
|
704
|
+
min_date=min_date, max_date=max_date, min_age=min_age, max_age=max_age
|
705
|
+
)
|
706
|
+
if (min_date is None) and (max_age is None):
|
707
|
+
assert min_date_use is None
|
708
|
+
else:
|
709
|
+
assert min_date_use is not None
|
710
|
+
if (max_date is None) and (min_age is None):
|
711
|
+
assert max_date_use is None
|
712
|
+
else:
|
713
|
+
assert max_date_use is not None
|
714
|
+
if min_date_use is not None:
|
715
|
+
assert min_date_use <= get_today()
|
716
|
+
if max_date_use is not None:
|
717
|
+
assert max_date_use <= get_today()
|
718
|
+
if (min_date_use is not None) and (max_date_use is not None):
|
719
|
+
assert min_date_use <= max_date_use
|
720
|
+
|
721
|
+
@given(date=dates(min_value=TODAY_UTC + DAY))
|
722
|
+
def test_error_min_date(self, *, date: dt.date) -> None:
|
723
|
+
with raises(
|
724
|
+
_GetMinMaxDateMinDateError,
|
725
|
+
match="Min date must be at most today; got .* > .*",
|
726
|
+
):
|
727
|
+
_ = get_min_max_date(min_date=date)
|
728
|
+
|
729
|
+
@given(duration=date_durations(max_int=-1, max_timedelta=-DAY))
|
730
|
+
def test_error_min_age(self, *, duration: Duration) -> None:
|
731
|
+
with raises(
|
732
|
+
_GetMinMaxDateMinAgeError, match="Min age must be non-negative; got .*"
|
733
|
+
):
|
734
|
+
_ = get_min_max_date(min_age=duration)
|
735
|
+
|
736
|
+
@given(date=dates(min_value=TODAY_UTC + DAY))
|
737
|
+
def test_error_max_date(self, *, date: dt.date) -> None:
|
738
|
+
with raises(
|
739
|
+
_GetMinMaxDateMaxDateError,
|
740
|
+
match="Max date must be at most today; got .* > .*",
|
741
|
+
):
|
742
|
+
_ = get_min_max_date(max_date=date)
|
743
|
+
|
744
|
+
@given(duration=date_durations(max_int=-1, max_timedelta=-DAY))
|
745
|
+
def test_error_max_age(self, *, duration: Duration) -> None:
|
746
|
+
with raises(
|
747
|
+
_GetMinMaxDateMaxAgeError, match="Max age must be non-negative; got .*"
|
748
|
+
):
|
749
|
+
_ = get_min_max_date(max_age=duration)
|
750
|
+
|
751
|
+
@given(dates=pairs(dates(max_value=TODAY_UTC), unique=True, sorted=True))
|
752
|
+
def test_error_period(self, *, dates: tuple[dt.date, dt.date]) -> None:
|
753
|
+
with raises(
|
754
|
+
_GetMinMaxDatePeriodError,
|
755
|
+
match="Min date must be at most max date; got .* > .*",
|
756
|
+
):
|
757
|
+
_ = get_min_max_date(min_date=dates[1], max_date=dates[0])
|
758
|
+
|
759
|
+
|
678
760
|
class TestGetNow:
|
679
761
|
@given(time_zone=timezones())
|
680
762
|
def test_function(self, *, time_zone: ZoneInfo) -> None:
|
@@ -17,6 +17,7 @@ from asyncio import (
|
|
17
17
|
sleep,
|
18
18
|
timeout,
|
19
19
|
)
|
20
|
+
from collections.abc import Callable
|
20
21
|
from contextlib import (
|
21
22
|
AsyncExitStack,
|
22
23
|
_AsyncGeneratorContextManager,
|
@@ -27,12 +28,22 @@ from dataclasses import dataclass, field
|
|
27
28
|
from io import StringIO
|
28
29
|
from subprocess import PIPE
|
29
30
|
from sys import stderr, stdout
|
30
|
-
from typing import
|
31
|
+
from typing import (
|
32
|
+
TYPE_CHECKING,
|
33
|
+
Generic,
|
34
|
+
Self,
|
35
|
+
TextIO,
|
36
|
+
TypeVar,
|
37
|
+
assert_never,
|
38
|
+
overload,
|
39
|
+
override,
|
40
|
+
)
|
31
41
|
|
32
42
|
from utilities.datetime import MILLISECOND, datetime_duration_to_float
|
33
43
|
from utilities.errors import ImpossibleCaseError
|
34
44
|
from utilities.functions import ensure_int, ensure_not_none
|
35
|
-
from utilities.
|
45
|
+
from utilities.sentinel import Sentinel, sentinel
|
46
|
+
from utilities.types import MaybeCallableEvent, THashable, TSupportsRichComparison
|
36
47
|
|
37
48
|
if TYPE_CHECKING:
|
38
49
|
from asyncio import _CoroutineLike
|
@@ -356,6 +367,34 @@ class UniqueQueue(Queue[THashable]):
|
|
356
367
|
##
|
357
368
|
|
358
369
|
|
370
|
+
@overload
|
371
|
+
def get_event(*, event: MaybeCallableEvent) -> Event: ...
|
372
|
+
@overload
|
373
|
+
def get_event(*, event: None) -> None: ...
|
374
|
+
@overload
|
375
|
+
def get_event(*, event: Sentinel) -> Sentinel: ...
|
376
|
+
@overload
|
377
|
+
def get_event(*, event: MaybeCallableEvent | Sentinel) -> Event | Sentinel: ...
|
378
|
+
@overload
|
379
|
+
def get_event(
|
380
|
+
*, event: MaybeCallableEvent | None | Sentinel = sentinel
|
381
|
+
) -> Event | None | Sentinel: ...
|
382
|
+
def get_event(
|
383
|
+
*, event: MaybeCallableEvent | None | Sentinel = sentinel
|
384
|
+
) -> Event | None | Sentinel:
|
385
|
+
"""Get the event."""
|
386
|
+
match event:
|
387
|
+
case Event() | None | Sentinel():
|
388
|
+
return event
|
389
|
+
case Callable() as func:
|
390
|
+
return get_event(event=func())
|
391
|
+
case _ as never:
|
392
|
+
assert_never(never)
|
393
|
+
|
394
|
+
|
395
|
+
##
|
396
|
+
|
397
|
+
|
359
398
|
async def get_items(
|
360
399
|
queue: Queue[_T], /, *, max_size: int | None = None, lock: Lock | None = None
|
361
400
|
) -> list[_T]:
|
@@ -490,6 +529,7 @@ __all__ = [
|
|
490
529
|
"StreamCommandOutput",
|
491
530
|
"UniquePriorityQueue",
|
492
531
|
"UniqueQueue",
|
532
|
+
"get_event",
|
493
533
|
"get_items",
|
494
534
|
"get_items_nowait",
|
495
535
|
"sleep_dur",
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import datetime as dt
|
4
|
-
from collections.abc import Callable, Iterable
|
4
|
+
from collections.abc import Callable, Iterable, Sequence
|
5
5
|
from dataclasses import dataclass, replace
|
6
6
|
from re import search, sub
|
7
7
|
from statistics import fmean
|
@@ -495,6 +495,101 @@ def get_half_years(*, n: int = 1) -> dt.timedelta:
|
|
495
495
|
|
496
496
|
HALF_YEAR = get_half_years(n=1)
|
497
497
|
|
498
|
+
##
|
499
|
+
|
500
|
+
|
501
|
+
def get_min_max_date(
|
502
|
+
*,
|
503
|
+
min_date: dt.date | None = None,
|
504
|
+
max_date: dt.date | None = None,
|
505
|
+
min_age: Duration | None = None,
|
506
|
+
max_age: Duration | None = None,
|
507
|
+
time_zone: TimeZoneLike = UTC,
|
508
|
+
) -> tuple[dt.date | None, dt.date | None]:
|
509
|
+
"""Get the min/max date given a combination of dates/ages."""
|
510
|
+
today = get_today(time_zone=time_zone)
|
511
|
+
min_parts: Sequence[dt.date] = []
|
512
|
+
if min_date is not None:
|
513
|
+
if min_date > today:
|
514
|
+
raise _GetMinMaxDateMinDateError(min_date=min_date, today=today)
|
515
|
+
min_parts.append(min_date)
|
516
|
+
if max_age is not None:
|
517
|
+
if date_duration_to_timedelta(max_age) < ZERO_TIME:
|
518
|
+
raise _GetMinMaxDateMaxAgeError(max_age=max_age)
|
519
|
+
min_parts.append(sub_duration(today, duration=max_age))
|
520
|
+
min_date_use = max(min_parts, default=None)
|
521
|
+
max_parts: Sequence[dt.date] = []
|
522
|
+
if max_date is not None:
|
523
|
+
if max_date > today:
|
524
|
+
raise _GetMinMaxDateMaxDateError(max_date=max_date, today=today)
|
525
|
+
max_parts.append(max_date)
|
526
|
+
if min_age is not None:
|
527
|
+
if date_duration_to_timedelta(min_age) < ZERO_TIME:
|
528
|
+
raise _GetMinMaxDateMinAgeError(min_age=min_age)
|
529
|
+
max_parts.append(sub_duration(today, duration=min_age))
|
530
|
+
max_date_use = min(max_parts, default=None)
|
531
|
+
if (
|
532
|
+
(min_date_use is not None)
|
533
|
+
and (max_date_use is not None)
|
534
|
+
and (min_date_use > max_date_use)
|
535
|
+
):
|
536
|
+
raise _GetMinMaxDatePeriodError(min_date=min_date_use, max_date=max_date_use)
|
537
|
+
return min_date_use, max_date_use
|
538
|
+
|
539
|
+
|
540
|
+
@dataclass(kw_only=True, slots=True)
|
541
|
+
class GetMinMaxDateError(Exception): ...
|
542
|
+
|
543
|
+
|
544
|
+
@dataclass(kw_only=True, slots=True)
|
545
|
+
class _GetMinMaxDateMinDateError(GetMinMaxDateError):
|
546
|
+
min_date: dt.date
|
547
|
+
today: dt.date
|
548
|
+
|
549
|
+
@override
|
550
|
+
def __str__(self) -> str:
|
551
|
+
return f"Min date must be at most today; got {self.min_date} > {self.today}"
|
552
|
+
|
553
|
+
|
554
|
+
@dataclass(kw_only=True, slots=True)
|
555
|
+
class _GetMinMaxDateMinAgeError(GetMinMaxDateError):
|
556
|
+
min_age: Duration
|
557
|
+
|
558
|
+
@override
|
559
|
+
def __str__(self) -> str:
|
560
|
+
return f"Min age must be non-negative; got {self.min_age}"
|
561
|
+
|
562
|
+
|
563
|
+
@dataclass(kw_only=True, slots=True)
|
564
|
+
class _GetMinMaxDateMaxDateError(GetMinMaxDateError):
|
565
|
+
max_date: dt.date
|
566
|
+
today: dt.date
|
567
|
+
|
568
|
+
@override
|
569
|
+
def __str__(self) -> str:
|
570
|
+
return f"Max date must be at most today; got {self.max_date} > {self.today}"
|
571
|
+
|
572
|
+
|
573
|
+
@dataclass(kw_only=True, slots=True)
|
574
|
+
class _GetMinMaxDateMaxAgeError(GetMinMaxDateError):
|
575
|
+
max_age: Duration
|
576
|
+
|
577
|
+
@override
|
578
|
+
def __str__(self) -> str:
|
579
|
+
return f"Max age must be non-negative; got {self.max_age}"
|
580
|
+
|
581
|
+
|
582
|
+
@dataclass(kw_only=True, slots=True)
|
583
|
+
class _GetMinMaxDatePeriodError(GetMinMaxDateError):
|
584
|
+
min_date: dt.date
|
585
|
+
max_date: dt.date
|
586
|
+
|
587
|
+
@override
|
588
|
+
def __str__(self) -> str:
|
589
|
+
return (
|
590
|
+
f"Min date must be at most max date; got {self.min_date} > {self.max_date}"
|
591
|
+
)
|
592
|
+
|
498
593
|
|
499
594
|
##
|
500
595
|
|
@@ -1244,6 +1339,7 @@ __all__ = [
|
|
1244
1339
|
"CheckDateNotDateTimeError",
|
1245
1340
|
"DateOrMonth",
|
1246
1341
|
"EnsureMonthError",
|
1342
|
+
"GetMinMaxDateError",
|
1247
1343
|
"MeanDateTimeError",
|
1248
1344
|
"MeanTimeDeltaError",
|
1249
1345
|
"MillisecondsSinceEpochError",
|
@@ -1280,6 +1376,7 @@ __all__ = [
|
|
1280
1376
|
"get_date",
|
1281
1377
|
"get_datetime",
|
1282
1378
|
"get_half_years",
|
1379
|
+
"get_min_max_date",
|
1283
1380
|
"get_months",
|
1284
1381
|
"get_now",
|
1285
1382
|
"get_quarters",
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import datetime as dt
|
4
|
+
from asyncio import Event
|
4
5
|
from collections.abc import Awaitable, Callable, Coroutine, Hashable, Iterable, Mapping
|
5
6
|
from enum import Enum
|
6
7
|
from logging import Logger
|
@@ -57,6 +58,7 @@ type TupleOrStrMapping = tuple[Any, ...] | StrMapping
|
|
57
58
|
# asyncio
|
58
59
|
type Coroutine1[_T] = Coroutine[Any, Any, _T]
|
59
60
|
type MaybeAwaitable[_T] = _T | Awaitable[_T]
|
61
|
+
type MaybeCallableEvent = MaybeCallable[Event]
|
60
62
|
type MaybeCoroutine1[_T] = _T | Coroutine1[_T]
|
61
63
|
|
62
64
|
|
@@ -277,6 +279,7 @@ __all__ = [
|
|
277
279
|
"MaybeCallable",
|
278
280
|
"MaybeCallableDate",
|
279
281
|
"MaybeCallableDateTime",
|
282
|
+
"MaybeCallableEvent",
|
280
283
|
"MaybeCoroutine1",
|
281
284
|
"MaybeIterable",
|
282
285
|
"MaybeIterableHashable",
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_missing/__init__.py
RENAMED
File without changes
|
{dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_missing/module.py
RENAMED
File without changes
|
{dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_with/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_without/__init__.py
RENAMED
File without changes
|
{dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_without/module_1.py
RENAMED
File without changes
|
{dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/modules/package_without/module_2.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/scripts/test_async_service/__init__.py
RENAMED
File without changes
|
{dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/scripts/test_async_service/__main__.py
RENAMED
File without changes
|
{dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/scripts/test_async_service/run.sh
RENAMED
File without changes
|
{dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/scripts/test_queue_processor/__init__.py
RENAMED
File without changes
|
{dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/scripts/test_queue_processor/__main__.py
RENAMED
File without changes
|
{dycw_utilities-0.113.1 → dycw_utilities-0.113.3}/src/tests/scripts/test_queue_processor/run.sh
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|