dycw-utilities 0.162.11__tar.gz → 0.163.0__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.162.11 → dycw_utilities-0.163.0}/PKG-INFO +1 -1
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/pyproject.toml +7 -5
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/conftest.py +7 -3
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_contextlib.py +1 -1
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_hypothesis.py +2 -2
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_logging.py +41 -71
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_pyinstrument.py +1 -1
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_sqlalchemy.py +2 -2
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_traceback.py +5 -3
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_whenever.py +52 -23
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/__init__.py +1 -1
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/fpdf2.py +2 -2
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/hypothesis.py +7 -2
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/logging.py +9 -9
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/pyinstrument.py +4 -2
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/traceback.py +4 -4
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/whenever.py +28 -25
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/.gitignore +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/LICENSE +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/README.md +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/__init__.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/modules/__init__.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/modules/package_missing/__init__.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/modules/package_missing/module.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/modules/package_with/__init__.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/modules/package_with/outer_1.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/modules/package_with/outer_2.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/modules/package_without/__init__.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/modules/package_without/module_1.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/modules/package_without/module_2.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/modules/standalone.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/modules/with_imports.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_aeventkit.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_altair.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_asyncio.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_atomicwrites.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_atools.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_cachetools.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_click.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_concurrent.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_contextvars.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_cryptography.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_cvxpy.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_dataclasses.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_enum.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_errors.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_fastapi.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_fpdf2.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_functions.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_functools.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_getpass.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_gzip.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_hashlib.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_http.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_importlib.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_inflect.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_ipython.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_iterables.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_json.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_jupyter.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_libcst.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_lightweight_charts.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_math.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_memory_profiler.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_modules.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_more_itertools.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_numpy.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_objects/__init__.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_objects/objects.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_operator.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_optuna.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_orjson.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_os.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_parse.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_pathlib.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_pickle.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_platform.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_polars.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_polars_ols.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_postgres.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_pottery.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_pqdm.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_psutil.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_pytest.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_pytest_randomly.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_pytest_regressions.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_random.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_re.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_redis.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_reprlib.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_scipy.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_sentinel.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_shelve.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_slack_sdk.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_socket.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_statsmodels.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_string.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_tempfile.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_testbook.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_text.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_threading.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_timer.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_typed_settings.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_types.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_typing.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_typing_funcs/__init__.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_typing_funcs/no_future.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_typing_funcs/with_future.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_tzdata.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_tzlocal.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_uuid.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_version.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_warnings.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_zipfile.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/tests/test_zoneinfo.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/aeventkit.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/altair.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/asyncio.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/atomicwrites.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/atools.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/cachetools.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/click.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/concurrent.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/contextlib.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/contextvars.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/cryptography.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/cvxpy.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/dataclasses.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/enum.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/errors.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/fastapi.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/functions.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/functools.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/getpass.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/gzip.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/hashlib.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/http.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/importlib.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/inflect.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/ipython.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/iterables.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/json.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/jupyter.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/libcst.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/lightweight_charts.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/math.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/memory_profiler.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/modules.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/more_itertools.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/numpy.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/operator.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/optuna.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/orjson.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/os.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/parse.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/pathlib.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/pickle.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/platform.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/polars.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/polars_ols.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/postgres.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/pottery.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/pqdm.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/psutil.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/py.typed +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/pytest.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/pytest_plugins/__init__.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/pytest_plugins/pytest_randomly.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/pytest_plugins/pytest_regressions.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/pytest_regressions.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/random.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/re.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/redis.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/reprlib.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/scipy.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/sentinel.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/shelve.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/slack_sdk.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/socket.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/sqlalchemy.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/statsmodels.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/string.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/tempfile.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/testbook.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/text.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/threading.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/timer.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/typed_settings.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/types.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/typing.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/tzdata.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/tzlocal.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/uuid.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/version.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/warnings.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/zipfile.py +0 -0
- {dycw_utilities-0.162.11 → dycw_utilities-0.163.0}/src/utilities/zoneinfo.py +0 -0
@@ -72,8 +72,8 @@ hypothesis = [
|
|
72
72
|
]
|
73
73
|
hypothesis-test = [
|
74
74
|
"libcst",
|
75
|
-
"pathvalidate",
|
76
75
|
"numpy",
|
76
|
+
"pathvalidate",
|
77
77
|
"pytest-rerunfailures",
|
78
78
|
]
|
79
79
|
inflect = [
|
@@ -135,7 +135,6 @@ pottery = [
|
|
135
135
|
]
|
136
136
|
pottery-test = [
|
137
137
|
"orjson",
|
138
|
-
"pytest-rerunfailures",
|
139
138
|
]
|
140
139
|
pqdm = [
|
141
140
|
"pqdm >=0.2.0, <0.3",
|
@@ -162,8 +161,8 @@ pytest-regressions-test = [
|
|
162
161
|
]
|
163
162
|
pytest-test = [
|
164
163
|
"orjson",
|
165
|
-
"pytest-rng",
|
166
164
|
"pytest-rerunfailures",
|
165
|
+
"pytest-rng",
|
167
166
|
]
|
168
167
|
redis = [
|
169
168
|
"redis >=6.4.0, <6.5",
|
@@ -217,6 +216,9 @@ typed-settings = [
|
|
217
216
|
tzdata = [
|
218
217
|
"tzdata >=2025.2, <2025.3",
|
219
218
|
]
|
219
|
+
whenever-test = [
|
220
|
+
"pathvalidate",
|
221
|
+
]
|
220
222
|
|
221
223
|
# project
|
222
224
|
[project]
|
@@ -230,7 +232,7 @@ dependencies = [
|
|
230
232
|
name = "dycw-utilities"
|
231
233
|
readme = "README.md"
|
232
234
|
requires-python = ">= 3.12"
|
233
|
-
version = "0.
|
235
|
+
version = "0.163.0"
|
234
236
|
|
235
237
|
[project.entry-points.pytest11]
|
236
238
|
pytest-randomly = "utilities.pytest_plugins.pytest_randomly"
|
@@ -263,7 +265,7 @@ test = [
|
|
263
265
|
# bump-my-version
|
264
266
|
[tool.bumpversion]
|
265
267
|
allow_dirty = true
|
266
|
-
current_version = "0.
|
268
|
+
current_version = "0.163.0"
|
267
269
|
|
268
270
|
[[tool.bumpversion.files]]
|
269
271
|
filename = "src/utilities/__init__.py"
|
@@ -7,11 +7,12 @@ from typing import TYPE_CHECKING
|
|
7
7
|
|
8
8
|
from hypothesis import HealthCheck
|
9
9
|
from pytest import fixture, mark, param, skip
|
10
|
+
from whenever import PlainDateTime
|
10
11
|
|
11
12
|
from utilities.contextlib import enhanced_context_manager
|
12
13
|
from utilities.platform import IS_LINUX, IS_MAC, IS_NOT_LINUX, IS_WINDOWS
|
13
14
|
from utilities.re import ExtractGroupError, extract_group
|
14
|
-
from utilities.whenever import MINUTE,
|
15
|
+
from utilities.whenever import MINUTE, get_now_local_plain
|
15
16
|
|
16
17
|
if TYPE_CHECKING:
|
17
18
|
from collections.abc import AsyncIterator, Iterator, Sequence
|
@@ -170,11 +171,14 @@ async def test_async_postgres_engine() -> AsyncEngine:
|
|
170
171
|
|
171
172
|
|
172
173
|
def _is_to_drop(table: str, /) -> bool:
|
174
|
+
now = get_now_local_plain()
|
173
175
|
try:
|
174
|
-
|
176
|
+
text = extract_group(r"^(\d{8}T\d{2,})_", table)
|
175
177
|
except ExtractGroupError:
|
176
178
|
return True
|
177
|
-
|
179
|
+
date_time = PlainDateTime.parse_common_iso(text)
|
180
|
+
age = now.difference(date_time, ignore_dst=True)
|
181
|
+
return age >= MINUTE
|
178
182
|
|
179
183
|
|
180
184
|
def _select_tables() -> TextClause:
|
@@ -153,7 +153,7 @@ class TestEnhancedContextManager:
|
|
153
153
|
def test_multiprocessing_sigterm(
|
154
154
|
self, *, tmp_path: Path, target: Callable[..., None]
|
155
155
|
) -> None:
|
156
|
-
sleep = 0
|
156
|
+
sleep = 1.0
|
157
157
|
marker = tmp_path.joinpath("marker")
|
158
158
|
proc = Process(target=target, args=(marker,), kwargs={"sleep": 4 * sleep})
|
159
159
|
proc.start()
|
@@ -40,6 +40,7 @@ from whenever import (
|
|
40
40
|
|
41
41
|
from utilities.functions import ensure_int
|
42
42
|
from utilities.hypothesis import (
|
43
|
+
_LINUX_DISALLOW_TIME_ZONES,
|
43
44
|
Shape,
|
44
45
|
_Draw2DefaultGeneratedSentinelError,
|
45
46
|
_Draw2InputResolvedToSentinelError,
|
@@ -1192,8 +1193,7 @@ class TestZoneInfos:
|
|
1192
1193
|
time_zone = data.draw(zone_infos())
|
1193
1194
|
assert isinstance(time_zone, ZoneInfo)
|
1194
1195
|
if IS_LINUX:
|
1195
|
-
|
1196
|
-
assert time_zone.key not in {"Etc/UTC", "localtime"}
|
1196
|
+
assert time_zone.key not in _LINUX_DISALLOW_TIME_ZONES
|
1197
1197
|
_ = get_now(time_zone)
|
1198
1198
|
|
1199
1199
|
|
@@ -31,7 +31,7 @@ from utilities.logging import (
|
|
31
31
|
from utilities.text import unique_str
|
32
32
|
from utilities.types import LogLevel
|
33
33
|
from utilities.typing import get_args
|
34
|
-
from utilities.whenever import
|
34
|
+
from utilities.whenever import format_compact, get_now_local
|
35
35
|
|
36
36
|
if TYPE_CHECKING:
|
37
37
|
from collections.abc import Mapping
|
@@ -101,7 +101,7 @@ class TestComputeRolloverActions:
|
|
101
101
|
actions.do()
|
102
102
|
files = list(tmp_path.iterdir())
|
103
103
|
assert len(files) == 1
|
104
|
-
assert any(p for p in files if search(r"^log\.1\__
|
104
|
+
assert any(p for p in files if search(r"^log\.1\__.+?\.txt$", p.name))
|
105
105
|
|
106
106
|
for _ in range(2):
|
107
107
|
await sleep(1)
|
@@ -112,9 +112,7 @@ class TestComputeRolloverActions:
|
|
112
112
|
actions.do()
|
113
113
|
files = list(tmp_path.iterdir())
|
114
114
|
assert len(files) == 1
|
115
|
-
assert any(
|
116
|
-
p for p in files if search(r"^log\.1\__[\dT]+__[\dT]+\.txt$", p.name)
|
117
|
-
)
|
115
|
+
assert any(p for p in files if search(r"^log\.1\__.+?__.+?\.txt$", p.name))
|
118
116
|
|
119
117
|
async def test_multiple_backups(self, *, tmp_path: Path) -> None:
|
120
118
|
tmp_path.joinpath("log.txt").touch()
|
@@ -125,7 +123,7 @@ class TestComputeRolloverActions:
|
|
125
123
|
actions.do()
|
126
124
|
files = list(tmp_path.iterdir())
|
127
125
|
assert len(files) == 1
|
128
|
-
assert any(p for p in files if search(r"^log\.1\__
|
126
|
+
assert any(p for p in files if search(r"^log\.1\__.+\.txt$", p.name))
|
129
127
|
|
130
128
|
await sleep(1)
|
131
129
|
tmp_path.joinpath("log.txt").touch()
|
@@ -135,10 +133,8 @@ class TestComputeRolloverActions:
|
|
135
133
|
actions.do()
|
136
134
|
files = list(tmp_path.iterdir())
|
137
135
|
assert len(files) == 2
|
138
|
-
assert any(
|
139
|
-
|
140
|
-
)
|
141
|
-
assert any(p for p in files if search(r"^log\.2\__[\dT]+\.txt$", p.name))
|
136
|
+
assert any(p for p in files if search(r"^log\.1\__.+?__.+?\.txt$", p.name))
|
137
|
+
assert any(p for p in files if search(r"^log\.2\__.+?\.txt$", p.name))
|
142
138
|
|
143
139
|
await sleep(1)
|
144
140
|
tmp_path.joinpath("log.txt").touch()
|
@@ -148,13 +144,9 @@ class TestComputeRolloverActions:
|
|
148
144
|
actions.do()
|
149
145
|
files = list(tmp_path.iterdir())
|
150
146
|
assert len(files) == 3
|
151
|
-
assert any(
|
152
|
-
|
153
|
-
)
|
154
|
-
assert any(
|
155
|
-
p for p in files if search(r"^log\.2\__[\dT]+__[\dT]+\.txt$", p.name)
|
156
|
-
)
|
157
|
-
assert all(p for p in files if search(r"^log\.3\__[\dT]+\.txt$", p.name))
|
147
|
+
assert any(p for p in files if search(r"^log\.1\__.+?__.+?\.txt$", p.name))
|
148
|
+
assert any(p for p in files if search(r"^log\.2\__.+?__.+?\.txt$", p.name))
|
149
|
+
assert all(p for p in files if search(r"^log\.3\__.+?\.txt$", p.name))
|
158
150
|
|
159
151
|
for _ in range(2):
|
160
152
|
await sleep(1)
|
@@ -165,15 +157,9 @@ class TestComputeRolloverActions:
|
|
165
157
|
actions.do()
|
166
158
|
files = list(tmp_path.iterdir())
|
167
159
|
assert len(files) == 3
|
168
|
-
assert any(
|
169
|
-
|
170
|
-
)
|
171
|
-
assert any(
|
172
|
-
p for p in files if search(r"^log\.2\__[\dT]+__[\dT]+\.txt$", p.name)
|
173
|
-
)
|
174
|
-
assert all(
|
175
|
-
p for p in files if search(r"^log\.3\__[\dT]+__[\dT]+\.txt$", p.name)
|
176
|
-
)
|
160
|
+
assert any(p for p in files if search(r"^log\.1\__.+?__.+?\.txt$", p.name))
|
161
|
+
assert any(p for p in files if search(r"^log\.2\__.+?__.+?\.txt$", p.name))
|
162
|
+
assert all(p for p in files if search(r"^log\.3\__.+?__.+?\.txt$", p.name))
|
177
163
|
|
178
164
|
async def test_deleting_old_files(self, *, tmp_path: Path) -> None:
|
179
165
|
tmp_path.joinpath("log.txt").touch()
|
@@ -184,11 +170,11 @@ class TestComputeRolloverActions:
|
|
184
170
|
actions.do()
|
185
171
|
files = list(tmp_path.iterdir())
|
186
172
|
assert len(files) == 1
|
187
|
-
assert any(p for p in files if search(r"^log\.1\__
|
173
|
+
assert any(p for p in files if search(r"^log\.1\__.+?\.txt$", p.name))
|
188
174
|
|
189
175
|
await sleep(1)
|
190
176
|
tmp_path.joinpath("log.txt").touch()
|
191
|
-
now =
|
177
|
+
now = format_compact(get_now_local(), path=True)
|
192
178
|
tmp_path.joinpath(f"log.99__{now}__{now}.txt").touch()
|
193
179
|
actions = _compute_rollover_actions(tmp_path, "log", ".txt")
|
194
180
|
assert len(actions.deletions) == 2
|
@@ -196,9 +182,7 @@ class TestComputeRolloverActions:
|
|
196
182
|
actions.do()
|
197
183
|
files = list(tmp_path.iterdir())
|
198
184
|
assert len(files) == 1
|
199
|
-
assert any(
|
200
|
-
p for p in files if search(r"^log\.1\__[\dT]+__[\dT]+\.txt$", p.name)
|
201
|
-
)
|
185
|
+
assert any(p for p in files if search(r"^log\.1\__.+?__.+?\.txt$", p.name))
|
202
186
|
|
203
187
|
|
204
188
|
class TestGetFormatStr:
|
@@ -278,7 +262,7 @@ class TestRotatingLogFile:
|
|
278
262
|
def test_from_path_with_index_and_end(
|
279
263
|
self, *, index: int, end: ZonedDateTime
|
280
264
|
) -> None:
|
281
|
-
path = Path(f"log.{index}__{
|
265
|
+
path = Path(f"log.{index}__{format_compact(end, path=True)}.txt")
|
282
266
|
result = _RotatingLogFile.from_path(path, "log", ".txt")
|
283
267
|
assert result is not None
|
284
268
|
assert result.stem == "log"
|
@@ -294,7 +278,9 @@ class TestRotatingLogFile:
|
|
294
278
|
self, *, index: int, datetimes: tuple[ZonedDateTime, ZonedDateTime]
|
295
279
|
) -> None:
|
296
280
|
start, end = datetimes
|
297
|
-
path = Path(
|
281
|
+
path = Path(
|
282
|
+
f"log.{index}__{format_compact(start, path=True)}__{format_compact(end, path=True)}.txt"
|
283
|
+
)
|
298
284
|
result = _RotatingLogFile.from_path(path, "log", ".txt")
|
299
285
|
assert result is not None
|
300
286
|
assert result.stem == "log"
|
@@ -324,7 +310,9 @@ class TestRotatingLogFile:
|
|
324
310
|
file = _RotatingLogFile(
|
325
311
|
directory=root, stem="log", suffix=".txt", index=index, end=end
|
326
312
|
)
|
327
|
-
assert file.path == root.joinpath(
|
313
|
+
assert file.path == root.joinpath(
|
314
|
+
f"log.{index}__{format_compact(end, path=True)}.txt"
|
315
|
+
)
|
328
316
|
|
329
317
|
@given(
|
330
318
|
root=temp_paths(),
|
@@ -339,7 +327,7 @@ class TestRotatingLogFile:
|
|
339
327
|
directory=root, stem="log", suffix=".txt", index=index, start=start, end=end
|
340
328
|
)
|
341
329
|
assert file.path == root.joinpath(
|
342
|
-
f"log.{index}__{
|
330
|
+
f"log.{index}__{format_compact(start, path=True)}__{format_compact(end, path=True)}.txt"
|
343
331
|
)
|
344
332
|
|
345
333
|
|
@@ -393,46 +381,34 @@ class TestSizeAndTimeRotatingFileHandler:
|
|
393
381
|
assert any(p for p in files if search(r"^log\.txt$", p.name))
|
394
382
|
if cycle == 2:
|
395
383
|
assert any(
|
396
|
-
p for p in files if search(r"^log\.1__
|
384
|
+
p for p in files if search(r"^log\.1__.+?\.txt$", p.name)
|
397
385
|
)
|
398
386
|
elif cycle == 3:
|
399
387
|
assert any(
|
400
|
-
p
|
401
|
-
for p in files
|
402
|
-
if search(r"^log\.1__[\dT]+__[\dT]+\.txt$", p.name)
|
388
|
+
p for p in files if search(r"^log\.1__.+?__.+?\.txt$", p.name)
|
403
389
|
)
|
404
390
|
assert any(
|
405
|
-
p for p in files if search(r"^log\.2__
|
391
|
+
p for p in files if search(r"^log\.2__.+?\.txt$", p.name)
|
406
392
|
)
|
407
393
|
elif cycle == 4:
|
408
394
|
assert any(
|
409
|
-
p
|
410
|
-
for p in files
|
411
|
-
if search(r"^log\.1__[\dT]+__[\dT]+\.txt$", p.name)
|
395
|
+
p for p in files if search(r"^log\.1__.+?__.+?\.txt$", p.name)
|
412
396
|
)
|
413
397
|
assert any(
|
414
|
-
p
|
415
|
-
for p in files
|
416
|
-
if search(r"^log\.2__[\dT]+__[\dT]+\.txt$", p.name)
|
398
|
+
p for p in files if search(r"^log\.2__.+?__.+?\.txt$", p.name)
|
417
399
|
)
|
418
400
|
assert any(
|
419
|
-
p for p in files if search(r"^log\.3__
|
401
|
+
p for p in files if search(r"^log\.3__.+?\.txt$", p.name)
|
420
402
|
)
|
421
403
|
elif cycle >= 5:
|
422
404
|
assert any(
|
423
|
-
p
|
424
|
-
for p in files
|
425
|
-
if search(r"^log\.1__[\dT]+__[\dT]+\.txt$", p.name)
|
405
|
+
p for p in files if search(r"^log\.1__.+?__.+?\.txt$", p.name)
|
426
406
|
)
|
427
407
|
assert any(
|
428
|
-
p
|
429
|
-
for p in files
|
430
|
-
if search(r"^log\.2__[\dT]+__[\dT]+\.txt$", p.name)
|
408
|
+
p for p in files if search(r"^log\.2__.+?__.+?\.txt$", p.name)
|
431
409
|
)
|
432
410
|
assert any(
|
433
|
-
p
|
434
|
-
for p in files
|
435
|
-
if search(r"^log\.3__[\dT]+__[\dT]+\.txt$", p.name)
|
411
|
+
p for p in files if search(r"^log\.3__.+?__.+?\.txt$", p.name)
|
436
412
|
)
|
437
413
|
await sleep(0.1)
|
438
414
|
|
@@ -463,7 +439,7 @@ class TestSizeAndTimeRotatingFileHandler:
|
|
463
439
|
files = list(tmp_path.iterdir())
|
464
440
|
assert len(files) == 2
|
465
441
|
assert any(p for p in files if search(r"^log\.txt$", p.name))
|
466
|
-
assert any(p for p in files if search(r"^log\.1__
|
442
|
+
assert any(p for p in files if search(r"^log\.1__.+?\.txt$", p.name))
|
467
443
|
|
468
444
|
await sleep(1.1)
|
469
445
|
for i in range(4, 6):
|
@@ -471,10 +447,8 @@ class TestSizeAndTimeRotatingFileHandler:
|
|
471
447
|
files = list(tmp_path.iterdir())
|
472
448
|
assert len(files) == 3
|
473
449
|
assert any(p for p in files if search(r"^log\.txt$", p.name))
|
474
|
-
assert any(
|
475
|
-
|
476
|
-
)
|
477
|
-
assert any(p for p in files if search(r"^log\.2__[\dT]+\.txt$", p.name))
|
450
|
+
assert any(p for p in files if search(r"^log\.1__.+?__.+?\.txt$", p.name))
|
451
|
+
assert any(p for p in files if search(r"^log\.2__.+?\.txt$", p.name))
|
478
452
|
|
479
453
|
await sleep(1.1)
|
480
454
|
for i in range(6, 8):
|
@@ -482,13 +456,9 @@ class TestSizeAndTimeRotatingFileHandler:
|
|
482
456
|
files = list(tmp_path.iterdir())
|
483
457
|
assert len(files) == 4
|
484
458
|
assert any(p for p in files if search(r"^log\.txt$", p.name))
|
485
|
-
assert any(
|
486
|
-
|
487
|
-
)
|
488
|
-
assert any(
|
489
|
-
p for p in files if search(r"^log\.2__[\dT]+__[\dT]+\.txt$", p.name)
|
490
|
-
)
|
491
|
-
assert any(p for p in files if search(r"^log\.3__[\dT]+\.txt$", p.name))
|
459
|
+
assert any(p for p in files if search(r"^log\.1__.+?__.+?\.txt$", p.name))
|
460
|
+
assert any(p for p in files if search(r"^log\.2__.+?__.+?\.txt$", p.name))
|
461
|
+
assert any(p for p in files if search(r"^log\.3__.+?\.txt$", p.name))
|
492
462
|
|
493
463
|
for _ in range(2):
|
494
464
|
await sleep(1.1)
|
@@ -498,13 +468,13 @@ class TestSizeAndTimeRotatingFileHandler:
|
|
498
468
|
assert len(files) == 4
|
499
469
|
assert any(p for p in files if search(r"^log\.txt$", p.name))
|
500
470
|
assert any(
|
501
|
-
p for p in files if search(r"^log\.1__
|
471
|
+
p for p in files if search(r"^log\.1__.+?__.+?\.txt$", p.name)
|
502
472
|
)
|
503
473
|
assert any(
|
504
|
-
p for p in files if search(r"^log\.2__
|
474
|
+
p for p in files if search(r"^log\.2__.+?__.+?\.txt$", p.name)
|
505
475
|
)
|
506
476
|
assert any(
|
507
|
-
p for p in files if search(r"^log\.3__
|
477
|
+
p for p in files if search(r"^log\.3__.+?__.+?\.txt$", p.name)
|
508
478
|
)
|
509
479
|
|
510
480
|
@mark.parametrize("max_bytes", [param(0), param(1)])
|
@@ -90,7 +90,7 @@ from utilities.sqlalchemy import (
|
|
90
90
|
)
|
91
91
|
from utilities.text import strip_and_dedent
|
92
92
|
from utilities.typing import get_args
|
93
|
-
from utilities.whenever import MILLISECOND,
|
93
|
+
from utilities.whenever import MILLISECOND, format_compact, get_now_local_plain
|
94
94
|
|
95
95
|
if TYPE_CHECKING:
|
96
96
|
from pathlib import Path
|
@@ -101,7 +101,7 @@ if TYPE_CHECKING:
|
|
101
101
|
def _table_names() -> str:
|
102
102
|
"""Generate at unique string."""
|
103
103
|
key = str(uuid4()).replace("-", "")
|
104
|
-
return f"{
|
104
|
+
return f"{format_compact(get_now_local_plain())}_{key}"
|
105
105
|
|
106
106
|
|
107
107
|
class TestCheckConnect:
|
@@ -19,7 +19,7 @@ from utilities.traceback import (
|
|
19
19
|
make_except_hook,
|
20
20
|
)
|
21
21
|
from utilities.tzlocal import LOCAL_TIME_ZONE_NAME
|
22
|
-
from utilities.whenever import SECOND,
|
22
|
+
from utilities.whenever import SECOND, format_compact, get_now
|
23
23
|
|
24
24
|
if TYPE_CHECKING:
|
25
25
|
from collections.abc import Iterable
|
@@ -106,7 +106,7 @@ class TestMakeExceptHook:
|
|
106
106
|
exc_type, exc_val, traceback = exc_info()
|
107
107
|
hook(exc_type, exc_val, traceback)
|
108
108
|
path = one(tmp_path.iterdir())
|
109
|
-
assert search(r"
|
109
|
+
assert search(r"^.+?\.txt$", path.name)
|
110
110
|
|
111
111
|
def test_non_error(self) -> None:
|
112
112
|
hook = make_except_hook()
|
@@ -116,7 +116,9 @@ class TestMakeExceptHook:
|
|
116
116
|
|
117
117
|
def test_purge(self, *, tmp_path: Path) -> None:
|
118
118
|
now = get_now()
|
119
|
-
path = tmp_path.joinpath(
|
119
|
+
path = tmp_path.joinpath(
|
120
|
+
format_compact(now - 2 * SECOND, path=True)
|
121
|
+
).with_suffix(".txt")
|
120
122
|
path.touch()
|
121
123
|
assert len(list(tmp_path.iterdir())) == 1
|
122
124
|
_make_except_hook_purge(tmp_path, SECOND)
|
@@ -9,6 +9,7 @@ from zoneinfo import ZoneInfo
|
|
9
9
|
|
10
10
|
from hypothesis import HealthCheck, given, settings
|
11
11
|
from hypothesis.strategies import DataObject, data, integers, none, sampled_from
|
12
|
+
from pathvalidate import validate_filepath
|
12
13
|
from pytest import mark, param, raises
|
13
14
|
from whenever import (
|
14
15
|
Date,
|
@@ -39,6 +40,7 @@ from utilities.hypothesis import (
|
|
39
40
|
zoned_date_times_2000,
|
40
41
|
)
|
41
42
|
from utilities.sentinel import Sentinel, sentinel
|
43
|
+
from utilities.types import TIME_ZONES
|
42
44
|
from utilities.tzdata import HongKong, Tokyo, USCentral, USEastern
|
43
45
|
from utilities.tzlocal import LOCAL_TIME_ZONE_NAME
|
44
46
|
from utilities.whenever import (
|
@@ -55,6 +57,7 @@ from utilities.whenever import (
|
|
55
57
|
MINUTE,
|
56
58
|
MONTH,
|
57
59
|
NOW_LOCAL,
|
60
|
+
NOW_LOCAL_PLAIN,
|
58
61
|
NOW_PLAIN,
|
59
62
|
NOW_UTC,
|
60
63
|
SECOND,
|
@@ -115,19 +118,18 @@ from utilities.whenever import (
|
|
115
118
|
from_timestamp_nanos,
|
116
119
|
get_now,
|
117
120
|
get_now_local,
|
121
|
+
get_now_local_plain,
|
118
122
|
get_now_plain,
|
119
123
|
get_today,
|
120
124
|
get_today_local,
|
121
125
|
mean_datetime,
|
122
126
|
min_max_date,
|
123
|
-
parse_plain_local,
|
124
127
|
round_date_or_date_time,
|
125
128
|
sub_year_month,
|
126
129
|
to_date,
|
127
130
|
to_date_time_delta,
|
128
131
|
to_days,
|
129
132
|
to_hours,
|
130
|
-
to_local_plain,
|
131
133
|
to_microseconds,
|
132
134
|
to_milliseconds,
|
133
135
|
to_minutes,
|
@@ -158,6 +160,7 @@ if TYPE_CHECKING:
|
|
158
160
|
MaybeCallableDateLike,
|
159
161
|
MaybeCallableZonedDateTimeLike,
|
160
162
|
TimeOrDateTimeDelta,
|
163
|
+
TimeZone,
|
161
164
|
)
|
162
165
|
|
163
166
|
|
@@ -354,24 +357,46 @@ class TestFormatCompact:
|
|
354
357
|
expected = time.round()
|
355
358
|
assert parsed == expected
|
356
359
|
|
357
|
-
@given(
|
358
|
-
def
|
359
|
-
result = format_compact(
|
360
|
+
@given(date_time=plain_date_times())
|
361
|
+
def test_plain_date_time(self, *, date_time: PlainDateTime) -> None:
|
362
|
+
result = format_compact(date_time)
|
360
363
|
assert isinstance(result, str)
|
361
364
|
parsed = PlainDateTime.parse_common_iso(result)
|
362
365
|
assert parsed.nanosecond == 0
|
363
|
-
expected =
|
366
|
+
expected = date_time.round()
|
364
367
|
assert parsed == expected
|
365
368
|
|
366
|
-
@given(
|
367
|
-
def
|
368
|
-
result = format_compact(
|
369
|
+
@given(date_time=zoned_date_times(time_zone=zone_infos()))
|
370
|
+
def test_zoned_date_time(self, *, date_time: ZonedDateTime) -> None:
|
371
|
+
result = format_compact(date_time)
|
369
372
|
assert isinstance(result, str)
|
370
|
-
parsed =
|
373
|
+
parsed = to_zoned_date_time(result)
|
371
374
|
assert parsed.nanosecond == 0
|
372
|
-
expected =
|
375
|
+
expected = date_time.round()
|
373
376
|
assert parsed == expected
|
374
377
|
|
378
|
+
@mark.parametrize(
|
379
|
+
("time_zone", "suffix"),
|
380
|
+
[
|
381
|
+
param("America/Argentina/Buenos_Aires", "America~Argentina~Buenos_Aires"),
|
382
|
+
param("Asia/Hong_Kong", "Asia~Hong_Kong"),
|
383
|
+
param("Etc/GMT", "Etc~GMT"),
|
384
|
+
param("Etc/GMT+1", "Etc~GMT+1"),
|
385
|
+
param("Etc/GMT-1", "Etc~GMT-1"),
|
386
|
+
],
|
387
|
+
)
|
388
|
+
def test_zoned_date_time_path(self, *, time_zone: TimeZone, suffix: str) -> None:
|
389
|
+
assert time_zone in TIME_ZONES
|
390
|
+
date_time = ZonedDateTime(
|
391
|
+
2000, 1, 2, 12, 34, 56, nanosecond=123456789, tz=time_zone
|
392
|
+
)
|
393
|
+
ser = format_compact(date_time, path=True)
|
394
|
+
validate_filepath(ser)
|
395
|
+
expected = f"20000102T123456[{suffix}]"
|
396
|
+
assert ser == expected
|
397
|
+
result = to_zoned_date_time(ser)
|
398
|
+
assert result.exact_eq(date_time.round())
|
399
|
+
|
375
400
|
|
376
401
|
class TestFromTimeStamp:
|
377
402
|
@given(
|
@@ -427,6 +452,15 @@ class TestGetNowLocal:
|
|
427
452
|
assert NOW_LOCAL.tz == LOCAL_TIME_ZONE_NAME
|
428
453
|
|
429
454
|
|
455
|
+
class TestGetNowLocalPlain:
|
456
|
+
def test_function(self) -> None:
|
457
|
+
now = get_now_local_plain()
|
458
|
+
assert isinstance(now, PlainDateTime)
|
459
|
+
|
460
|
+
def test_constant(self) -> None:
|
461
|
+
assert isinstance(NOW_LOCAL_PLAIN, PlainDateTime)
|
462
|
+
|
463
|
+
|
430
464
|
class TestGetNowPlain:
|
431
465
|
@given(time_zone=zone_infos())
|
432
466
|
def test_function(self, *, time_zone: ZoneInfo) -> None:
|
@@ -968,15 +1002,6 @@ class TestToHours:
|
|
968
1002
|
_ = to_hours(delta)
|
969
1003
|
|
970
1004
|
|
971
|
-
class TestToLocalPlainAndParsePlainLocal:
|
972
|
-
@given(date_time=zoned_date_times())
|
973
|
-
def test_main(self, *, date_time: ZonedDateTime) -> None:
|
974
|
-
text = to_local_plain(date_time)
|
975
|
-
assert isinstance(text, str)
|
976
|
-
parsed = parse_plain_local(text)
|
977
|
-
assert abs(parsed - date_time) <= SECOND
|
978
|
-
|
979
|
-
|
980
1005
|
class TestToMicroseconds:
|
981
1006
|
@given(days=integers())
|
982
1007
|
def test_date_delta(self, *, days: int) -> None:
|
@@ -1399,9 +1424,13 @@ class TestToZonedDateTime:
|
|
1399
1424
|
expected = date_time.to_tz(time_zone.key)
|
1400
1425
|
assert result.exact_eq(expected)
|
1401
1426
|
|
1402
|
-
@given(date_time=zoned_date_times(), time_zone=zone_infos())
|
1403
|
-
def test_str(
|
1404
|
-
|
1427
|
+
@given(data=data(), date_time=zoned_date_times(), time_zone=zone_infos())
|
1428
|
+
def test_str(
|
1429
|
+
self, *, data: DataObject, date_time: ZonedDateTime, time_zone: ZoneInfo
|
1430
|
+
) -> None:
|
1431
|
+
text = date_time.format_common_iso()
|
1432
|
+
text_use = data.draw(sampled_from([text, text.replace("/", "_")]))
|
1433
|
+
result = to_zoned_date_time(text_use, time_zone=time_zone)
|
1405
1434
|
expected = date_time.to_tz(time_zone.key)
|
1406
1435
|
assert result.exact_eq(expected)
|
1407
1436
|
|
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, override
|
|
6
6
|
from fpdf import FPDF
|
7
7
|
from fpdf.enums import XPos, YPos
|
8
8
|
|
9
|
-
from utilities.whenever import
|
9
|
+
from utilities.whenever import format_compact, get_now_local
|
10
10
|
|
11
11
|
if TYPE_CHECKING:
|
12
12
|
from collections.abc import Iterator
|
@@ -47,7 +47,7 @@ def yield_pdf(*, header: str | None = None) -> Iterator[_BasePDF]:
|
|
47
47
|
def footer(self) -> None:
|
48
48
|
self.set_y(-15)
|
49
49
|
self.set_font(family="Helvetica", style="I", size=8)
|
50
|
-
page_no, now = (self.page_no(),
|
50
|
+
page_no, now = (self.page_no(), format_compact(get_now_local()))
|
51
51
|
text = f"page {page_no}/{{}}; {now}"
|
52
52
|
_ = self.cell(
|
53
53
|
w=0,
|
@@ -115,7 +115,7 @@ if TYPE_CHECKING:
|
|
115
115
|
from sqlalchemy import URL
|
116
116
|
|
117
117
|
from utilities.numpy import NDArrayB, NDArrayF, NDArrayI, NDArrayO
|
118
|
-
from utilities.types import Number, TimeZoneLike
|
118
|
+
from utilities.types import Number, TimeZone, TimeZoneLike
|
119
119
|
|
120
120
|
|
121
121
|
type MaybeSearchStrategy[_T] = _T | SearchStrategy[_T]
|
@@ -1484,12 +1484,17 @@ def zone_infos(draw: DrawFn, /) -> ZoneInfo:
|
|
1484
1484
|
"""Strategy for generating time-zones."""
|
1485
1485
|
time_zone = draw(timezones())
|
1486
1486
|
if IS_LINUX: # skipif-not-linux
|
1487
|
-
_ = assume(time_zone.key not in
|
1487
|
+
_ = assume(time_zone.key not in _LINUX_DISALLOW_TIME_ZONES)
|
1488
1488
|
with assume_does_not_raise(TimeZoneNotFoundError):
|
1489
1489
|
_ = get_now(time_zone)
|
1490
1490
|
return time_zone
|
1491
1491
|
|
1492
1492
|
|
1493
|
+
_LINUX_DISALLOW_TIME_ZONES: set[TimeZone | Literal["localtime"]] = {
|
1494
|
+
"Etc/UTC",
|
1495
|
+
"localtime",
|
1496
|
+
}
|
1497
|
+
|
1493
1498
|
##
|
1494
1499
|
|
1495
1500
|
|