dycw-utilities 0.131.18__tar.gz → 0.131.19__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.18 → dycw_utilities-0.131.19}/PKG-INFO +1 -1
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/pyproject.toml +2 -2
- dycw_utilities-0.131.19/src/tests/conftest.py +104 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_altair.py +23 -17
- dycw_utilities-0.131.19/src/tests/test_datetime.py +161 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_functions.py +55 -27
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_http.py +2 -2
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_hypothesis.py +11 -277
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_iterables.py +10 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_orjson.py +2 -3
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_polars.py +32 -16
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_pytest.py +113 -93
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_slack_sdk.py +3 -4
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_sqlalchemy_polars.py +3 -4
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_types.py +1 -12
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_typing.py +237 -228
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_whenever2.py +142 -14
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_zoneinfo.py +21 -4
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/__init__.py +1 -1
- dycw_utilities-0.131.19/src/utilities/datetime.py +222 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/fastapi.py +5 -7
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/functions.py +78 -45
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/hypothesis.py +20 -269
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/polars.py +6 -3
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/pytest.py +83 -63
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/types.py +3 -24
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/typing.py +2 -15
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/whenever2.py +147 -3
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/zoneinfo.py +4 -0
- dycw_utilities-0.131.18/src/tests/conftest.py +0 -446
- dycw_utilities-0.131.18/src/tests/test_datetime.py +0 -1049
- dycw_utilities-0.131.18/src/tests/test_whenever.py +0 -180
- dycw_utilities-0.131.18/src/utilities/datetime.py +0 -1125
- dycw_utilities-0.131.18/src/utilities/whenever.py +0 -230
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/.gitignore +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/LICENSE +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/README.md +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/__init__.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/modules/__init__.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/modules/package_missing/__init__.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/modules/package_missing/module.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/modules/package_with/__init__.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/modules/package_with/outer_1.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/modules/package_with/outer_2.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/modules/package_without/__init__.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/modules/package_without/module_1.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/modules/package_without/module_2.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/modules/standalone.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/modules/with_imports.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_aiolimiter.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_asyncio.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_asyncio_classes/__init__.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_asyncio_classes/loopers.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_asyncio_classes/redis.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_atomicwrites.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_atools.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_cachetools.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_click.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_concurrent.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_contextlib.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_contextvars.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_cryptography.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_cvxpy.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_dataclasses.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_enum.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_errors.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_eventkit.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_fastapi.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_fpdf2.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_functools.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_getpass.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_git.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_hashlib.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_importlib.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_inflect.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_ipython.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_jupyter.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_libcst.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_lightweight_charts.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_logging.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_luigi.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_math.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_memory_profiler.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_modules.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_more_itertools.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_numpy.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_objects/__init__.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_objects/objects.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_operator.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_optuna.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_os.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_parse.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_pathlib.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_period.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_pickle.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_platform.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_polars_ols.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_pottery.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_pqdm.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_psutil.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_pydantic.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_pyinstrument.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_pyrsistent.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_pytest_regressions.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_python_dotenv.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_random.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_re.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_redis.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_reprlib.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_scipy.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_sentinel.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_shelve.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_socket.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_sqlalchemy.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_statsmodel.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_streamlit.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_string.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_tempfile.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_text.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_threading.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_timer.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_traceback.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_typed_settings.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_typing_funcs/__init__.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_typing_funcs/no_future.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_typing_funcs/with_future.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_tzdata.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_tzlocal.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_uuid.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_version.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_warnings.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/tests/test_zipfile.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/aiolimiter.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/altair.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/asyncio.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/atomicwrites.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/atools.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/cachetools.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/click.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/concurrent.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/contextlib.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/contextvars.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/cryptography.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/cvxpy.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/dataclasses.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/enum.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/errors.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/eventkit.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/fpdf2.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/functools.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/getpass.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/git.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/hashlib.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/http.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/importlib.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/inflect.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/ipython.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/iterables.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/jupyter.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/libcst.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/lightweight_charts.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/logging.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/luigi.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/math.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/memory_profiler.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/modules.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/more_itertools.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/numpy.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/operator.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/optuna.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/orjson.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/os.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/parse.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/pathlib.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/period.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/pickle.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/platform.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/polars_ols.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/pottery.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/pqdm.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/psutil.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/py.typed +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/pydantic.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/pyinstrument.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/pyrsistent.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/pytest_regressions.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/python_dotenv.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/random.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/re.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/redis.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/reprlib.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/scipy.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/sentinel.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/shelve.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/slack_sdk.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/socket.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/sqlalchemy.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/statsmodels.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/streamlit.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/string.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/tempfile.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/text.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/threading.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/timer.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/traceback.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/typed_settings.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/tzdata.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/tzlocal.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/uuid.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/version.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/warnings.py +0 -0
- {dycw_utilities-0.131.18 → dycw_utilities-0.131.19}/src/utilities/zipfile.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.19"
|
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.19"
|
125
125
|
|
126
126
|
[[tool.bumpversion.files]]
|
127
127
|
filename = "src/utilities/__init__.py"
|
@@ -0,0 +1,104 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from asyncio import sleep
|
4
|
+
from contextlib import AbstractContextManager, contextmanager, suppress
|
5
|
+
from logging import LogRecord, setLogRecordFactory
|
6
|
+
from os import environ
|
7
|
+
from typing import TYPE_CHECKING, Any
|
8
|
+
|
9
|
+
from hypothesis import HealthCheck
|
10
|
+
from pytest import fixture, mark, param
|
11
|
+
from sqlalchemy import text
|
12
|
+
from whenever import PlainDateTime
|
13
|
+
|
14
|
+
from utilities.platform import IS_NOT_LINUX, IS_WINDOWS
|
15
|
+
from utilities.re import ExtractGroupError, extract_group
|
16
|
+
from utilities.tzlocal import LOCAL_TIME_ZONE_NAME
|
17
|
+
from utilities.whenever2 import MINUTE, get_now
|
18
|
+
|
19
|
+
if TYPE_CHECKING:
|
20
|
+
from collections.abc import Iterator, Sequence
|
21
|
+
from pathlib import Path
|
22
|
+
|
23
|
+
from _pytest.fixtures import SubRequest
|
24
|
+
|
25
|
+
|
26
|
+
FLAKY = mark.flaky(reruns=5, reruns_delay=1)
|
27
|
+
IS_CI = "CI" in environ
|
28
|
+
SKIPIF_CI = mark.skipif(IS_CI, reason="Skipped for CI")
|
29
|
+
IS_CI_AND_WINDOWS = IS_CI and IS_WINDOWS
|
30
|
+
SKIPIF_CI_AND_WINDOWS = mark.skipif(IS_CI_AND_WINDOWS, reason="Skipped for CI/Windows")
|
31
|
+
SKIPIF_CI_AND_NOT_LINUX = mark.skipif(
|
32
|
+
IS_CI and IS_NOT_LINUX, reason="Skipped for CI/non-Linux"
|
33
|
+
)
|
34
|
+
|
35
|
+
|
36
|
+
# hypothesis
|
37
|
+
|
38
|
+
|
39
|
+
try:
|
40
|
+
from utilities.hypothesis import setup_hypothesis_profiles
|
41
|
+
except ModuleNotFoundError:
|
42
|
+
pass
|
43
|
+
else:
|
44
|
+
setup_hypothesis_profiles(suppress_health_check={HealthCheck.differing_executors})
|
45
|
+
|
46
|
+
|
47
|
+
# fixture - logging
|
48
|
+
|
49
|
+
|
50
|
+
@fixture
|
51
|
+
def set_log_factory() -> AbstractContextManager[None]:
|
52
|
+
@contextmanager
|
53
|
+
def cm() -> Iterator[None]:
|
54
|
+
try:
|
55
|
+
yield
|
56
|
+
finally:
|
57
|
+
setLogRecordFactory(LogRecord)
|
58
|
+
|
59
|
+
return cm()
|
60
|
+
|
61
|
+
|
62
|
+
# fixtures - sqlalchemy
|
63
|
+
|
64
|
+
|
65
|
+
@fixture(params=[param("sqlite"), param("postgresql", marks=SKIPIF_CI)])
|
66
|
+
async def test_engine(*, request: SubRequest, tmp_path: Path) -> Any:
|
67
|
+
from utilities.sqlalchemy import create_async_engine
|
68
|
+
|
69
|
+
dialect = request.param
|
70
|
+
match dialect:
|
71
|
+
case "sqlite":
|
72
|
+
db_path = tmp_path / "db.sqlite"
|
73
|
+
return create_async_engine("sqlite+aiosqlite", database=str(db_path))
|
74
|
+
case "postgresql":
|
75
|
+
engine = create_async_engine(
|
76
|
+
"postgresql+asyncpg", host="localhost", port=5432, database="testing"
|
77
|
+
)
|
78
|
+
query = text("SELECT tablename FROM pg_tables")
|
79
|
+
async with engine.begin() as conn:
|
80
|
+
tables: Sequence[str] = (await conn.execute(query)).scalars().all()
|
81
|
+
for table in tables:
|
82
|
+
if _is_to_drop(table):
|
83
|
+
async with engine.begin() as conn:
|
84
|
+
with suppress(Exception):
|
85
|
+
_ = await conn.execute(
|
86
|
+
text(f'DROP TABLE IF EXISTS "{table}" CASCADE')
|
87
|
+
)
|
88
|
+
await sleep(0.01)
|
89
|
+
return engine
|
90
|
+
case _:
|
91
|
+
msg = f"Unsupported dialect: {dialect}"
|
92
|
+
raise NotImplementedError(msg)
|
93
|
+
|
94
|
+
|
95
|
+
def _is_to_drop(table: str, /) -> bool:
|
96
|
+
try:
|
97
|
+
datetime_str = extract_group(r"^(\d{8}T\d{6})_", table)
|
98
|
+
except ExtractGroupError:
|
99
|
+
return True
|
100
|
+
datetime = PlainDateTime.parse_common_iso(datetime_str).assume_tz(
|
101
|
+
LOCAL_TIME_ZONE_NAME
|
102
|
+
)
|
103
|
+
now = get_now()
|
104
|
+
return (now - datetime) >= MINUTE
|
@@ -2,15 +2,12 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import datetime as dt
|
4
4
|
from math import inf
|
5
|
-
from typing import TYPE_CHECKING
|
5
|
+
from typing import TYPE_CHECKING
|
6
6
|
|
7
7
|
import polars as pl
|
8
8
|
from hypothesis import HealthCheck, given, settings
|
9
9
|
from hypothesis.strategies import (
|
10
|
-
DataObject,
|
11
10
|
booleans,
|
12
|
-
data,
|
13
|
-
dates,
|
14
11
|
floats,
|
15
12
|
integers,
|
16
13
|
just,
|
@@ -19,7 +16,7 @@ from hypothesis.strategies import (
|
|
19
16
|
sampled_from,
|
20
17
|
tuples,
|
21
18
|
)
|
22
|
-
from polars import DataFrame,
|
19
|
+
from polars import DataFrame, Float64, datetime_range, int_range
|
23
20
|
from pytest import fixture
|
24
21
|
|
25
22
|
from utilities.altair import (
|
@@ -30,7 +27,7 @@ from utilities.altair import (
|
|
30
27
|
vconcat_charts,
|
31
28
|
)
|
32
29
|
from utilities.functions import ensure_class
|
33
|
-
from utilities.hypothesis import text_ascii,
|
30
|
+
from utilities.hypothesis import dates_whenever, text_ascii, zoned_datetimes_whenever
|
34
31
|
from utilities.polars import DatetimeUTC, zoned_datetime
|
35
32
|
from utilities.tzdata import HongKong, Tokyo
|
36
33
|
from utilities.whenever2 import get_now
|
@@ -40,6 +37,9 @@ if TYPE_CHECKING:
|
|
40
37
|
from pathlib import Path
|
41
38
|
from zoneinfo import ZoneInfo
|
42
39
|
|
40
|
+
import whenever
|
41
|
+
from whenever import ZonedDateTime
|
42
|
+
|
43
43
|
|
44
44
|
@fixture
|
45
45
|
def time_series() -> DataFrame:
|
@@ -105,19 +105,25 @@ class TestPlotDataFrames:
|
|
105
105
|
expected = dt.datetime(2000, 1, 1, 12, tzinfo=time_zone).replace(tzinfo=None)
|
106
106
|
assert datetime == expected
|
107
107
|
|
108
|
-
@given(data=
|
109
|
-
def
|
110
|
-
self, *, data:
|
108
|
+
@given(data=lists(tuples(dates_whenever(), floats(-10, 10))))
|
109
|
+
def test_tooltip_format_date(
|
110
|
+
self, *, data: list[tuple[whenever.Date, float]]
|
111
|
+
) -> None:
|
112
|
+
df = DataFrame(
|
113
|
+
data=[(d.py_date(), v) for d, v in data],
|
114
|
+
schema={"index": pl.Date, "value": Float64},
|
115
|
+
orient="row",
|
116
|
+
)
|
117
|
+
_ = plot_dataframes(df, x="index", y="value")
|
118
|
+
|
119
|
+
@given(data=lists(tuples(zoned_datetimes_whenever(), floats(-10, 10))))
|
120
|
+
def test_tooltip_format_date_time(
|
121
|
+
self, *, data: list[tuple[ZonedDateTime, float]]
|
111
122
|
) -> None:
|
112
|
-
match case:
|
113
|
-
case "date":
|
114
|
-
values = data.draw(lists(tuples(dates(), floats(-10, 10))))
|
115
|
-
dtype = Date()
|
116
|
-
case "datetime":
|
117
|
-
values = data.draw(lists(tuples(zoned_datetimes(), floats(-10, 10))))
|
118
|
-
dtype = DatetimeUTC
|
119
123
|
df = DataFrame(
|
120
|
-
data=
|
124
|
+
data=[(d.py_datetime(), v) for d, v in data],
|
125
|
+
schema={"index": DatetimeUTC, "value": Float64},
|
126
|
+
orient="row",
|
121
127
|
)
|
122
128
|
_ = plot_dataframes(df, x="index", y="value")
|
123
129
|
|
@@ -0,0 +1,161 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import datetime as dt
|
4
|
+
from re import search
|
5
|
+
from typing import TYPE_CHECKING
|
6
|
+
|
7
|
+
from hypothesis import assume, given
|
8
|
+
from hypothesis.strategies import DataObject, data, dates, integers, sampled_from
|
9
|
+
from pytest import mark, param, raises
|
10
|
+
|
11
|
+
from utilities.datetime import (
|
12
|
+
EnsureMonthError,
|
13
|
+
Month,
|
14
|
+
MonthError,
|
15
|
+
ParseMonthError,
|
16
|
+
_ParseTwoDigitYearInvalidIntegerError,
|
17
|
+
_ParseTwoDigitYearInvalidStringError,
|
18
|
+
date_to_month,
|
19
|
+
ensure_month,
|
20
|
+
maybe_sub_pct_y,
|
21
|
+
parse_month,
|
22
|
+
parse_two_digit_year,
|
23
|
+
serialize_month,
|
24
|
+
)
|
25
|
+
from utilities.hypothesis import months, text_clean
|
26
|
+
from utilities.zoneinfo import UTC
|
27
|
+
|
28
|
+
if TYPE_CHECKING:
|
29
|
+
from collections.abc import Callable
|
30
|
+
|
31
|
+
|
32
|
+
class TestDateToMonth:
|
33
|
+
@given(date=dates())
|
34
|
+
def test_main(self, *, date: dt.date) -> None:
|
35
|
+
result = date_to_month(date).to_date(day=date.day)
|
36
|
+
assert result == date
|
37
|
+
|
38
|
+
|
39
|
+
class TestMaybeSubPctY:
|
40
|
+
@given(text=text_clean())
|
41
|
+
def test_main(self, *, text: str) -> None:
|
42
|
+
result = maybe_sub_pct_y(text)
|
43
|
+
_ = assume(not search("%Y", result))
|
44
|
+
assert not search("%Y", result)
|
45
|
+
|
46
|
+
|
47
|
+
class TestMonth:
|
48
|
+
@mark.parametrize(
|
49
|
+
("month", "n", "expected"),
|
50
|
+
[
|
51
|
+
param(Month(2000, 1), -2, Month(1999, 11)),
|
52
|
+
param(Month(2000, 1), -1, Month(1999, 12)),
|
53
|
+
param(Month(2000, 1), 0, Month(2000, 1)),
|
54
|
+
param(Month(2000, 1), 1, Month(2000, 2)),
|
55
|
+
param(Month(2000, 1), 2, Month(2000, 3)),
|
56
|
+
param(Month(2000, 1), 11, Month(2000, 12)),
|
57
|
+
param(Month(2000, 1), 12, Month(2001, 1)),
|
58
|
+
],
|
59
|
+
)
|
60
|
+
def test_add(self, *, month: Month, n: int, expected: Month) -> None:
|
61
|
+
result = month + n
|
62
|
+
assert result == expected
|
63
|
+
|
64
|
+
@mark.parametrize(
|
65
|
+
("x", "y", "expected"),
|
66
|
+
[
|
67
|
+
param(Month(2000, 1), Month(1999, 11), 2),
|
68
|
+
param(Month(2000, 1), Month(1999, 12), 1),
|
69
|
+
param(Month(2000, 1), Month(2000, 1), 0),
|
70
|
+
param(Month(2000, 1), Month(2000, 2), -1),
|
71
|
+
param(Month(2000, 1), Month(2000, 3), -2),
|
72
|
+
param(Month(2000, 1), Month(2000, 12), -11),
|
73
|
+
param(Month(2000, 1), Month(2001, 1), -12),
|
74
|
+
],
|
75
|
+
)
|
76
|
+
def test_diff(self, *, x: Month, y: Month, expected: int) -> None:
|
77
|
+
result = x - y
|
78
|
+
assert result == expected
|
79
|
+
|
80
|
+
@given(month=months())
|
81
|
+
def test_hashable(self, *, month: Month) -> None:
|
82
|
+
_ = hash(month)
|
83
|
+
|
84
|
+
@mark.parametrize("func", [param(repr), param(str)])
|
85
|
+
def test_repr(self, *, func: Callable[..., str]) -> None:
|
86
|
+
result = func(Month(2000, 12))
|
87
|
+
expected = "2000-12"
|
88
|
+
assert result == expected
|
89
|
+
|
90
|
+
@mark.parametrize(
|
91
|
+
("month", "n", "expected"),
|
92
|
+
[
|
93
|
+
param(Month(2000, 1), -2, Month(2000, 3)),
|
94
|
+
param(Month(2000, 1), -1, Month(2000, 2)),
|
95
|
+
param(Month(2000, 1), 0, Month(2000, 1)),
|
96
|
+
param(Month(2000, 1), 1, Month(1999, 12)),
|
97
|
+
param(Month(2000, 1), 2, Month(1999, 11)),
|
98
|
+
param(Month(2000, 1), 12, Month(1999, 1)),
|
99
|
+
param(Month(2000, 1), 13, Month(1998, 12)),
|
100
|
+
],
|
101
|
+
)
|
102
|
+
def test_subtract(self, *, month: Month, n: int, expected: Month) -> None:
|
103
|
+
result = month - n
|
104
|
+
assert result == expected
|
105
|
+
|
106
|
+
@given(date=dates())
|
107
|
+
def test_to_and_from_date(self, *, date: dt.date) -> None:
|
108
|
+
month = Month.from_date(date)
|
109
|
+
result = month.to_date(day=date.day)
|
110
|
+
assert result == date
|
111
|
+
|
112
|
+
def test_error(self) -> None:
|
113
|
+
with raises(MonthError, match=r"Invalid year and month: \d+, \d+"):
|
114
|
+
_ = Month(2000, 13)
|
115
|
+
|
116
|
+
|
117
|
+
class TestSerializeAndParseMonth:
|
118
|
+
@given(month=months())
|
119
|
+
def test_main(self, *, month: Month) -> None:
|
120
|
+
serialized = serialize_month(month)
|
121
|
+
result = parse_month(serialized)
|
122
|
+
assert result == month
|
123
|
+
|
124
|
+
def test_error_parse(self) -> None:
|
125
|
+
with raises(ParseMonthError, match="Unable to parse month; got 'invalid'"):
|
126
|
+
_ = parse_month("invalid")
|
127
|
+
|
128
|
+
@given(data=data(), month=months())
|
129
|
+
def test_ensure(self, *, data: DataObject, month: Month) -> None:
|
130
|
+
str_or_value = data.draw(sampled_from([month, serialize_month(month)]))
|
131
|
+
result = ensure_month(str_or_value)
|
132
|
+
assert result == month
|
133
|
+
|
134
|
+
def test_error_ensure(self) -> None:
|
135
|
+
with raises(EnsureMonthError, match="Unable to ensure month; got 'invalid'"):
|
136
|
+
_ = ensure_month("invalid")
|
137
|
+
|
138
|
+
|
139
|
+
class TestParseTwoDigitYear:
|
140
|
+
@given(data=data(), year=integers(0, 99))
|
141
|
+
def test_main(self, *, data: DataObject, year: int) -> None:
|
142
|
+
input_ = data.draw(sampled_from([year, str(year)]))
|
143
|
+
result = parse_two_digit_year(input_)
|
144
|
+
expected = (
|
145
|
+
dt.datetime.strptime(format(year, "02d"), "%y").replace(tzinfo=UTC).year
|
146
|
+
)
|
147
|
+
assert result == expected
|
148
|
+
|
149
|
+
@given(year=integers(max_value=-1) | integers(min_value=100))
|
150
|
+
def test_error_int(self, *, year: int) -> None:
|
151
|
+
with raises(
|
152
|
+
_ParseTwoDigitYearInvalidIntegerError, match="Unable to parse year; got .*"
|
153
|
+
):
|
154
|
+
_ = parse_two_digit_year(year)
|
155
|
+
|
156
|
+
@given(year=(integers(max_value=-1) | integers(min_value=100)).map(str))
|
157
|
+
def test_error_str(self, *, year: str) -> None:
|
158
|
+
with raises(
|
159
|
+
_ParseTwoDigitYearInvalidStringError, match="Unable to parse year; got .*"
|
160
|
+
):
|
161
|
+
_ = parse_two_digit_year(year)
|
@@ -24,14 +24,12 @@ from hypothesis.strategies import (
|
|
24
24
|
)
|
25
25
|
from pytest import raises
|
26
26
|
|
27
|
-
from utilities.datetime import ZERO_TIME, get_now, get_today
|
28
27
|
from utilities.errors import ImpossibleCaseError
|
29
28
|
from utilities.functions import (
|
30
29
|
EnsureBoolError,
|
31
30
|
EnsureBytesError,
|
32
31
|
EnsureClassError,
|
33
32
|
EnsureDateError,
|
34
|
-
EnsureDateTimeError,
|
35
33
|
EnsureFloatError,
|
36
34
|
EnsureHashableError,
|
37
35
|
EnsureIntError,
|
@@ -39,11 +37,13 @@ from utilities.functions import (
|
|
39
37
|
EnsureNotNoneError,
|
40
38
|
EnsureNumberError,
|
41
39
|
EnsurePathError,
|
40
|
+
EnsurePlainDateTimeError,
|
42
41
|
EnsureSizedError,
|
43
42
|
EnsureSizedNotStrError,
|
44
43
|
EnsureStrError,
|
45
44
|
EnsureTimeDeltaError,
|
46
45
|
EnsureTimeError,
|
46
|
+
EnsureZonedDateTimeError,
|
47
47
|
MaxNullableError,
|
48
48
|
MinNullableError,
|
49
49
|
apply_decorators,
|
@@ -51,7 +51,6 @@ from utilities.functions import (
|
|
51
51
|
ensure_bytes,
|
52
52
|
ensure_class,
|
53
53
|
ensure_date,
|
54
|
-
ensure_datetime,
|
55
54
|
ensure_float,
|
56
55
|
ensure_hashable,
|
57
56
|
ensure_int,
|
@@ -59,11 +58,13 @@ from utilities.functions import (
|
|
59
58
|
ensure_not_none,
|
60
59
|
ensure_number,
|
61
60
|
ensure_path,
|
61
|
+
ensure_plain_date_time,
|
62
62
|
ensure_sized,
|
63
63
|
ensure_sized_not_str,
|
64
64
|
ensure_str,
|
65
65
|
ensure_time,
|
66
|
-
|
66
|
+
ensure_time_delta,
|
67
|
+
ensure_zoned_date_time,
|
67
68
|
first,
|
68
69
|
get_class,
|
69
70
|
get_class_name,
|
@@ -94,11 +95,14 @@ from utilities.functions import (
|
|
94
95
|
yield_object_properties,
|
95
96
|
)
|
96
97
|
from utilities.sentinel import sentinel
|
98
|
+
from utilities.whenever2 import NOW_UTC, ZERO_TIME, get_now, get_today
|
97
99
|
|
98
100
|
if TYPE_CHECKING:
|
99
101
|
import datetime as dt
|
100
102
|
from collections.abc import Callable, Iterable
|
101
103
|
|
104
|
+
from whenever import PlainDateTime, TimeDelta, ZonedDateTime
|
105
|
+
|
102
106
|
from utilities.types import Number
|
103
107
|
|
104
108
|
|
@@ -212,24 +216,6 @@ class TestEnsureDate:
|
|
212
216
|
_ = ensure_date(sentinel, nullable=nullable)
|
213
217
|
|
214
218
|
|
215
|
-
class TestEnsureDateTime:
|
216
|
-
@given(case=sampled_from([(get_now(), False), (get_now(), True), (None, True)]))
|
217
|
-
def test_main(self, *, case: tuple[dt.datetime | None, bool]) -> None:
|
218
|
-
obj, nullable = case
|
219
|
-
_ = ensure_datetime(obj, nullable=nullable)
|
220
|
-
|
221
|
-
@given(
|
222
|
-
case=sampled_from([
|
223
|
-
(False, "Object '.*' of type '.*' must be a datetime"),
|
224
|
-
(True, "Object '.*' of type '.*' must be a datetime or None"),
|
225
|
-
])
|
226
|
-
)
|
227
|
-
def test_error(self, *, case: tuple[bool, str]) -> None:
|
228
|
-
nullable, match = case
|
229
|
-
with raises(EnsureDateTimeError, match=match):
|
230
|
-
_ = ensure_datetime(sentinel, nullable=nullable)
|
231
|
-
|
232
|
-
|
233
219
|
class TestEnsureFloat:
|
234
220
|
@given(case=sampled_from([(0.0, False), (0.0, True), (None, True)]))
|
235
221
|
def test_main(self, *, case: tuple[float | None, bool]) -> None:
|
@@ -355,6 +341,30 @@ class TestEnsurePath:
|
|
355
341
|
_ = ensure_path(sentinel, nullable=nullable)
|
356
342
|
|
357
343
|
|
344
|
+
class TestEnsurePlainDateTime:
|
345
|
+
@given(
|
346
|
+
case=sampled_from([
|
347
|
+
(NOW_UTC.to_plain(), False),
|
348
|
+
(NOW_UTC.to_plain(), True),
|
349
|
+
(None, True),
|
350
|
+
])
|
351
|
+
)
|
352
|
+
def test_main(self, *, case: tuple[PlainDateTime | None, bool]) -> None:
|
353
|
+
obj, nullable = case
|
354
|
+
_ = ensure_plain_date_time(obj, nullable=nullable)
|
355
|
+
|
356
|
+
@given(
|
357
|
+
case=sampled_from([
|
358
|
+
(False, "Object '.*' of type '.*' must be a plain date-time"),
|
359
|
+
(True, "Object '.*' of type '.*' must be a plain date-time or None"),
|
360
|
+
])
|
361
|
+
)
|
362
|
+
def test_error(self, *, case: tuple[bool, str]) -> None:
|
363
|
+
nullable, match = case
|
364
|
+
with raises(EnsurePlainDateTimeError, match=match):
|
365
|
+
_ = ensure_plain_date_time(sentinel, nullable=nullable)
|
366
|
+
|
367
|
+
|
358
368
|
class TestEnsureSized:
|
359
369
|
@given(obj=sampled_from([[], (), ""]))
|
360
370
|
def test_main(self, *, obj: Any) -> None:
|
@@ -423,20 +433,38 @@ class TestEnsureTime:
|
|
423
433
|
|
424
434
|
class TestEnsureTimeDelta:
|
425
435
|
@given(case=sampled_from([(ZERO_TIME, False), (ZERO_TIME, True), (None, True)]))
|
426
|
-
def test_main(self, *, case: tuple[
|
436
|
+
def test_main(self, *, case: tuple[TimeDelta | None, bool]) -> None:
|
427
437
|
obj, nullable = case
|
428
|
-
_ =
|
438
|
+
_ = ensure_time_delta(obj, nullable=nullable)
|
429
439
|
|
430
440
|
@given(
|
431
441
|
case=sampled_from([
|
432
|
-
(False, "Object '.*' of type '.*' must be a
|
433
|
-
(True, "Object '.*' of type '.*' must be a
|
442
|
+
(False, "Object '.*' of type '.*' must be a time-delta"),
|
443
|
+
(True, "Object '.*' of type '.*' must be a time-delta or None"),
|
434
444
|
])
|
435
445
|
)
|
436
446
|
def test_error(self, *, case: tuple[bool, str]) -> None:
|
437
447
|
nullable, match = case
|
438
448
|
with raises(EnsureTimeDeltaError, match=match):
|
439
|
-
_ =
|
449
|
+
_ = ensure_time_delta(sentinel, nullable=nullable)
|
450
|
+
|
451
|
+
|
452
|
+
class TestEnsureZonedDateTime:
|
453
|
+
@given(case=sampled_from([(NOW_UTC, False), (NOW_UTC, True), (None, True)]))
|
454
|
+
def test_main(self, *, case: tuple[ZonedDateTime | None, bool]) -> None:
|
455
|
+
obj, nullable = case
|
456
|
+
_ = ensure_zoned_date_time(obj, nullable=nullable)
|
457
|
+
|
458
|
+
@given(
|
459
|
+
case=sampled_from([
|
460
|
+
(False, "Object '.*' of type '.*' must be a zoned date-time"),
|
461
|
+
(True, "Object '.*' of type '.*' must be a zoned date-time or None"),
|
462
|
+
])
|
463
|
+
)
|
464
|
+
def test_error(self, *, case: tuple[bool, str]) -> None:
|
465
|
+
nullable, match = case
|
466
|
+
with raises(EnsureZonedDateTimeError, match=match):
|
467
|
+
_ = ensure_zoned_date_time(sentinel, nullable=nullable)
|
440
468
|
|
441
469
|
|
442
470
|
class TestFirst:
|
@@ -2,13 +2,13 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
from ipaddress import IPv4Address
|
4
4
|
|
5
|
-
from utilities.datetime import MINUTE
|
6
5
|
from utilities.http import get_public_ip, yield_connection
|
7
6
|
from utilities.pytest import throttle
|
7
|
+
from utilities.whenever2 import MINUTE
|
8
8
|
|
9
9
|
|
10
10
|
class TestGetPublicIP:
|
11
|
-
@throttle(
|
11
|
+
@throttle(delta=5 * MINUTE)
|
12
12
|
def test_main(self) -> None:
|
13
13
|
ip = get_public_ip(timeout=10.0)
|
14
14
|
assert isinstance(ip, IPv4Address)
|