dycw-utilities 0.129.15__tar.gz → 0.130.1__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.129.15 → dycw_utilities-0.130.1}/PKG-INFO +1 -3
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/pyproject.toml +5 -5
- dycw_utilities-0.130.1/src/tests/conftest.py +27 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_logging.py +98 -193
- dycw_utilities-0.130.1/src/tests/test_traceback.py +144 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_whenever.py +3 -2
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/__init__.py +1 -1
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/logging.py +276 -498
- dycw_utilities-0.130.1/src/utilities/traceback.py +287 -0
- dycw_utilities-0.129.15/src/tests/conftest.py +0 -369
- dycw_utilities-0.129.15/src/tests/test_loguru.py +0 -139
- dycw_utilities-0.129.15/src/tests/test_sys.py +0 -134
- dycw_utilities-0.129.15/src/tests/test_traceback.py +0 -725
- dycw_utilities-0.129.15/src/tests/test_traceback_funcs/__init__.py +0 -1
- dycw_utilities-0.129.15/src/tests/test_traceback_funcs/chain.py +0 -31
- dycw_utilities-0.129.15/src/tests/test_traceback_funcs/decorated_async.py +0 -89
- dycw_utilities-0.129.15/src/tests/test_traceback_funcs/decorated_sync.py +0 -93
- dycw_utilities-0.129.15/src/tests/test_traceback_funcs/error_bind.py +0 -17
- dycw_utilities-0.129.15/src/tests/test_traceback_funcs/many.py +0 -17
- dycw_utilities-0.129.15/src/tests/test_traceback_funcs/one.py +0 -17
- dycw_utilities-0.129.15/src/tests/test_traceback_funcs/recursive.py +0 -19
- dycw_utilities-0.129.15/src/tests/test_traceback_funcs/task_group_one.py +0 -34
- dycw_utilities-0.129.15/src/tests/test_traceback_funcs/task_group_two.py +0 -43
- dycw_utilities-0.129.15/src/tests/test_traceback_funcs/two.py +0 -27
- dycw_utilities-0.129.15/src/tests/test_traceback_funcs/untraced.py +0 -14
- dycw_utilities-0.129.15/src/utilities/loguru.py +0 -144
- dycw_utilities-0.129.15/src/utilities/sys.py +0 -87
- dycw_utilities-0.129.15/src/utilities/traceback.py +0 -1086
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/.gitignore +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/LICENSE +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/README.md +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/__init__.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/__init__.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_missing/__init__.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_missing/module.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_with/__init__.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_with/outer_1.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_with/outer_2.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_without/__init__.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_without/module_1.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/package_without/module_2.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/standalone.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/modules/with_imports.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_aiolimiter.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_altair.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_asyncio.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_asyncio_classes/__init__.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_asyncio_classes/loopers.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_asyncio_classes/redis.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_atomicwrites.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_atools.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_cachetools.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_click.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_concurrent.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_contextlib.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_contextvars.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_cryptography.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_cvxpy.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_dataclasses.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_datetime.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_enum.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_errors.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_eventkit.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_fastapi.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_fpdf2.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_functions.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_functools.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_getpass.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_git.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_hashlib.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_http.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_hypothesis.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_importlib.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_inflect.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_ipython.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_iterables.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_jupyter.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_libcst.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_lightweight_charts.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_luigi.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_math.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_memory_profiler.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_modules.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_more_itertools.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_numpy.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_operator.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_optuna.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_orjson.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_os.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_parse.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pathlib.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_period.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pickle.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_platform.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_polars.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_polars_ols.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pottery.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pqdm.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_psutil.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pydantic.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pyinstrument.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pyrsistent.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pytest.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_pytest_regressions.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_python_dotenv.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_random.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_re.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_redis.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_reprlib.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_scipy.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_sentinel.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_shelve.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_slack_sdk.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_socket.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_sqlalchemy.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_statsmodel.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_streamlit.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_string.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_tempfile.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_tenacity.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_text.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_threading.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_timer.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_types.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_typing.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_typing_funcs/__init__.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_typing_funcs/no_future.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_typing_funcs/with_future.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_tzdata.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_tzlocal.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_uuid.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_version.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_warnings.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_zipfile.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/tests/test_zoneinfo.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/aiolimiter.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/altair.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/asyncio.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/atomicwrites.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/atools.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/cachetools.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/click.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/concurrent.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/contextlib.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/contextvars.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/cryptography.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/cvxpy.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/dataclasses.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/datetime.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/enum.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/errors.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/eventkit.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/fastapi.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/fpdf2.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/functions.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/functools.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/getpass.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/git.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/hashlib.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/http.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/hypothesis.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/importlib.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/inflect.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/ipython.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/iterables.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/jupyter.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/libcst.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/lightweight_charts.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/luigi.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/math.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/memory_profiler.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/modules.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/more_itertools.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/numpy.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/operator.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/optuna.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/orjson.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/os.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/parse.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pathlib.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/period.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pickle.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/platform.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/polars.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/polars_ols.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pottery.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pqdm.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/psutil.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/py.typed +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pydantic.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pyinstrument.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pyrsistent.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pytest.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/pytest_regressions.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/python_dotenv.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/random.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/re.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/redis.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/reprlib.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/scipy.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/sentinel.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/shelve.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/slack_sdk.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/socket.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/sqlalchemy.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/statsmodels.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/streamlit.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/string.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/tempfile.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/tenacity.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/text.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/threading.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/timer.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/types.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/typing.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/tzdata.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/tzlocal.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/uuid.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/version.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/warnings.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/whenever.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/zipfile.py +0 -0
- {dycw_utilities-0.129.15 → dycw_utilities-0.130.1}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: dycw-utilities
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.130.1
|
4
4
|
Author-email: Derek Wan <d.wan@icloud.com>
|
5
5
|
License-File: LICENSE
|
6
6
|
Requires-Python: >=3.12
|
@@ -109,8 +109,6 @@ Requires-Dist: rich<14.1,>=14.0.0; extra == 'zzz-test-logging'
|
|
109
109
|
Requires-Dist: tomlkit<0.14,>=0.13.2; extra == 'zzz-test-logging'
|
110
110
|
Requires-Dist: tzlocal<5.4,>=5.3.1; extra == 'zzz-test-logging'
|
111
111
|
Requires-Dist: whenever<0.9,>=0.8.5; extra == 'zzz-test-logging'
|
112
|
-
Provides-Extra: zzz-test-loguru
|
113
|
-
Requires-Dist: loguru<0.8,>=0.7.3; extra == 'zzz-test-loguru'
|
114
112
|
Provides-Extra: zzz-test-luigi
|
115
113
|
Requires-Dist: luigi<3.7,>=3.6.0; extra == 'zzz-test-luigi'
|
116
114
|
Requires-Dist: whenever<0.9,>=0.8.5; extra == 'zzz-test-luigi'
|
@@ -29,7 +29,6 @@ dev = [
|
|
29
29
|
"img2pdf >= 0.6.0, < 0.7",
|
30
30
|
"inflect >= 7.5.0, < 7.6",
|
31
31
|
"lightweight-charts >= 2.1, < 2.2",
|
32
|
-
"loguru >= 0.7.3, < 0.8",
|
33
32
|
"luigi >= 3.6.0, < 3.7",
|
34
33
|
"memory-profiler >= 0.61.0, < 0.62",
|
35
34
|
"more-itertools >= 10.7.0, < 10.8",
|
@@ -83,7 +82,6 @@ dev = [
|
|
83
82
|
"pytest-timeout >= 2.4.0, < 2.5",
|
84
83
|
"pytest-xdist >= 3.7.0, < 3.8",
|
85
84
|
# CI
|
86
|
-
"win32_setctime >= 1.2.0, < 1.3", # https://github.com/Delgan/loguru/issues/147
|
87
85
|
"aiolimiter>=1.2.1",
|
88
86
|
]
|
89
87
|
|
@@ -96,7 +94,7 @@ dependencies = [
|
|
96
94
|
name = "dycw-utilities"
|
97
95
|
readme = "README.md"
|
98
96
|
requires-python = ">= 3.12"
|
99
|
-
version = "0.
|
97
|
+
version = "0.130.1"
|
100
98
|
|
101
99
|
[project.optional-dependencies]
|
102
100
|
logging = [
|
@@ -213,7 +211,6 @@ zzz-test-logging = [
|
|
213
211
|
"tzlocal >= 5.3.1, < 5.4",
|
214
212
|
"whenever >= 0.8.5, < 0.9",
|
215
213
|
]
|
216
|
-
zzz-test-loguru = ["loguru >= 0.7.3, < 0.8"]
|
217
214
|
zzz-test-luigi = [
|
218
215
|
"luigi >= 3.6.0, < 3.7",
|
219
216
|
"whenever >= 0.8.5, < 0.9",
|
@@ -344,7 +341,7 @@ zzz-test-zoneinfo = [
|
|
344
341
|
# bump-my-version
|
345
342
|
[tool.bumpversion]
|
346
343
|
allow_dirty = true
|
347
|
-
current_version = "0.
|
344
|
+
current_version = "0.130.1"
|
348
345
|
|
349
346
|
[[tool.bumpversion.files]]
|
350
347
|
filename = "src/utilities/__init__.py"
|
@@ -464,6 +461,7 @@ filterwarnings = [
|
|
464
461
|
"ignore:unclosed <socket.*socket .*>:ResourceWarning", # redis
|
465
462
|
"ignore:unclosed Connection <redis.*asyncio.*connection.*Connection.*>:ResourceWarning", # redis
|
466
463
|
"ignore:unclosed event loop <_UnixSelectorEventLoop .*>:ResourceWarning", # redis
|
464
|
+
"ignore:unclosed file <_io.*TextIOWrapper .*>:ResourceWarning", # logging
|
467
465
|
"ignore:unclosed transport <_SelectorSocketTransport .*>:ResourceWarning", # redis
|
468
466
|
]
|
469
467
|
minversion = "8.0"
|
@@ -478,6 +476,7 @@ unsafe-fixes = true
|
|
478
476
|
|
479
477
|
[tool.ruff.format]
|
480
478
|
preview = true
|
479
|
+
skip-magic-trailing-comma = true
|
481
480
|
|
482
481
|
[tool.ruff.lint]
|
483
482
|
explicit-preview-rules = true
|
@@ -545,3 +544,4 @@ ban-relative-imports = "all"
|
|
545
544
|
|
546
545
|
[tool.ruff.lint.isort]
|
547
546
|
required-imports = ["from __future__ import annotations"]
|
547
|
+
split-on-trailing-comma = false
|
@@ -0,0 +1,27 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from os import environ
|
4
|
+
|
5
|
+
from pytest import mark
|
6
|
+
|
7
|
+
from utilities.platform import IS_NOT_LINUX, IS_WINDOWS
|
8
|
+
|
9
|
+
FLAKY = mark.flaky(reruns=5, reruns_delay=1)
|
10
|
+
IS_CI = "CI" in environ
|
11
|
+
SKIPIF_CI = mark.skipif(IS_CI, reason="Skipped for CI")
|
12
|
+
IS_CI_AND_WINDOWS = IS_CI and IS_WINDOWS
|
13
|
+
SKIPIF_CI_AND_WINDOWS = mark.skipif(IS_CI_AND_WINDOWS, reason="Skipped for CI/Windows")
|
14
|
+
SKIPIF_CI_AND_NOT_LINUX = mark.skipif(
|
15
|
+
IS_CI and IS_NOT_LINUX, reason="Skipped for CI/non-Linux"
|
16
|
+
)
|
17
|
+
|
18
|
+
|
19
|
+
# hypothesis
|
20
|
+
|
21
|
+
|
22
|
+
try:
|
23
|
+
from utilities.hypothesis import setup_hypothesis_profiles
|
24
|
+
except ModuleNotFoundError:
|
25
|
+
pass
|
26
|
+
else:
|
27
|
+
setup_hypothesis_profiles()
|
@@ -1,19 +1,25 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
from asyncio import sleep
|
4
|
+
from contextlib import contextmanager
|
3
5
|
from io import StringIO
|
4
|
-
from logging import
|
6
|
+
from logging import (
|
7
|
+
Formatter,
|
8
|
+
Logger,
|
9
|
+
LogRecord,
|
10
|
+
StreamHandler,
|
11
|
+
getLogger,
|
12
|
+
setLogRecordFactory,
|
13
|
+
)
|
5
14
|
from pathlib import Path
|
6
15
|
from re import search
|
7
|
-
from
|
8
|
-
from typing import TYPE_CHECKING, Any, Literal, cast
|
16
|
+
from typing import TYPE_CHECKING, Any, cast
|
9
17
|
|
10
18
|
from hypothesis import given
|
11
19
|
from hypothesis.strategies import booleans, integers, none, sampled_from
|
12
20
|
from pytest import LogCaptureFixture, mark, param, raises
|
13
|
-
from whenever import ZonedDateTime
|
14
21
|
|
15
|
-
from tests.
|
16
|
-
from tests.test_traceback_funcs.untraced import func_untraced
|
22
|
+
from tests.conftest import SKIPIF_CI_AND_WINDOWS
|
17
23
|
from utilities.datetime import NOW_UTC, SECOND, serialize_compact
|
18
24
|
from utilities.hypothesis import (
|
19
25
|
assume_does_not_raise,
|
@@ -27,30 +33,33 @@ from utilities.logging import (
|
|
27
33
|
FilterForKeyError,
|
28
34
|
GetLoggingLevelNumberError,
|
29
35
|
SizeAndTimeRotatingFileHandler,
|
30
|
-
StandaloneFileHandler,
|
31
|
-
_AdvancedLogRecord,
|
32
36
|
_compute_rollover_actions,
|
37
|
+
_FieldStyleKeys,
|
33
38
|
_RotatingLogFile,
|
34
39
|
add_filters,
|
35
40
|
basic_config,
|
36
41
|
filter_for_key,
|
37
|
-
|
42
|
+
get_formatter,
|
38
43
|
get_logger,
|
39
44
|
get_logging_level_number,
|
40
45
|
setup_logging,
|
41
|
-
temp_handler,
|
42
|
-
temp_logger,
|
43
46
|
)
|
44
|
-
from utilities.pytest import skipif_windows
|
45
47
|
from utilities.text import unique_str
|
46
48
|
from utilities.types import LogLevel
|
47
49
|
from utilities.typing import get_args
|
48
50
|
|
49
51
|
if TYPE_CHECKING:
|
50
52
|
import datetime as dt
|
51
|
-
from
|
53
|
+
from collections.abc import Iterator, Mapping
|
54
|
+
from logging import _FilterType
|
55
|
+
|
52
56
|
|
53
|
-
|
57
|
+
@contextmanager
|
58
|
+
def _temp_log_factory() -> Iterator[None]:
|
59
|
+
try:
|
60
|
+
yield
|
61
|
+
finally:
|
62
|
+
setLogRecordFactory(LogRecord)
|
54
63
|
|
55
64
|
|
56
65
|
class TestAddFilters:
|
@@ -72,22 +81,38 @@ class TestAddFilters:
|
|
72
81
|
|
73
82
|
|
74
83
|
class TestBasicConfig:
|
75
|
-
@mark.parametrize("log", [param(True), param(False)])
|
76
84
|
@mark.parametrize("whenever", [param(True), param(False)])
|
85
|
+
@mark.parametrize(
|
86
|
+
"filters",
|
87
|
+
[
|
88
|
+
param(lambda _: True), # pyright: ignore[reportUnknownLambdaType]
|
89
|
+
param(None),
|
90
|
+
],
|
91
|
+
)
|
77
92
|
@mark.parametrize("plain", [param(True), param(False)])
|
78
93
|
def test_main(
|
79
|
-
self,
|
94
|
+
self,
|
95
|
+
*,
|
96
|
+
caplog: LogCaptureFixture,
|
97
|
+
whenever: bool,
|
98
|
+
filters: _FilterType | None,
|
99
|
+
plain: bool,
|
80
100
|
) -> None:
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
101
|
+
name = unique_str()
|
102
|
+
with _temp_log_factory():
|
103
|
+
basic_config(obj=name, whenever=whenever, filters=filters, plain=plain)
|
104
|
+
getLogger(name).warning("message")
|
105
|
+
record = one(r for r in caplog.records if r.name == name)
|
106
|
+
assert record.message == "message"
|
107
|
+
|
108
|
+
@mark.parametrize("whenever", [param(True), param(False)])
|
109
|
+
def test_none(self, *, whenever: bool) -> None:
|
110
|
+
with _temp_log_factory():
|
111
|
+
basic_config(whenever=whenever)
|
86
112
|
|
87
113
|
|
88
114
|
class TestComputeRolloverActions:
|
89
|
-
|
90
|
-
def test_main(self, *, tmp_path: Path) -> None:
|
115
|
+
async def test_main(self, *, tmp_path: Path) -> None:
|
91
116
|
tmp_path.joinpath("log.txt").touch()
|
92
117
|
|
93
118
|
actions = _compute_rollover_actions(tmp_path, "log", ".txt")
|
@@ -99,7 +124,7 @@ class TestComputeRolloverActions:
|
|
99
124
|
assert any(p for p in files if search(r"^log\.1\__[\dT]+\.txt$", p.name))
|
100
125
|
|
101
126
|
for _ in range(2):
|
102
|
-
sleep(1)
|
127
|
+
await sleep(1)
|
103
128
|
tmp_path.joinpath("log.txt").touch()
|
104
129
|
actions = _compute_rollover_actions(tmp_path, "log", ".txt")
|
105
130
|
assert len(actions.deletions) == 1
|
@@ -111,8 +136,7 @@ class TestComputeRolloverActions:
|
|
111
136
|
p for p in files if search(r"^log\.1\__[\dT]+__[\dT]+\.txt$", p.name)
|
112
137
|
)
|
113
138
|
|
114
|
-
|
115
|
-
def test_multiple_backups(self, *, tmp_path: Path) -> None:
|
139
|
+
async def test_multiple_backups(self, *, tmp_path: Path) -> None:
|
116
140
|
tmp_path.joinpath("log.txt").touch()
|
117
141
|
|
118
142
|
actions = _compute_rollover_actions(tmp_path, "log", ".txt", backup_count=3)
|
@@ -123,7 +147,7 @@ class TestComputeRolloverActions:
|
|
123
147
|
assert len(files) == 1
|
124
148
|
assert any(p for p in files if search(r"^log\.1\__[\dT]+\.txt$", p.name))
|
125
149
|
|
126
|
-
sleep(1)
|
150
|
+
await sleep(1)
|
127
151
|
tmp_path.joinpath("log.txt").touch()
|
128
152
|
actions = _compute_rollover_actions(tmp_path, "log", ".txt", backup_count=3)
|
129
153
|
assert len(actions.deletions) == 0
|
@@ -136,7 +160,7 @@ class TestComputeRolloverActions:
|
|
136
160
|
)
|
137
161
|
assert any(p for p in files if search(r"^log\.2\__[\dT]+\.txt$", p.name))
|
138
162
|
|
139
|
-
sleep(1)
|
163
|
+
await sleep(1)
|
140
164
|
tmp_path.joinpath("log.txt").touch()
|
141
165
|
actions = _compute_rollover_actions(tmp_path, "log", ".txt", backup_count=3)
|
142
166
|
assert len(actions.deletions) == 0
|
@@ -153,7 +177,7 @@ class TestComputeRolloverActions:
|
|
153
177
|
assert all(p for p in files if search(r"^log\.3\__[\dT]+\.txt$", p.name))
|
154
178
|
|
155
179
|
for _ in range(2):
|
156
|
-
sleep(1)
|
180
|
+
await sleep(1)
|
157
181
|
tmp_path.joinpath("log.txt").touch()
|
158
182
|
actions = _compute_rollover_actions(tmp_path, "log", ".txt", backup_count=3)
|
159
183
|
assert len(actions.deletions) == 1
|
@@ -171,8 +195,7 @@ class TestComputeRolloverActions:
|
|
171
195
|
p for p in files if search(r"^log\.3\__[\dT]+__[\dT]+\.txt$", p.name)
|
172
196
|
)
|
173
197
|
|
174
|
-
|
175
|
-
def test_deleting_old_files(self, *, tmp_path: Path) -> None:
|
198
|
+
async def test_deleting_old_files(self, *, tmp_path: Path) -> None:
|
176
199
|
tmp_path.joinpath("log.txt").touch()
|
177
200
|
|
178
201
|
actions = _compute_rollover_actions(tmp_path, "log", ".txt")
|
@@ -183,7 +206,7 @@ class TestComputeRolloverActions:
|
|
183
206
|
assert len(files) == 1
|
184
207
|
assert any(p for p in files if search(r"^log\.1\__[\dT]+\.txt$", p.name))
|
185
208
|
|
186
|
-
sleep(1)
|
209
|
+
await sleep(1)
|
187
210
|
tmp_path.joinpath("log.txt").touch()
|
188
211
|
now = serialize_compact(NOW_UTC)
|
189
212
|
tmp_path.joinpath(f"log.99__{now}__{now}.txt").touch()
|
@@ -225,9 +248,22 @@ class TestFilterForKey:
|
|
225
248
|
_ = filter_for_key(key)
|
226
249
|
|
227
250
|
|
228
|
-
class
|
229
|
-
|
230
|
-
|
251
|
+
class TestGetFormatter:
|
252
|
+
@mark.parametrize("whenever", [param(True), param(False)])
|
253
|
+
@mark.parametrize("plain", [param(True), param(False)])
|
254
|
+
@mark.parametrize("color_field_styles", [param({}), param(None)])
|
255
|
+
def test_main(
|
256
|
+
self,
|
257
|
+
*,
|
258
|
+
whenever: bool,
|
259
|
+
plain: bool,
|
260
|
+
color_field_styles: Mapping[str, _FieldStyleKeys] | None,
|
261
|
+
) -> None:
|
262
|
+
with _temp_log_factory():
|
263
|
+
formatter = get_formatter(
|
264
|
+
whenever=whenever, plain=plain, color_field_styles=color_field_styles
|
265
|
+
)
|
266
|
+
assert isinstance(formatter, Formatter)
|
231
267
|
|
232
268
|
|
233
269
|
class TestGetLogger:
|
@@ -380,105 +416,25 @@ class TestRotatingLogFile:
|
|
380
416
|
|
381
417
|
|
382
418
|
class TestSetupLogging:
|
383
|
-
|
384
|
-
def test_decorated(
|
385
|
-
self, *, tmp_path: Path, traceback_func_one: Pattern[str]
|
386
|
-
) -> None:
|
387
|
-
name = unique_str()
|
388
|
-
setup_logging(logger=name, files_dir=tmp_path)
|
389
|
-
logger = getLogger(name)
|
390
|
-
assert len(logger.handlers) == 7
|
391
|
-
self.assert_files(tmp_path, "init")
|
392
|
-
try:
|
393
|
-
_ = func_one(1, 2, 3, 4, c=5, d=6, e=7)
|
394
|
-
except AssertionError:
|
395
|
-
logger.exception("message")
|
396
|
-
self.assert_files(tmp_path, ("post", traceback_func_one))
|
397
|
-
|
398
|
-
@skipif_windows
|
399
|
-
def test_undecorated(
|
400
|
-
self, *, tmp_path: Path, traceback_func_untraced: Pattern[str]
|
401
|
-
) -> None:
|
419
|
+
def test_main(self, *, tmp_path: Path) -> None:
|
402
420
|
name = unique_str()
|
403
421
|
setup_logging(logger=name, files_dir=tmp_path)
|
404
422
|
logger = getLogger(name)
|
405
423
|
assert len(logger.handlers) == 7
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
name = unique_str()
|
418
|
-
setup_logging(logger=name, files_dir=tmp_path)
|
419
|
-
logger = getLogger(name)
|
420
|
-
logger.info("int: %d, float: %.2f", 1, 12.3456)
|
421
|
-
record = one(caplog.records)
|
422
|
-
assert isinstance(record, _AdvancedLogRecord)
|
423
|
-
expected = "int: 1, float: 12.35"
|
424
|
-
assert record.message == expected
|
425
|
-
|
426
|
-
@skipif_windows
|
427
|
-
def test_no_console(self, *, tmp_path: Path) -> None:
|
428
|
-
name = unique_str()
|
429
|
-
setup_logging(logger=name, console_level=None, files_dir=tmp_path)
|
430
|
-
logger = getLogger(name)
|
431
|
-
assert len(logger.handlers) == 5
|
432
|
-
|
433
|
-
@skipif_windows
|
434
|
-
def test_zoned_datetime(self, *, tmp_path: Path, caplog: LogCaptureFixture) -> None:
|
435
|
-
name = unique_str()
|
436
|
-
setup_logging(logger=name, files_dir=tmp_path)
|
437
|
-
logger = getLogger(name)
|
438
|
-
logger.info("")
|
439
|
-
record = one(caplog.records)
|
440
|
-
assert isinstance(record, _AdvancedLogRecord)
|
441
|
-
assert isinstance(record._zoned_datetime, ZonedDateTime)
|
442
|
-
assert isinstance(record._zoned_datetime_str, str)
|
443
|
-
|
444
|
-
@skipif_windows
|
445
|
-
def test_extra(self, *, tmp_path: Path) -> None:
|
446
|
-
name = unique_str()
|
447
|
-
|
448
|
-
def extra(logger: LoggerOrName | None, /) -> None:
|
449
|
-
get_logger(logger=logger).addHandler(
|
450
|
-
FileHandler(tmp_path.joinpath("extra.log"))
|
451
|
-
)
|
452
|
-
|
453
|
-
setup_logging(logger=name, files_dir=tmp_path, extra=extra)
|
454
|
-
logger = getLogger(name)
|
455
|
-
logger.info("")
|
456
|
-
files = list(tmp_path.iterdir())
|
457
|
-
names = {f.name for f in files}
|
458
|
-
assert len(names) == 4
|
459
|
-
|
460
|
-
@classmethod
|
461
|
-
def assert_files(
|
462
|
-
cls, path: Path, check: Literal["init"] | tuple[Literal["post"], Pattern[str]]
|
463
|
-
) -> None:
|
464
|
-
files = list(path.iterdir())
|
465
|
-
names = {f.name for f in files}
|
466
|
-
match check:
|
467
|
-
case "init":
|
468
|
-
assert names == {"debug.txt", "info.txt", "plain"}
|
469
|
-
case "post", pattern:
|
470
|
-
assert names == {"debug.txt", "info.txt", "errors", "plain"}
|
471
|
-
errors = path.joinpath("errors")
|
472
|
-
assert errors.is_dir()
|
473
|
-
files = list(errors.iterdir())
|
474
|
-
assert len(files) == 1
|
475
|
-
with one(files).open() as fh:
|
476
|
-
contents = fh.read()
|
477
|
-
assert pattern.search(contents)
|
424
|
+
logger.warning("message")
|
425
|
+
files = {p.name for p in tmp_path.iterdir() if p.is_file()}
|
426
|
+
expected = {
|
427
|
+
"debug.txt",
|
428
|
+
"info.txt",
|
429
|
+
"error.txt",
|
430
|
+
f"{name}-debug.txt",
|
431
|
+
f"{name}-info.txt",
|
432
|
+
f"{name}-error.txt",
|
433
|
+
}
|
434
|
+
assert files == expected
|
478
435
|
|
479
436
|
|
480
437
|
class TestSizeAndTimeRotatingFileHandler:
|
481
|
-
@skipif_windows
|
482
438
|
def test_handlers(self, *, tmp_path: Path) -> None:
|
483
439
|
logger = getLogger(unique_str())
|
484
440
|
filename = tmp_path.joinpath("log")
|
@@ -488,15 +444,14 @@ class TestSizeAndTimeRotatingFileHandler:
|
|
488
444
|
content = fh.read()
|
489
445
|
assert content == "message\n"
|
490
446
|
|
491
|
-
@skipif_windows
|
492
447
|
def test_create_parents(self, *, tmp_path: Path) -> None:
|
493
448
|
logger = getLogger(unique_str())
|
494
449
|
filename = tmp_path.joinpath("foo", "bar", "bar", "log")
|
495
450
|
logger.addHandler(SizeAndTimeRotatingFileHandler(filename=filename))
|
496
451
|
assert filename.exists()
|
497
452
|
|
498
|
-
@
|
499
|
-
def test_size(self, *, tmp_path: Path) -> None:
|
453
|
+
@SKIPIF_CI_AND_WINDOWS
|
454
|
+
async def test_size(self, *, tmp_path: Path) -> None:
|
500
455
|
logger = getLogger(unique_str())
|
501
456
|
logger.addHandler(
|
502
457
|
SizeAndTimeRotatingFileHandler(
|
@@ -552,10 +507,10 @@ class TestSizeAndTimeRotatingFileHandler:
|
|
552
507
|
for p in files
|
553
508
|
if search(r"^log\.3__[\dT]+__[\dT]+\.txt$", p.name)
|
554
509
|
)
|
510
|
+
await sleep(0.1)
|
555
511
|
|
556
|
-
@
|
557
|
-
|
558
|
-
def test_time(self, *, tmp_path: Path) -> None:
|
512
|
+
@SKIPIF_CI_AND_WINDOWS
|
513
|
+
async def test_time(self, *, tmp_path: Path) -> None:
|
559
514
|
logger = getLogger(unique_str())
|
560
515
|
logger.addHandler(
|
561
516
|
SizeAndTimeRotatingFileHandler(
|
@@ -575,7 +530,7 @@ class TestSizeAndTimeRotatingFileHandler:
|
|
575
530
|
assert len(files) == 1
|
576
531
|
assert any(p for p in files if search(r"^log\.txt$", p.name))
|
577
532
|
|
578
|
-
sleep(1.
|
533
|
+
await sleep(1.1)
|
579
534
|
for i in range(2, 4):
|
580
535
|
logger.warning("message %d", i)
|
581
536
|
files = list(tmp_path.iterdir())
|
@@ -583,7 +538,7 @@ class TestSizeAndTimeRotatingFileHandler:
|
|
583
538
|
assert any(p for p in files if search(r"^log\.txt$", p.name))
|
584
539
|
assert any(p for p in files if search(r"^log\.1__[\dT]+\.txt$", p.name))
|
585
540
|
|
586
|
-
sleep(1.
|
541
|
+
await sleep(1.1)
|
587
542
|
for i in range(4, 6):
|
588
543
|
logger.warning("message %d", i)
|
589
544
|
files = list(tmp_path.iterdir())
|
@@ -594,7 +549,7 @@ class TestSizeAndTimeRotatingFileHandler:
|
|
594
549
|
)
|
595
550
|
assert any(p for p in files if search(r"^log\.2__[\dT]+\.txt$", p.name))
|
596
551
|
|
597
|
-
sleep(1.
|
552
|
+
await sleep(1.1)
|
598
553
|
for i in range(6, 8):
|
599
554
|
logger.warning("message %d", i)
|
600
555
|
files = list(tmp_path.iterdir())
|
@@ -609,7 +564,7 @@ class TestSizeAndTimeRotatingFileHandler:
|
|
609
564
|
assert any(p for p in files if search(r"^log\.3__[\dT]+\.txt$", p.name))
|
610
565
|
|
611
566
|
for _ in range(2):
|
612
|
-
sleep(1.
|
567
|
+
await sleep(1.1)
|
613
568
|
for i in range(8, 10):
|
614
569
|
logger.warning("message %d", i)
|
615
570
|
files = list(tmp_path.iterdir())
|
@@ -625,67 +580,17 @@ class TestSizeAndTimeRotatingFileHandler:
|
|
625
580
|
p for p in files if search(r"^log\.3__[\dT]+__[\dT]+\.txt$", p.name)
|
626
581
|
)
|
627
582
|
|
628
|
-
@
|
583
|
+
@mark.parametrize("max_bytes", [param(0), param(1)])
|
584
|
+
@SKIPIF_CI_AND_WINDOWS
|
629
585
|
def test_should_rollover_file_not_found(
|
630
|
-
self, *, tmp_path: Path, caplog: LogCaptureFixture
|
586
|
+
self, *, tmp_path: Path, max_bytes: int, caplog: LogCaptureFixture
|
631
587
|
) -> None:
|
632
|
-
logger = getLogger(unique_str())
|
588
|
+
logger = getLogger(name := unique_str())
|
633
589
|
path = tmp_path.joinpath("log")
|
634
590
|
logger.addHandler(
|
635
|
-
handler := SizeAndTimeRotatingFileHandler(filename=path, maxBytes=
|
591
|
+
handler := SizeAndTimeRotatingFileHandler(filename=path, maxBytes=max_bytes)
|
636
592
|
)
|
637
593
|
logger.warning("message")
|
638
|
-
record = one(caplog.records)
|
594
|
+
record = one(r for r in caplog.records if r.name == name)
|
639
595
|
path.unlink()
|
640
596
|
assert not handler._should_rollover(record)
|
641
|
-
|
642
|
-
|
643
|
-
class TestStandaloneFileHandler:
|
644
|
-
@skipif_windows
|
645
|
-
def test_main(self, *, tmp_path: Path) -> None:
|
646
|
-
logger = getLogger(unique_str())
|
647
|
-
logger.addHandler(StandaloneFileHandler(level=DEBUG, path=tmp_path))
|
648
|
-
assert len(list(tmp_path.iterdir())) == 0
|
649
|
-
logger.warning("message")
|
650
|
-
files = list(tmp_path.iterdir())
|
651
|
-
assert len(files) == 1
|
652
|
-
with one(files).open() as fh:
|
653
|
-
contents = fh.read()
|
654
|
-
assert contents == "message"
|
655
|
-
|
656
|
-
|
657
|
-
class TestTempHandler:
|
658
|
-
def test_main(self) -> None:
|
659
|
-
logger = getLogger(unique_str())
|
660
|
-
logger.addHandler(h1 := StreamHandler())
|
661
|
-
logger.addHandler(h2 := StreamHandler())
|
662
|
-
assert len(logger.handlers) == 2
|
663
|
-
handler = StreamHandler()
|
664
|
-
with temp_handler(handler, logger=logger):
|
665
|
-
assert len(logger.handlers) == 3
|
666
|
-
assert len(logger.handlers) == 2
|
667
|
-
assert logger.handlers[0] is h1
|
668
|
-
assert logger.handlers[1] is h2
|
669
|
-
|
670
|
-
|
671
|
-
class TestTempLogger:
|
672
|
-
def test_disabled(self) -> None:
|
673
|
-
logger = getLogger(unique_str())
|
674
|
-
assert not logger.disabled
|
675
|
-
with temp_logger(logger, disabled=True):
|
676
|
-
assert logger.disabled
|
677
|
-
assert not logger.disabled
|
678
|
-
|
679
|
-
def test_level(self) -> None:
|
680
|
-
logger = getLogger(unique_str())
|
681
|
-
assert logger.level == NOTSET
|
682
|
-
with temp_logger(logger, level="DEBUG"):
|
683
|
-
assert logger.level == DEBUG
|
684
|
-
assert logger.level == NOTSET
|
685
|
-
|
686
|
-
def test_propagate(self) -> None:
|
687
|
-
logger = getLogger(unique_str())
|
688
|
-
assert logger.propagate
|
689
|
-
with temp_logger(logger, propagate=False):
|
690
|
-
assert not logger.propagate
|
691
|
-
assert logger.propagate
|