dycw-utilities 0.155.4__tar.gz → 0.157.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.155.4 → dycw_utilities-0.157.0}/PKG-INFO +1 -1
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/pyproject.toml +3 -3
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_asyncio.py +2 -68
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_click.py +14 -87
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_eventkit.py +7 -3
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_logging.py +12 -6
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_os.py +6 -0
- dycw_utilities-0.157.0/src/tests/test_pottery.py +103 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_pytest.py +1 -6
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/__init__.py +1 -1
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/asyncio.py +1 -45
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/click.py +29 -15
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/eventkit.py +5 -2
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/logging.py +12 -4
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/os.py +10 -1
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/pottery.py +6 -90
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/pytest.py +0 -9
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/redis.py +1 -2
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/sqlalchemy.py +1 -2
- dycw_utilities-0.155.4/src/tests/test_pottery.py +0 -200
- dycw_utilities-0.155.4/src/tests/test_yield_access/script.py +0 -61
- dycw_utilities-0.155.4/src/tests/test_yield_access/script.sh +0 -54
- dycw_utilities-0.155.4/src/utilities/pytest_plugins/__init__.py +0 -1
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/.gitignore +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/LICENSE +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/README.md +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/__init__.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/conftest.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/modules/__init__.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/modules/package_missing/__init__.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/modules/package_missing/module.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/modules/package_with/__init__.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/modules/package_with/outer_1.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/modules/package_with/outer_2.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/modules/package_without/__init__.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/modules/package_without/module_1.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/modules/package_without/module_2.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/modules/standalone.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/modules/with_imports.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_altair.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_atomicwrites.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_atools.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_cachetools.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_concurrent.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_contextlib.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_contextvars.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_cryptography.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_cvxpy.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_dataclasses.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_enum.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_errors.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_fastapi.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_fpdf2.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_functions.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_functools.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_getpass.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_gzip.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_hashlib.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_http.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_hypothesis.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_importlib.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_inflect.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_ipython.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_iterables.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_json.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_jupyter.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_libcst.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_lightweight_charts.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_math.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_memory_profiler.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_modules.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_more_itertools.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_numpy.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_objects/__init__.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_objects/objects.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_operator.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_optuna.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_orjson.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_parse.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_pathlib.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_pickle.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_platform.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_polars.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_polars_ols.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_postgres.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_pqdm.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_psutil.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_pyinstrument.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_pytest_randomly.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_pytest_regressions.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_random.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_re.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_redis.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_reprlib.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_scipy.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_sentinel.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_shelve.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_slack_sdk.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_socket.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_sqlalchemy.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_statsmodels.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_string.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_tempfile.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_text.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_threading.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_timer.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_traceback.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_typed_settings.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_types.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_typing.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_typing_funcs/__init__.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_typing_funcs/no_future.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_typing_funcs/with_future.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_tzdata.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_tzlocal.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_uuid.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_version.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_warnings.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_whenever.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_zipfile.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/tests/test_zoneinfo.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/altair.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/atomicwrites.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/atools.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/cachetools.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/concurrent.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/contextlib.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/contextvars.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/cryptography.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/cvxpy.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/dataclasses.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/enum.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/errors.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/fastapi.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/fpdf2.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/functions.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/functools.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/getpass.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/gzip.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/hashlib.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/http.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/hypothesis.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/importlib.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/inflect.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/ipython.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/iterables.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/json.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/jupyter.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/libcst.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/lightweight_charts.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/math.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/memory_profiler.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/modules.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/more_itertools.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/numpy.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/operator.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/optuna.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/orjson.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/parse.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/pathlib.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/pickle.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/platform.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/polars.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/polars_ols.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/postgres.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/pqdm.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/psutil.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/py.typed +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/pyinstrument.py +0 -0
- {dycw_utilities-0.155.4/src/tests/test_yield_access → dycw_utilities-0.157.0/src/utilities/pytest_plugins}/__init__.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/pytest_plugins/pytest_randomly.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/pytest_plugins/pytest_regressions.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/pytest_regressions.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/random.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/re.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/reprlib.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/scipy.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/sentinel.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/shelve.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/slack_sdk.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/socket.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/statsmodels.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/string.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/tempfile.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/text.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/threading.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/timer.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/traceback.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/typed_settings.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/types.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/typing.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/tzdata.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/tzlocal.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/uuid.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/version.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/warnings.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/whenever.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/zipfile.py +0 -0
- {dycw_utilities-0.155.4 → dycw_utilities-0.157.0}/src/utilities/zoneinfo.py +0 -0
@@ -144,7 +144,7 @@ psutil = [
|
|
144
144
|
"psutil >=7.0.0, <7.1",
|
145
145
|
]
|
146
146
|
pyinstrument = [
|
147
|
-
"pyinstrument >=5.0
|
147
|
+
"pyinstrument >=5.1.0, <5.2",
|
148
148
|
]
|
149
149
|
pytest = [
|
150
150
|
"pytest >=8.4.1, <8.5",
|
@@ -227,7 +227,7 @@ dependencies = [
|
|
227
227
|
name = "dycw-utilities"
|
228
228
|
readme = "README.md"
|
229
229
|
requires-python = ">= 3.12"
|
230
|
-
version = "0.
|
230
|
+
version = "0.157.0"
|
231
231
|
|
232
232
|
[project.entry-points.pytest11]
|
233
233
|
pytest-randomly = "utilities.pytest_plugins.pytest_randomly"
|
@@ -259,7 +259,7 @@ test = [
|
|
259
259
|
# bump-my-version
|
260
260
|
[tool.bumpversion]
|
261
261
|
allow_dirty = true
|
262
|
-
current_version = "0.
|
262
|
+
current_version = "0.157.0"
|
263
263
|
|
264
264
|
[[tool.bumpversion.files]]
|
265
265
|
filename = "src/utilities/__init__.py"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
from asyncio import Queue,
|
3
|
+
from asyncio import Queue, run
|
4
4
|
from collections.abc import ItemsView, KeysView, ValuesView
|
5
5
|
from contextlib import asynccontextmanager
|
6
6
|
from re import search
|
@@ -8,7 +8,7 @@ from typing import TYPE_CHECKING, ClassVar
|
|
8
8
|
|
9
9
|
from hypothesis import HealthCheck, given, settings
|
10
10
|
from hypothesis.strategies import booleans, dictionaries, integers, lists, none
|
11
|
-
from pytest import
|
11
|
+
from pytest import RaisesGroup, raises
|
12
12
|
|
13
13
|
from utilities.asyncio import (
|
14
14
|
AsyncDict,
|
@@ -16,7 +16,6 @@ from utilities.asyncio import (
|
|
16
16
|
get_coroutine_name,
|
17
17
|
get_items,
|
18
18
|
get_items_nowait,
|
19
|
-
loop_until_succeed,
|
20
19
|
put_items,
|
21
20
|
put_items_nowait,
|
22
21
|
sleep_max,
|
@@ -29,7 +28,6 @@ from utilities.asyncio import (
|
|
29
28
|
)
|
30
29
|
from utilities.hypothesis import pairs, text_ascii
|
31
30
|
from utilities.pytest import skipif_windows
|
32
|
-
from utilities.text import unique_str
|
33
31
|
from utilities.timer import Timer
|
34
32
|
from utilities.whenever import MILLISECOND, SECOND, get_now
|
35
33
|
|
@@ -319,70 +317,6 @@ class TestGetItems:
|
|
319
317
|
assert result == xs[:max_size]
|
320
318
|
|
321
319
|
|
322
|
-
class TestLoopUntilSucceed:
|
323
|
-
@mark.parametrize("sleep", [param(MILLISECOND), param(None)])
|
324
|
-
@mark.parametrize("use_logger", [param(True), param(False)])
|
325
|
-
async def test_main(
|
326
|
-
self, *, caplog: LogCaptureFixture, sleep: TimeDelta | None, use_logger: bool
|
327
|
-
) -> None:
|
328
|
-
class CustomError(Exception): ...
|
329
|
-
|
330
|
-
caplog.set_level("DEBUG", logger=(name := unique_str()))
|
331
|
-
counter = 0
|
332
|
-
|
333
|
-
async def func() -> None:
|
334
|
-
nonlocal counter
|
335
|
-
counter += 1
|
336
|
-
if counter <= 3:
|
337
|
-
raise CustomError
|
338
|
-
|
339
|
-
assert await loop_until_succeed(
|
340
|
-
lambda: func(), logger=name if use_logger else None, sleep=sleep
|
341
|
-
)
|
342
|
-
assert counter == 4
|
343
|
-
|
344
|
-
if use_logger:
|
345
|
-
messages = [r.message for r in caplog.records if r.name == name]
|
346
|
-
expected = 3 * (
|
347
|
-
["Error running 'func'"]
|
348
|
-
+ ([] if sleep is None else ["Sleeping for PT0.001S..."])
|
349
|
-
+ ["Retrying 'func'..."]
|
350
|
-
)
|
351
|
-
assert messages == expected
|
352
|
-
|
353
|
-
async def test_error_flat(self) -> None:
|
354
|
-
class CustomError(Exception): ...
|
355
|
-
|
356
|
-
counter = 0
|
357
|
-
|
358
|
-
async def func() -> None:
|
359
|
-
nonlocal counter
|
360
|
-
counter += 1
|
361
|
-
if counter <= 3:
|
362
|
-
raise CustomError
|
363
|
-
|
364
|
-
assert not await loop_until_succeed(lambda: func(), errors=CustomError)
|
365
|
-
assert counter == 1
|
366
|
-
|
367
|
-
async def test_error_nested(self) -> None:
|
368
|
-
class CustomError(Exception): ...
|
369
|
-
|
370
|
-
counter = 0
|
371
|
-
|
372
|
-
async def func() -> None:
|
373
|
-
async with TaskGroup() as tg:
|
374
|
-
_ = tg.create_task(inner())
|
375
|
-
|
376
|
-
async def inner() -> None:
|
377
|
-
nonlocal counter
|
378
|
-
counter += 1
|
379
|
-
if counter <= 3:
|
380
|
-
raise CustomError
|
381
|
-
|
382
|
-
assert not await loop_until_succeed(lambda: func(), errors=CustomError)
|
383
|
-
assert counter == 1
|
384
|
-
|
385
|
-
|
386
320
|
class TestPutItems:
|
387
321
|
@given(xs=lists(integers(), min_size=1), wait=booleans())
|
388
322
|
async def test_main(self, *, xs: list[int], wait: bool) -> None:
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import enum
|
4
|
+
import pathlib
|
4
5
|
from dataclasses import dataclass
|
5
6
|
from enum import auto
|
6
7
|
from operator import attrgetter
|
@@ -30,11 +31,7 @@ from utilities.click import (
|
|
30
31
|
Date,
|
31
32
|
DateDelta,
|
32
33
|
DateTimeDelta,
|
33
|
-
DirPath,
|
34
34
|
Enum,
|
35
|
-
ExistingDirPath,
|
36
|
-
ExistingFilePath,
|
37
|
-
FilePath,
|
38
35
|
FrozenSetChoices,
|
39
36
|
FrozenSetEnums,
|
40
37
|
FrozenSetInts,
|
@@ -46,6 +43,7 @@ from utilities.click import (
|
|
46
43
|
ListInts,
|
47
44
|
ListStrs,
|
48
45
|
MonthDay,
|
46
|
+
Path,
|
49
47
|
PlainDateTime,
|
50
48
|
Time,
|
51
49
|
TimeDelta,
|
@@ -57,6 +55,7 @@ from utilities.hypothesis import (
|
|
57
55
|
date_time_deltas,
|
58
56
|
dates,
|
59
57
|
month_days,
|
58
|
+
paths,
|
60
59
|
plain_date_times,
|
61
60
|
text_ascii,
|
62
61
|
time_deltas,
|
@@ -68,7 +67,6 @@ from utilities.text import join_strs, strip_and_dedent
|
|
68
67
|
|
69
68
|
if TYPE_CHECKING:
|
70
69
|
from collections.abc import Callable, Iterable
|
71
|
-
from pathlib import Path
|
72
70
|
|
73
71
|
|
74
72
|
class TestContextSettingsHelpOptionNames:
|
@@ -81,91 +79,17 @@ class TestContextSettingsHelpOptionNames:
|
|
81
79
|
assert result.exit_code == 0
|
82
80
|
|
83
81
|
|
84
|
-
class
|
85
|
-
def
|
86
|
-
|
87
|
-
@argument("path", type=ExistingDirPath)
|
88
|
-
def cli(*, path: Path) -> None:
|
89
|
-
from pathlib import Path
|
90
|
-
|
91
|
-
assert isinstance(path, Path)
|
82
|
+
class TestPath:
|
83
|
+
def test_path(self, *, tmp_path: pathlib.Path) -> None:
|
84
|
+
path_use = pathlib.Path("~", tmp_path)
|
92
85
|
|
93
|
-
result = CliRunner().invoke(cli, [str(tmp_path)])
|
94
|
-
assert result.exit_code == 0
|
95
|
-
|
96
|
-
file_path = tmp_path.joinpath("file.txt")
|
97
|
-
file_path.touch()
|
98
|
-
result = CliRunner().invoke(cli, [str(file_path)])
|
99
|
-
assert result.exit_code == 2
|
100
|
-
assert search("is a file", result.stderr)
|
101
|
-
|
102
|
-
non_existent = tmp_path.joinpath("non-existent")
|
103
|
-
result = CliRunner().invoke(cli, [str(non_existent)])
|
104
|
-
assert result.exit_code == 2
|
105
|
-
assert search("does not exist", result.stderr)
|
106
|
-
|
107
|
-
def test_existing_file_path(self, *, tmp_path: Path) -> None:
|
108
86
|
@command()
|
109
|
-
@argument("path", type=
|
110
|
-
def cli(*, path: Path) -> None:
|
111
|
-
|
112
|
-
|
113
|
-
assert isinstance(path, Path)
|
87
|
+
@argument("path", type=Path())
|
88
|
+
def cli(*, path: pathlib.Path) -> None:
|
89
|
+
assert isinstance(path, pathlib.Path)
|
90
|
+
assert path == path.expanduser()
|
114
91
|
|
115
|
-
result = CliRunner().invoke(cli, [str(
|
116
|
-
assert result.exit_code == 2
|
117
|
-
assert search("is a directory", result.stderr)
|
118
|
-
|
119
|
-
file_path = tmp_path.joinpath("file.txt")
|
120
|
-
file_path.touch()
|
121
|
-
result = CliRunner().invoke(cli, [str(file_path)])
|
122
|
-
assert result.exit_code == 0
|
123
|
-
|
124
|
-
non_existent = tmp_path.joinpath("non-existent")
|
125
|
-
result = CliRunner().invoke(cli, [str(non_existent)])
|
126
|
-
assert result.exit_code == 2
|
127
|
-
assert search("does not exist", result.stderr)
|
128
|
-
|
129
|
-
def test_dir_path(self, *, tmp_path: Path) -> None:
|
130
|
-
@command()
|
131
|
-
@argument("path", type=DirPath)
|
132
|
-
def cli(*, path: Path) -> None:
|
133
|
-
from pathlib import Path
|
134
|
-
|
135
|
-
assert isinstance(path, Path)
|
136
|
-
|
137
|
-
result = CliRunner().invoke(cli, [str(tmp_path)])
|
138
|
-
assert result.exit_code == 0
|
139
|
-
|
140
|
-
file_path = tmp_path.joinpath("file.txt")
|
141
|
-
file_path.touch()
|
142
|
-
result = CliRunner().invoke(cli, [str(file_path)])
|
143
|
-
assert result.exit_code == 2
|
144
|
-
assert search("is a file", result.stderr)
|
145
|
-
|
146
|
-
non_existent = tmp_path.joinpath("non-existent")
|
147
|
-
result = CliRunner().invoke(cli, [str(non_existent)])
|
148
|
-
assert result.exit_code == 0
|
149
|
-
|
150
|
-
def test_file_path(self, *, tmp_path: Path) -> None:
|
151
|
-
@command()
|
152
|
-
@argument("path", type=FilePath)
|
153
|
-
def cli(*, path: Path) -> None:
|
154
|
-
from pathlib import Path
|
155
|
-
|
156
|
-
assert isinstance(path, Path)
|
157
|
-
|
158
|
-
result = CliRunner().invoke(cli, [str(tmp_path)])
|
159
|
-
assert result.exit_code == 2
|
160
|
-
assert search("is a directory", result.stderr)
|
161
|
-
|
162
|
-
file_path = tmp_path.joinpath("file.txt")
|
163
|
-
file_path.touch()
|
164
|
-
result = CliRunner().invoke(cli, [str(file_path)])
|
165
|
-
assert result.exit_code == 0
|
166
|
-
|
167
|
-
non_existent = tmp_path.joinpath("non-existent")
|
168
|
-
result = CliRunner().invoke(cli, [str(non_existent)])
|
92
|
+
result = CliRunner().invoke(cli, [str(path_use)])
|
169
93
|
assert result.exit_code == 0
|
170
94
|
|
171
95
|
|
@@ -301,6 +225,9 @@ class TestParameters:
|
|
301
225
|
serialize=whenever.MonthDay.format_common_iso,
|
302
226
|
failable=True,
|
303
227
|
),
|
228
|
+
_Case(
|
229
|
+
param=Path(), name="path", strategy=paths(), serialize=str, failable=False
|
230
|
+
),
|
304
231
|
_Case(
|
305
232
|
param=PlainDateTime(),
|
306
233
|
name="plain date-time",
|
@@ -65,13 +65,17 @@ class TestAddListener:
|
|
65
65
|
|
66
66
|
def listener_sync() -> None: ...
|
67
67
|
|
68
|
-
_ = add_listener(
|
68
|
+
_ = add_listener(
|
69
|
+
event, listener_sync, logger=str(root), logger_allow_pytest=True
|
70
|
+
)
|
69
71
|
case "async":
|
70
72
|
|
71
73
|
async def listener_async() -> None:
|
72
74
|
await sleep(0.01)
|
73
75
|
|
74
|
-
_ = add_listener(
|
76
|
+
_ = add_listener(
|
77
|
+
event, listener_async, logger=str(root), logger_allow_pytest=True
|
78
|
+
)
|
75
79
|
|
76
80
|
event.emit(None)
|
77
81
|
await sleep(0.01)
|
@@ -233,7 +237,7 @@ class TestLiftListener:
|
|
233
237
|
LiftListenerError,
|
234
238
|
match="Synchronous listener .* cannot be paired with an asynchronous error handler .*",
|
235
239
|
):
|
236
|
-
_ = lift_listener(listener, Event(), error=error)
|
240
|
+
_ = lift_listener(listener, Event(), error=error, logger_allow_pytest=True)
|
237
241
|
|
238
242
|
|
239
243
|
class TestLiftedEvent:
|
@@ -12,7 +12,7 @@ from hypothesis.strategies import booleans, integers
|
|
12
12
|
from pytest import LogCaptureFixture, mark, param, raises
|
13
13
|
|
14
14
|
from tests.conftest import SKIPIF_CI_AND_WINDOWS
|
15
|
-
from utilities.hypothesis import pairs, temp_paths,
|
15
|
+
from utilities.hypothesis import pairs, temp_paths, zoned_date_times
|
16
16
|
from utilities.iterables import one
|
17
17
|
from utilities.logging import (
|
18
18
|
GetLoggingLevelNumberError,
|
@@ -78,7 +78,7 @@ class TestBasicConfig:
|
|
78
78
|
) -> None:
|
79
79
|
name = unique_str()
|
80
80
|
with set_log_factory:
|
81
|
-
basic_config(obj=name, filters=filters, plain=plain)
|
81
|
+
basic_config(obj=name, filters=filters, plain=plain, allow_pytest=True)
|
82
82
|
getLogger(name).warning("message")
|
83
83
|
record = one(r for r in caplog.records if r.name == name)
|
84
84
|
assert record.message == "message"
|
@@ -527,13 +527,19 @@ class TestToLogger:
|
|
527
527
|
def test_default(self) -> None:
|
528
528
|
assert to_logger().name == "root"
|
529
529
|
|
530
|
-
|
531
|
-
|
530
|
+
def test_logger(self) -> None:
|
531
|
+
name = unique_str()
|
532
532
|
assert to_logger(getLogger(name)).name == name
|
533
533
|
|
534
|
-
|
535
|
-
|
534
|
+
def test_str(self) -> None:
|
535
|
+
name = unique_str()
|
536
536
|
assert to_logger(name).name == name
|
537
537
|
|
538
|
+
@mark.parametrize(("allow_pytest", "expected"), [param(False, 1), param(True, 0)])
|
539
|
+
def test_allow_pytest(self, *, allow_pytest: bool, expected: int) -> None:
|
540
|
+
name = unique_str()
|
541
|
+
logger = to_logger(name, allow_pytest=allow_pytest)
|
542
|
+
assert len(logger.filters) == expected
|
543
|
+
|
538
544
|
def test_none(self) -> None:
|
539
545
|
assert to_logger(None).name == "root"
|
@@ -22,6 +22,7 @@ from utilities.os import (
|
|
22
22
|
get_cpu_use,
|
23
23
|
get_env_var,
|
24
24
|
is_debug,
|
25
|
+
is_pytest,
|
25
26
|
temp_environ,
|
26
27
|
)
|
27
28
|
from utilities.pytest import skipif_windows
|
@@ -124,6 +125,11 @@ class TestIsDebug:
|
|
124
125
|
assert isinstance(result, bool)
|
125
126
|
|
126
127
|
|
128
|
+
class TestIsPytest:
|
129
|
+
def test_main(self) -> None:
|
130
|
+
assert is_pytest()
|
131
|
+
|
132
|
+
|
127
133
|
class TestTempEnviron:
|
128
134
|
@given(key=text.map(_prefix), value=text)
|
129
135
|
def test_set(self, *, key: str, value: str) -> None:
|
@@ -0,0 +1,103 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from asyncio import TaskGroup
|
4
|
+
from typing import TYPE_CHECKING, ClassVar
|
5
|
+
|
6
|
+
from pottery import AIORedlock
|
7
|
+
from pytest import mark, param, raises
|
8
|
+
|
9
|
+
from utilities.asyncio import sleep_td
|
10
|
+
from utilities.pottery import (
|
11
|
+
_YieldAccessNumLocksError,
|
12
|
+
_YieldAccessUnableToAcquireLockError,
|
13
|
+
extend_lock,
|
14
|
+
yield_access,
|
15
|
+
)
|
16
|
+
from utilities.text import unique_str
|
17
|
+
from utilities.timer import Timer
|
18
|
+
from utilities.whenever import SECOND
|
19
|
+
|
20
|
+
if TYPE_CHECKING:
|
21
|
+
from redis.asyncio import Redis
|
22
|
+
from whenever import TimeDelta
|
23
|
+
|
24
|
+
|
25
|
+
class TestExtendLock:
|
26
|
+
async def test_main(self, *, test_redis: Redis) -> None:
|
27
|
+
lock = AIORedlock(key=unique_str(), masters={test_redis})
|
28
|
+
async with lock:
|
29
|
+
await extend_lock(lock=lock)
|
30
|
+
|
31
|
+
async def test_none(self) -> None:
|
32
|
+
await extend_lock()
|
33
|
+
|
34
|
+
|
35
|
+
class TestYieldAccess:
|
36
|
+
delta: ClassVar[TimeDelta] = 0.1 * SECOND
|
37
|
+
|
38
|
+
@mark.parametrize(
|
39
|
+
("num_tasks", "num_locks", "min_multiple"),
|
40
|
+
[
|
41
|
+
param(1, 1, 1),
|
42
|
+
param(1, 2, 1),
|
43
|
+
param(1, 3, 1),
|
44
|
+
param(2, 1, 2),
|
45
|
+
param(2, 2, 1),
|
46
|
+
param(2, 3, 1),
|
47
|
+
param(2, 4, 1),
|
48
|
+
param(2, 5, 1),
|
49
|
+
param(3, 1, 3),
|
50
|
+
param(3, 2, 2),
|
51
|
+
param(3, 3, 1),
|
52
|
+
param(3, 4, 1),
|
53
|
+
param(3, 5, 1),
|
54
|
+
param(4, 1, 4),
|
55
|
+
param(4, 2, 2),
|
56
|
+
param(4, 3, 2),
|
57
|
+
param(4, 4, 1),
|
58
|
+
param(4, 5, 1),
|
59
|
+
],
|
60
|
+
)
|
61
|
+
async def test_main(
|
62
|
+
self, *, test_redis: Redis, num_tasks: int, num_locks: int, min_multiple: int
|
63
|
+
) -> None:
|
64
|
+
with Timer() as timer:
|
65
|
+
await self.func(test_redis, num_tasks, unique_str(), num_locks=num_locks)
|
66
|
+
assert (min_multiple * self.delta) <= timer <= (5 * min_multiple * self.delta)
|
67
|
+
|
68
|
+
async def test_error_num_locks(self, *, test_redis: Redis) -> None:
|
69
|
+
with raises(
|
70
|
+
_YieldAccessNumLocksError,
|
71
|
+
match=r"Number of locks for '\w+' must be positive; got 0",
|
72
|
+
):
|
73
|
+
async with yield_access(test_redis, unique_str(), num=0):
|
74
|
+
...
|
75
|
+
|
76
|
+
async def test_error_unable_to_acquire_lock(self, *, test_redis: Redis) -> None:
|
77
|
+
key = unique_str()
|
78
|
+
delta = 0.1 * SECOND
|
79
|
+
|
80
|
+
async def coroutine(key: str, /) -> None:
|
81
|
+
async with yield_access(
|
82
|
+
test_redis, key, num=1, timeout_acquire=delta, throttle=5 * delta
|
83
|
+
):
|
84
|
+
await sleep_td(delta)
|
85
|
+
|
86
|
+
with raises(ExceptionGroup) as exc_info:
|
87
|
+
async with TaskGroup() as tg:
|
88
|
+
_ = tg.create_task(coroutine(key))
|
89
|
+
_ = tg.create_task(coroutine(key))
|
90
|
+
assert exc_info.group_contains(
|
91
|
+
_YieldAccessUnableToAcquireLockError,
|
92
|
+
match=r"Unable to acquire any 1 of 1 locks for '\w+' after .*",
|
93
|
+
)
|
94
|
+
|
95
|
+
async def func(
|
96
|
+
self, redis: Redis, num_tasks: int, key: str, /, *, num_locks: int = 1
|
97
|
+
) -> None:
|
98
|
+
async def coroutine() -> None:
|
99
|
+
async with yield_access(redis, key, num=num_locks):
|
100
|
+
await sleep_td(self.delta)
|
101
|
+
|
102
|
+
async with TaskGroup() as tg:
|
103
|
+
_ = [tg.create_task(coroutine()) for _ in range(num_tasks)]
|
@@ -9,7 +9,7 @@ from pytest import fixture, mark, param, raises
|
|
9
9
|
|
10
10
|
from utilities.iterables import one
|
11
11
|
from utilities.os import temp_environ
|
12
|
-
from utilities.pytest import NodeIdToPathError,
|
12
|
+
from utilities.pytest import NodeIdToPathError, node_id_path, throttle
|
13
13
|
|
14
14
|
if TYPE_CHECKING:
|
15
15
|
from collections.abc import Sequence
|
@@ -25,11 +25,6 @@ def set_asyncio_default_fixture_loop_scope(*, testdir: Testdir) -> None:
|
|
25
25
|
""")
|
26
26
|
|
27
27
|
|
28
|
-
class TestIsPytest:
|
29
|
-
def test_main(self) -> None:
|
30
|
-
assert is_pytest()
|
31
|
-
|
32
|
-
|
33
28
|
class TestNodeIdPath:
|
34
29
|
@mark.parametrize(
|
35
30
|
("node_id", "expected"),
|
@@ -1,7 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import asyncio
|
4
|
-
import sys
|
5
4
|
from asyncio import (
|
6
5
|
Lock,
|
7
6
|
Queue,
|
@@ -36,9 +35,8 @@ from typing import (
|
|
36
35
|
override,
|
37
36
|
)
|
38
37
|
|
39
|
-
from utilities.errors import ImpossibleCaseError, is_instance_error
|
40
38
|
from utilities.functions import ensure_int, ensure_not_none
|
41
|
-
from utilities.
|
39
|
+
from utilities.os import is_pytest
|
42
40
|
from utilities.random import SYSTEM_RANDOM
|
43
41
|
from utilities.sentinel import Sentinel, sentinel
|
44
42
|
from utilities.shelve import yield_shelf
|
@@ -70,8 +68,6 @@ if TYPE_CHECKING:
|
|
70
68
|
from utilities.types import (
|
71
69
|
Coro,
|
72
70
|
Delta,
|
73
|
-
ExceptionTypeLike,
|
74
|
-
LoggerLike,
|
75
71
|
MaybeCallableBoolLike,
|
76
72
|
MaybeType,
|
77
73
|
PathLike,
|
@@ -369,8 +365,6 @@ async def get_items[T](queue: Queue[T], /, *, max_size: int | None = None) -> li
|
|
369
365
|
try:
|
370
366
|
items = [await queue.get()]
|
371
367
|
except RuntimeError as error: # pragma: no cover
|
372
|
-
from utilities.pytest import is_pytest
|
373
|
-
|
374
368
|
if (not is_pytest()) or (error.args[0] != "Event loop is closed"):
|
375
369
|
raise
|
376
370
|
return []
|
@@ -400,43 +394,6 @@ def get_items_nowait[T](queue: Queue[T], /, *, max_size: int | None = None) -> l
|
|
400
394
|
##
|
401
395
|
|
402
396
|
|
403
|
-
async def loop_until_succeed(
|
404
|
-
func: Callable[[], Coro[None]],
|
405
|
-
/,
|
406
|
-
*,
|
407
|
-
logger: LoggerLike | None = None,
|
408
|
-
errors: ExceptionTypeLike[Exception] | None = None,
|
409
|
-
sleep: Delta | None = None,
|
410
|
-
) -> bool:
|
411
|
-
"""Repeatedly call a coroutine until it succeeds."""
|
412
|
-
name = get_coroutine_name(func)
|
413
|
-
while True:
|
414
|
-
try:
|
415
|
-
await func()
|
416
|
-
except Exception as error: # noqa: BLE001
|
417
|
-
if logger is not None:
|
418
|
-
to_logger(logger).error("Error running %r", name, exc_info=True)
|
419
|
-
exc_type, exc_value, traceback = sys.exc_info()
|
420
|
-
if (exc_type is None) or (exc_value is None): # pragma: no cover
|
421
|
-
raise ImpossibleCaseError(
|
422
|
-
case=[f"{exc_type=}", f"{exc_value=}"]
|
423
|
-
) from None
|
424
|
-
sys.excepthook(exc_type, exc_value, traceback)
|
425
|
-
if (errors is not None) and is_instance_error(error, errors):
|
426
|
-
return False
|
427
|
-
if sleep is not None:
|
428
|
-
if logger is not None:
|
429
|
-
to_logger(logger).info("Sleeping for %s...", sleep)
|
430
|
-
await sleep_td(sleep)
|
431
|
-
if logger is not None:
|
432
|
-
to_logger(logger).info("Retrying %r...", name)
|
433
|
-
else:
|
434
|
-
return True
|
435
|
-
|
436
|
-
|
437
|
-
##
|
438
|
-
|
439
|
-
|
440
397
|
async def put_items[T](items: Iterable[T], queue: Queue[T], /) -> None:
|
441
398
|
"""Put items into a queue; if full then wait."""
|
442
399
|
for item in items:
|
@@ -589,7 +546,6 @@ __all__ = [
|
|
589
546
|
"get_coroutine_name",
|
590
547
|
"get_items",
|
591
548
|
"get_items_nowait",
|
592
|
-
"loop_until_succeed",
|
593
549
|
"put_items",
|
594
550
|
"put_items_nowait",
|
595
551
|
"sleep_max",
|
@@ -6,7 +6,6 @@ import pathlib
|
|
6
6
|
import uuid
|
7
7
|
from typing import TYPE_CHECKING, TypedDict, assert_never, override
|
8
8
|
|
9
|
-
import click
|
10
9
|
import whenever
|
11
10
|
from click import Choice, Context, Parameter, ParamType
|
12
11
|
from click.types import IntParamType, StringParamType
|
@@ -29,6 +28,7 @@ if TYPE_CHECKING:
|
|
29
28
|
IPv6AddressLike,
|
30
29
|
MaybeStr,
|
31
30
|
MonthDayLike,
|
31
|
+
PathLike,
|
32
32
|
PlainDateTimeLike,
|
33
33
|
TimeDeltaLike,
|
34
34
|
TimeLike,
|
@@ -37,16 +37,6 @@ if TYPE_CHECKING:
|
|
37
37
|
)
|
38
38
|
|
39
39
|
|
40
|
-
FilePath = click.Path(file_okay=True, dir_okay=False, path_type=pathlib.Path)
|
41
|
-
DirPath = click.Path(file_okay=False, dir_okay=True, path_type=pathlib.Path)
|
42
|
-
ExistingFilePath = click.Path(
|
43
|
-
exists=True, file_okay=True, dir_okay=False, path_type=pathlib.Path
|
44
|
-
)
|
45
|
-
ExistingDirPath = click.Path(
|
46
|
-
exists=True, file_okay=False, dir_okay=True, path_type=pathlib.Path
|
47
|
-
)
|
48
|
-
|
49
|
-
|
50
40
|
class _HelpOptionNames(TypedDict):
|
51
41
|
help_option_names: Sequence[str]
|
52
42
|
|
@@ -252,6 +242,32 @@ class MonthDay(ParamType):
|
|
252
242
|
assert_never(never)
|
253
243
|
|
254
244
|
|
245
|
+
class Path(ParamType):
|
246
|
+
"""A path-valued parameter."""
|
247
|
+
|
248
|
+
name = "path"
|
249
|
+
|
250
|
+
@override
|
251
|
+
def __repr__(self) -> str:
|
252
|
+
return self.name.upper()
|
253
|
+
|
254
|
+
@override
|
255
|
+
def convert(
|
256
|
+
self, value: PathLike, param: Parameter | None, ctx: Context | None
|
257
|
+
) -> pathlib.Path:
|
258
|
+
"""Convert a value into the `Path` type."""
|
259
|
+
match value:
|
260
|
+
case pathlib.Path():
|
261
|
+
return value.expanduser()
|
262
|
+
case str():
|
263
|
+
try:
|
264
|
+
return pathlib.Path(value).expanduser()
|
265
|
+
except ValueError as error:
|
266
|
+
self.fail(str(error), param, ctx)
|
267
|
+
case never:
|
268
|
+
assert_never(never)
|
269
|
+
|
270
|
+
|
255
271
|
class PlainDateTime(ParamType):
|
256
272
|
"""A local-datetime-valued parameter."""
|
257
273
|
|
@@ -592,11 +608,7 @@ __all__ = [
|
|
592
608
|
"Date",
|
593
609
|
"DateDelta",
|
594
610
|
"DateTimeDelta",
|
595
|
-
"DirPath",
|
596
611
|
"Enum",
|
597
|
-
"ExistingDirPath",
|
598
|
-
"ExistingFilePath",
|
599
|
-
"FilePath",
|
600
612
|
"FrozenSetChoices",
|
601
613
|
"FrozenSetEnums",
|
602
614
|
"FrozenSetParameter",
|
@@ -609,6 +621,8 @@ __all__ = [
|
|
609
621
|
"ListParameter",
|
610
622
|
"ListStrs",
|
611
623
|
"MonthDay",
|
624
|
+
"Path",
|
625
|
+
"Path",
|
612
626
|
"PlainDateTime",
|
613
627
|
"Time",
|
614
628
|
"TimeDelta",
|