dycw-utilities 0.112.14__tar.gz → 0.113.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.112.14 → dycw_utilities-0.113.1}/PKG-INFO +1 -2
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/pyproject.toml +2 -4
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_dataclasses.py +31 -2
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_iterables.py +24 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_polars.py +0 -152
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/__init__.py +1 -1
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/dataclasses.py +24 -1
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/iterables.py +30 -14
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/math.py +2 -2
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/polars.py +3 -124
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/types.py +2 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/.gitignore +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/LICENSE +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/README.md +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/__init__.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/conftest.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/modules/__init__.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/modules/package_missing/__init__.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/modules/package_missing/module.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/modules/package_with/__init__.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/modules/package_with/outer_1.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/modules/package_with/outer_2.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/modules/package_without/__init__.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/modules/package_without/module_1.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/modules/package_without/module_2.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/modules/standalone.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/modules/with_imports.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/scripts/__init__.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/scripts/test_async_service/__init__.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/scripts/test_async_service/__main__.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/scripts/test_async_service/run.sh +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/scripts/test_queue_processor/__init__.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/scripts/test_queue_processor/__main__.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/scripts/test_queue_processor/run.sh +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_altair.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_astor.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_asyncio.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_atomicwrites.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_atools.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_cachetools.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_click.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_concurrent.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_contextlib.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_contextvars.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_cryptography.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_cvxpy.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_datetime.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_enum.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_errors.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_eventkit.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_fastapi.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_fpdf2.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_functions.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_functools.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_getpass.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_git.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_hashlib.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_http.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_hypothesis.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_ipython.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_jupyter.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_lightweight_charts.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_logging.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_loguru.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_luigi.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_math.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_memory_profiler.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_modules.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_more_itertools.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_numpy.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_operator.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_optuna.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_orjson.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_os.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_parse.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_pathlib.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_period.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_pickle.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_platform.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_polars_ols.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_pqdm.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_pydantic.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_pyinstrument.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_pyrsistent.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_pytest.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_pytest_regressions.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_python_dotenv.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_random.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_re.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_redis.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_reprlib.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_rich.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_scipy.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_sentinel.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_shelve.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_slack_sdk.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_socket.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_sqlalchemy.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_statsmodel.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_streamlit.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_sys.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_tempfile.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_tenacity.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_text.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_threading.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_timer.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_traceback.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_traceback_funcs/__init__.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_traceback_funcs/chain.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_traceback_funcs/error_bind.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_traceback_funcs/many.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_traceback_funcs/one.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_traceback_funcs/recursive.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_traceback_funcs/two.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_traceback_funcs/untraced.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_types.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_typing.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_typing_funcs/__init__.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_typing_funcs/no_future.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_typing_funcs/with_future.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_tzdata.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_tzlocal.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_uuid.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_version.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_warnings.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_whenever.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_zipfile.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/tests/test_zoneinfo.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/altair.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/astor.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/asyncio.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/atomicwrites.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/atools.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/cachetools.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/click.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/concurrent.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/contextlib.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/contextvars.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/cryptography.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/cvxpy.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/datetime.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/enum.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/errors.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/eventkit.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/fastapi.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/fpdf2.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/functions.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/functools.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/getpass.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/git.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/hashlib.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/http.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/hypothesis.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/ipython.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/jupyter.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/lightweight_charts.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/logging.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/loguru.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/luigi.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/memory_profiler.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/modules.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/more_itertools.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/numpy.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/operator.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/optuna.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/orjson.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/os.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/parse.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/pathlib.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/period.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/pickle.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/platform.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/polars_ols.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/pqdm.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/py.typed +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/pydantic.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/pyinstrument.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/pyrsistent.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/pytest.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/pytest_regressions.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/python_dotenv.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/random.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/re.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/redis.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/reprlib.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/rich.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/scipy.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/sentinel.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/shelve.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/slack_sdk.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/socket.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/sqlalchemy.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/sqlalchemy_polars.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/statsmodels.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/streamlit.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/sys.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/tempfile.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/tenacity.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/text.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/threading.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/timer.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/traceback.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/typing.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/tzdata.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/tzlocal.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/uuid.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/version.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/warnings.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/whenever.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.1}/src/utilities/zipfile.py +0 -0
- {dycw_utilities-0.112.14 → dycw_utilities-0.113.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.113.1
|
4
4
|
Author-email: Derek Wan <d.wan@icloud.com>
|
5
5
|
License-File: LICENSE
|
6
6
|
Requires-Python: >=3.12
|
@@ -137,7 +137,6 @@ Provides-Extra: zzz-test-pickle
|
|
137
137
|
Requires-Dist: atomicwrites<1.5,>=1.4.1; extra == 'zzz-test-pickle'
|
138
138
|
Provides-Extra: zzz-test-platform
|
139
139
|
Provides-Extra: zzz-test-polars
|
140
|
-
Requires-Dist: dacite<1.10,>=1.9.2; extra == 'zzz-test-polars'
|
141
140
|
Requires-Dist: polars-lts-cpu<1.30,>=1.29.0; extra == 'zzz-test-polars'
|
142
141
|
Requires-Dist: whenever<0.8,>=0.7.3; extra == 'zzz-test-polars'
|
143
142
|
Provides-Extra: zzz-test-pqdm
|
@@ -21,7 +21,6 @@ dev = [
|
|
21
21
|
"concurrent-log-handler >= 0.9.25, < 0.10",
|
22
22
|
"cryptography >= 44.0.2, < 44.1",
|
23
23
|
"cvxpy >= 1.6.5, < 1.7",
|
24
|
-
"dacite >= 1.9.2, < 1.10",
|
25
24
|
"eventkit >= 1.0.3, < 1.1",
|
26
25
|
"fastapi >= 0.115.11, < 0.116",
|
27
26
|
"fpdf2 >= 2.8.3, < 2.9",
|
@@ -93,7 +92,7 @@ dependencies = [
|
|
93
92
|
name = "dycw-utilities"
|
94
93
|
readme = "README.md"
|
95
94
|
requires-python = ">= 3.12"
|
96
|
-
version = "0.
|
95
|
+
version = "0.113.1"
|
97
96
|
|
98
97
|
[project.optional-dependencies]
|
99
98
|
test = [
|
@@ -231,7 +230,6 @@ zzz-test-pathlib = []
|
|
231
230
|
zzz-test-pickle = ["atomicwrites >= 1.4.1, < 1.5"]
|
232
231
|
zzz-test-platform = []
|
233
232
|
zzz-test-polars = [
|
234
|
-
"dacite >= 1.9.2, < 1.10",
|
235
233
|
"polars-lts-cpu >= 1.29.0, < 1.30",
|
236
234
|
"whenever >= 0.7.3, < 0.8",
|
237
235
|
]
|
@@ -336,7 +334,7 @@ zzz-test-zoneinfo = [
|
|
336
334
|
# bump-my-version
|
337
335
|
[tool.bumpversion]
|
338
336
|
allow_dirty = true
|
339
|
-
current_version = "0.
|
337
|
+
current_version = "0.113.1"
|
340
338
|
|
341
339
|
[[tool.bumpversion.files]]
|
342
340
|
filename = "src/utilities/__init__.py"
|
@@ -1,12 +1,21 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
from dataclasses import dataclass, field
|
4
|
+
from functools import total_ordering
|
4
5
|
from pathlib import Path
|
5
6
|
from types import NoneType
|
6
|
-
from typing import Any, Literal, cast, override
|
7
|
+
from typing import Any, Literal, Self, cast, override
|
7
8
|
|
8
9
|
from hypothesis import given
|
9
|
-
from hypothesis.strategies import
|
10
|
+
from hypothesis.strategies import (
|
11
|
+
DataObject,
|
12
|
+
booleans,
|
13
|
+
data,
|
14
|
+
integers,
|
15
|
+
lists,
|
16
|
+
permutations,
|
17
|
+
sampled_from,
|
18
|
+
)
|
10
19
|
from polars import DataFrame
|
11
20
|
from pytest import raises
|
12
21
|
|
@@ -53,6 +62,7 @@ from utilities.dataclasses import (
|
|
53
62
|
_YieldFieldsInstance,
|
54
63
|
dataclass_repr,
|
55
64
|
dataclass_to_dict,
|
65
|
+
is_nullable_lt,
|
56
66
|
mapping_to_dataclass,
|
57
67
|
one_field,
|
58
68
|
parse_dataclass,
|
@@ -272,6 +282,25 @@ class TestDataClassToDictAndDataClassRepr:
|
|
272
282
|
assert repr_res == repr_exp
|
273
283
|
|
274
284
|
|
285
|
+
class TestIsNullableLT:
|
286
|
+
@given(data=data())
|
287
|
+
def test_main(self, *, data: DataObject) -> None:
|
288
|
+
@dataclass(kw_only=True)
|
289
|
+
@total_ordering
|
290
|
+
class Example:
|
291
|
+
x: int | None = None
|
292
|
+
|
293
|
+
def __lt__(self, other: Self) -> bool:
|
294
|
+
if (cmp := is_nullable_lt(self.x, other.x)) is not None:
|
295
|
+
return cmp
|
296
|
+
return False
|
297
|
+
|
298
|
+
obj_none, obj1, obj2 = [Example(x=x) for x in [None, 1, 2]]
|
299
|
+
expected = [obj_none, obj_none, obj1, obj1, obj2, obj2]
|
300
|
+
result = sorted(data.draw(permutations(expected)))
|
301
|
+
assert result == expected
|
302
|
+
|
303
|
+
|
275
304
|
class TestMappingToDataClass:
|
276
305
|
@given(key=sampled_from(["int_", "INT_"]), int_=integers())
|
277
306
|
def test_exact_match_case_insensitive(self, *, key: str, int_: int) -> None:
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
3
3
|
import re
|
4
4
|
from dataclasses import dataclass, replace
|
5
5
|
from enum import Enum, auto
|
6
|
+
from functools import cmp_to_key
|
6
7
|
from itertools import chain, repeat
|
7
8
|
from math import isfinite, isinf, isnan, nan
|
8
9
|
from operator import add, neg, sub
|
@@ -92,6 +93,7 @@ from utilities.iterables import (
|
|
92
93
|
check_superset,
|
93
94
|
check_unique_modulo_case,
|
94
95
|
chunked,
|
96
|
+
cmp_nullable,
|
95
97
|
ensure_hashables,
|
96
98
|
ensure_iterable,
|
97
99
|
ensure_iterable_not_str,
|
@@ -613,6 +615,28 @@ class TestChunked:
|
|
613
615
|
assert result == expected
|
614
616
|
|
615
617
|
|
618
|
+
class TestCmpNullable:
|
619
|
+
@given(
|
620
|
+
data=data(),
|
621
|
+
case=sampled_from([
|
622
|
+
([None, None], [None, None]),
|
623
|
+
([1, None], [None, 1]),
|
624
|
+
([1, None, None], [None, None, 1]),
|
625
|
+
([2, 1, None], [None, 1, 2]),
|
626
|
+
([2, 1, None, None], [None, None, 1, 2]),
|
627
|
+
]),
|
628
|
+
)
|
629
|
+
def test_main(
|
630
|
+
self,
|
631
|
+
*,
|
632
|
+
data: DataObject,
|
633
|
+
case: tuple[Sequence[int | None], Sequence[int | None]],
|
634
|
+
) -> None:
|
635
|
+
values, expected = case
|
636
|
+
result = sorted(data.draw(permutations(values)), key=cmp_to_key(cmp_nullable))
|
637
|
+
assert result == expected
|
638
|
+
|
639
|
+
|
616
640
|
@dataclass(unsafe_hash=True, slots=True)
|
617
641
|
class _Item:
|
618
642
|
n: int
|
@@ -87,7 +87,6 @@ from utilities.polars import (
|
|
87
87
|
IsNullStructSeriesError,
|
88
88
|
SetFirstRowAsColumnsError,
|
89
89
|
StructFromDataClassError,
|
90
|
-
YieldStructSeriesElementsError,
|
91
90
|
_check_polars_dataframe_predicates,
|
92
91
|
_check_polars_dataframe_schema_list,
|
93
92
|
_check_polars_dataframe_schema_set,
|
@@ -117,7 +116,6 @@ from utilities.polars import (
|
|
117
116
|
_IsNearEventBeforeError,
|
118
117
|
_ReifyExprsEmptyError,
|
119
118
|
_ReifyExprsSeriesNonUniqueError,
|
120
|
-
_yield_struct_series_element_remove_nulls,
|
121
119
|
ac_halflife,
|
122
120
|
acf,
|
123
121
|
adjust_frequencies,
|
@@ -167,8 +165,6 @@ from utilities.polars import (
|
|
167
165
|
uniform,
|
168
166
|
unique_element,
|
169
167
|
week_num,
|
170
|
-
yield_struct_series_dataclasses,
|
171
|
-
yield_struct_series_elements,
|
172
168
|
zoned_datetime,
|
173
169
|
)
|
174
170
|
from utilities.random import get_state
|
@@ -2561,154 +2557,6 @@ class TestWeekNum:
|
|
2561
2557
|
assert_series_equal(result, expected)
|
2562
2558
|
|
2563
2559
|
|
2564
|
-
class TestYieldStructSeriesDataclasses:
|
2565
|
-
def test_main(self) -> None:
|
2566
|
-
@dataclass(kw_only=True, slots=True)
|
2567
|
-
class Row:
|
2568
|
-
lower: int | None = None
|
2569
|
-
upper: int | None = None
|
2570
|
-
|
2571
|
-
series = Series(
|
2572
|
-
name="series",
|
2573
|
-
values=[(1, 1), (2, None), (None, 3), (None, None)],
|
2574
|
-
dtype=Struct({"lower": Int64, "upper": Int64}),
|
2575
|
-
)
|
2576
|
-
result = list(yield_struct_series_dataclasses(series, Row))
|
2577
|
-
expected = [
|
2578
|
-
Row(lower=1, upper=1),
|
2579
|
-
Row(lower=2, upper=None),
|
2580
|
-
Row(lower=None, upper=3),
|
2581
|
-
None,
|
2582
|
-
]
|
2583
|
-
assert result == expected
|
2584
|
-
|
2585
|
-
def test_nested(self) -> None:
|
2586
|
-
@dataclass(kw_only=True, slots=True)
|
2587
|
-
class Inner:
|
2588
|
-
lower: int
|
2589
|
-
upper: int
|
2590
|
-
|
2591
|
-
@dataclass(kw_only=True, slots=True)
|
2592
|
-
class Outer:
|
2593
|
-
a: int | None = None
|
2594
|
-
b: int | None = None
|
2595
|
-
inner: Inner | None = None
|
2596
|
-
|
2597
|
-
series = Series(
|
2598
|
-
name="series",
|
2599
|
-
values=[
|
2600
|
-
{"a": 1, "b": 2, "inner": {"lower": 3, "upper": 4}},
|
2601
|
-
{"a": 1, "b": 2, "inner": None},
|
2602
|
-
{"a": None, "b": None, "inner": {"lower": 3, "upper": 4}},
|
2603
|
-
{"a": None, "b": None, "inner": None},
|
2604
|
-
],
|
2605
|
-
dtype=Struct({
|
2606
|
-
"a": Int64,
|
2607
|
-
"b": Int64,
|
2608
|
-
"inner": Struct({"lower": Int64, "upper": Int64}),
|
2609
|
-
}),
|
2610
|
-
)
|
2611
|
-
result = list(
|
2612
|
-
yield_struct_series_dataclasses(
|
2613
|
-
series, Outer, forward_references={"Inner": Inner}
|
2614
|
-
)
|
2615
|
-
)
|
2616
|
-
expected = [
|
2617
|
-
Outer(a=1, b=2, inner=Inner(lower=3, upper=4)),
|
2618
|
-
Outer(a=1, b=2, inner=None),
|
2619
|
-
Outer(a=None, b=None, inner=Inner(lower=3, upper=4)),
|
2620
|
-
None,
|
2621
|
-
]
|
2622
|
-
assert result == expected
|
2623
|
-
|
2624
|
-
|
2625
|
-
class TestYieldStructSeriesElements:
|
2626
|
-
def test_main(self) -> None:
|
2627
|
-
series = Series(
|
2628
|
-
name="series",
|
2629
|
-
values=[(1, 1), (2, None), (None, 3), (None, None)],
|
2630
|
-
dtype=Struct({"lower": Int64, "upper": Int64}),
|
2631
|
-
)
|
2632
|
-
result = list(yield_struct_series_elements(series))
|
2633
|
-
expected = [
|
2634
|
-
{"lower": 1, "upper": 1},
|
2635
|
-
{"lower": 2, "upper": None},
|
2636
|
-
{"lower": None, "upper": 3},
|
2637
|
-
None,
|
2638
|
-
]
|
2639
|
-
assert result == expected
|
2640
|
-
|
2641
|
-
def test_nested(self) -> None:
|
2642
|
-
series = Series(
|
2643
|
-
name="series",
|
2644
|
-
values=[
|
2645
|
-
{"a": 1, "b": 2, "inner": {"lower": 3, "upper": 4}},
|
2646
|
-
{"a": 1, "b": 2, "inner": None},
|
2647
|
-
{"a": None, "b": None, "inner": {"lower": 3, "upper": 4}},
|
2648
|
-
{"a": None, "b": None, "inner": None},
|
2649
|
-
],
|
2650
|
-
dtype=Struct({
|
2651
|
-
"a": Int64,
|
2652
|
-
"b": Int64,
|
2653
|
-
"inner": Struct({"lower": Int64, "upper": Int64}),
|
2654
|
-
}),
|
2655
|
-
)
|
2656
|
-
result = list(yield_struct_series_elements(series))
|
2657
|
-
expected = [
|
2658
|
-
{"a": 1, "b": 2, "inner": {"lower": 3, "upper": 4}},
|
2659
|
-
{"a": 1, "b": 2, "inner": None},
|
2660
|
-
{"a": None, "b": None, "inner": {"lower": 3, "upper": 4}},
|
2661
|
-
None,
|
2662
|
-
]
|
2663
|
-
assert result == expected
|
2664
|
-
|
2665
|
-
@given(
|
2666
|
-
case=sampled_from([
|
2667
|
-
(None, None),
|
2668
|
-
(1, 1),
|
2669
|
-
({"a": 1, "b": 2}, {"a": 1, "b": 2}),
|
2670
|
-
({"a": 1, "b": None}, {"a": 1, "b": None}),
|
2671
|
-
({"a": None, "b": None}, None),
|
2672
|
-
(
|
2673
|
-
{"a": 1, "b": 2, "inner": {"lower": 3, "upper": 4}},
|
2674
|
-
{"a": 1, "b": 2, "inner": {"lower": 3, "upper": 4}},
|
2675
|
-
),
|
2676
|
-
(
|
2677
|
-
{"a": 1, "b": 2, "inner": {"lower": None, "upper": None}},
|
2678
|
-
{"a": 1, "b": 2, "inner": None},
|
2679
|
-
),
|
2680
|
-
(
|
2681
|
-
{"a": None, "b": None, "inner": {"lower": 3, "upper": 4}},
|
2682
|
-
{"a": None, "b": None, "inner": {"lower": 3, "upper": 4}},
|
2683
|
-
),
|
2684
|
-
({"a": None, "b": None, "inner": {"lower": None, "upper": None}}, None),
|
2685
|
-
])
|
2686
|
-
)
|
2687
|
-
def test_remove_nulls(self, *, case: tuple[Any, Any]) -> None:
|
2688
|
-
obj, expected = case
|
2689
|
-
result = _yield_struct_series_element_remove_nulls(obj)
|
2690
|
-
assert result == expected
|
2691
|
-
|
2692
|
-
def test_error_struct_dtype(self) -> None:
|
2693
|
-
series = Series(name="series", values=[1, 2, 3, None], dtype=Int64)
|
2694
|
-
with raises(
|
2695
|
-
YieldStructSeriesElementsError,
|
2696
|
-
match="Series must have Struct-dtype; got Int64",
|
2697
|
-
):
|
2698
|
-
_ = list(yield_struct_series_elements(series))
|
2699
|
-
|
2700
|
-
def test_error_null_elements(self) -> None:
|
2701
|
-
series = Series(
|
2702
|
-
name="series",
|
2703
|
-
values=[{"value": 1}, {"value": 2}, {"value": 3}, None],
|
2704
|
-
dtype=Struct({"value": Int64}),
|
2705
|
-
)
|
2706
|
-
with raises(
|
2707
|
-
YieldStructSeriesElementsError, match="Series must not have nulls; got .*"
|
2708
|
-
):
|
2709
|
-
_ = list(yield_struct_series_elements(series, strict=True))
|
2710
|
-
|
2711
|
-
|
2712
2560
|
class TestZonedDateTime:
|
2713
2561
|
@given(time_zone=sampled_from([HongKong, UTC]))
|
2714
2562
|
def test_main(self, *, time_zone: ZoneInfo) -> None:
|
@@ -20,7 +20,12 @@ from utilities.functions import (
|
|
20
20
|
is_dataclass_class,
|
21
21
|
is_dataclass_instance,
|
22
22
|
)
|
23
|
-
from utilities.iterables import
|
23
|
+
from utilities.iterables import (
|
24
|
+
OneStrEmptyError,
|
25
|
+
OneStrNonUniqueError,
|
26
|
+
cmp_nullable,
|
27
|
+
one_str,
|
28
|
+
)
|
24
29
|
from utilities.operator import is_equal
|
25
30
|
from utilities.parse import (
|
26
31
|
_ParseObjectExtraNonUniqueError,
|
@@ -43,6 +48,7 @@ from utilities.types import (
|
|
43
48
|
SerializeObjectExtra,
|
44
49
|
StrStrMapping,
|
45
50
|
TDataclass,
|
51
|
+
TSupportsLT,
|
46
52
|
)
|
47
53
|
from utilities.typing import get_type_hints
|
48
54
|
|
@@ -215,6 +221,22 @@ def dataclass_to_dict(
|
|
215
221
|
##
|
216
222
|
|
217
223
|
|
224
|
+
def is_nullable_lt(x: TSupportsLT | None, y: TSupportsLT | None, /) -> bool | None:
|
225
|
+
"""Compare two nullable fields."""
|
226
|
+
match cmp_nullable(x, y):
|
227
|
+
case 1:
|
228
|
+
return False
|
229
|
+
case -1:
|
230
|
+
return True
|
231
|
+
case 0:
|
232
|
+
return None
|
233
|
+
case _ as never:
|
234
|
+
assert_never(never)
|
235
|
+
|
236
|
+
|
237
|
+
##
|
238
|
+
|
239
|
+
|
218
240
|
def mapping_to_dataclass(
|
219
241
|
cls: type[TDataclass],
|
220
242
|
mapping: StrMapping,
|
@@ -1056,6 +1078,7 @@ __all__ = [
|
|
1056
1078
|
"YieldFieldsError",
|
1057
1079
|
"dataclass_repr",
|
1058
1080
|
"dataclass_to_dict",
|
1081
|
+
"is_nullable_lt",
|
1059
1082
|
"mapping_to_dataclass",
|
1060
1083
|
"one_field",
|
1061
1084
|
"parse_dataclass",
|
@@ -45,7 +45,7 @@ from utilities.math import (
|
|
45
45
|
)
|
46
46
|
from utilities.reprlib import get_repr
|
47
47
|
from utilities.sentinel import Sentinel, sentinel
|
48
|
-
from utilities.types import THashable, THashable2, TSupportsAdd
|
48
|
+
from utilities.types import Sign, THashable, THashable2, TSupportsAdd, TSupportsLT
|
49
49
|
from utilities.zoneinfo import UTC
|
50
50
|
|
51
51
|
if TYPE_CHECKING:
|
@@ -696,6 +696,24 @@ class _CheckUniqueModuloCaseDuplicateLowerCaseStringsError(CheckUniqueModuloCase
|
|
696
696
|
##
|
697
697
|
|
698
698
|
|
699
|
+
def cmp_nullable(x: TSupportsLT | None, y: TSupportsLT | None, /) -> Sign:
|
700
|
+
"""Compare two nullable objects."""
|
701
|
+
match x, y:
|
702
|
+
case None, None:
|
703
|
+
return 0
|
704
|
+
case None, _:
|
705
|
+
return -1
|
706
|
+
case _, None:
|
707
|
+
return 1
|
708
|
+
case _, _:
|
709
|
+
return cast("Sign", (x > y) - (x < y))
|
710
|
+
case _ as never:
|
711
|
+
assert_never(never)
|
712
|
+
|
713
|
+
|
714
|
+
##
|
715
|
+
|
716
|
+
|
699
717
|
def chunked(iterable: Iterable[_T], n: int, /) -> Iterator[Sequence[_T]]:
|
700
718
|
"""Break an iterable into lists of length n."""
|
701
719
|
return iter(partial(take, n, iter(iterable)), [])
|
@@ -1293,7 +1311,7 @@ def sort_iterable(iterable: Iterable[_T], /) -> list[_T]:
|
|
1293
1311
|
return sorted(iterable, key=cmp_to_key(_sort_iterable_cmp))
|
1294
1312
|
|
1295
1313
|
|
1296
|
-
def _sort_iterable_cmp(x: Any, y: Any, /) ->
|
1314
|
+
def _sort_iterable_cmp(x: Any, y: Any, /) -> Sign:
|
1297
1315
|
"""Compare two quantities."""
|
1298
1316
|
if type(x) is not type(y):
|
1299
1317
|
x_qualname = type(x).__qualname__
|
@@ -1318,7 +1336,7 @@ def _sort_iterable_cmp(x: Any, y: Any, /) -> Literal[-1, 0, 1]:
|
|
1318
1336
|
return _sort_iterable_cmp_floats(x, y)
|
1319
1337
|
if isinstance(x, str): # else Sequence
|
1320
1338
|
y = cast("str", y)
|
1321
|
-
return cast("
|
1339
|
+
return cast("Sign", (x > y) - (x < y))
|
1322
1340
|
|
1323
1341
|
# collections
|
1324
1342
|
if isinstance(x, Sized):
|
@@ -1333,14 +1351,14 @@ def _sort_iterable_cmp(x: Any, y: Any, /) -> Literal[-1, 0, 1]:
|
|
1333
1351
|
return _sort_iterable_cmp(sort_iterable(x), sort_iterable(y))
|
1334
1352
|
if isinstance(x, Sequence):
|
1335
1353
|
y = cast("Sequence[Any]", y)
|
1336
|
-
it: Iterable[
|
1354
|
+
it: Iterable[Sign] = (
|
1337
1355
|
_sort_iterable_cmp(x_i, y_i) for x_i, y_i in zip(x, y, strict=True)
|
1338
1356
|
)
|
1339
1357
|
with suppress(StopIteration):
|
1340
1358
|
return next(r for r in it if r != 0)
|
1341
1359
|
|
1342
1360
|
try:
|
1343
|
-
return cast("
|
1361
|
+
return cast("Sign", (x > y) - (x < y))
|
1344
1362
|
except TypeError:
|
1345
1363
|
raise SortIterableError(x=x, y=y) from None
|
1346
1364
|
|
@@ -1355,13 +1373,11 @@ class SortIterableError(Exception):
|
|
1355
1373
|
return f"Unable to sort {get_repr(self.x)} and {get_repr(self.y)}"
|
1356
1374
|
|
1357
1375
|
|
1358
|
-
def _sort_iterable_cmp_datetimes(
|
1359
|
-
x: dt.datetime, y: dt.datetime, /
|
1360
|
-
) -> Literal[-1, 0, 1]:
|
1376
|
+
def _sort_iterable_cmp_datetimes(x: dt.datetime, y: dt.datetime, /) -> Sign:
|
1361
1377
|
"""Compare two datetimes."""
|
1362
1378
|
match x.tzinfo, y.tzinfo:
|
1363
1379
|
case None, None:
|
1364
|
-
return cast("
|
1380
|
+
return cast("Sign", (x > y) - (x < y))
|
1365
1381
|
case dt.tzinfo(), None:
|
1366
1382
|
return 1
|
1367
1383
|
case None, dt.tzinfo():
|
@@ -1369,20 +1385,19 @@ def _sort_iterable_cmp_datetimes(
|
|
1369
1385
|
case dt.tzinfo(), dt.tzinfo():
|
1370
1386
|
x_utc = x.astimezone(tz=UTC)
|
1371
1387
|
y_utc = y.astimezone(tz=UTC)
|
1372
|
-
result = cast("
|
1388
|
+
result = cast("Sign", (x_utc > y_utc) - (x_utc < y_utc))
|
1373
1389
|
if result != 0:
|
1374
1390
|
return result
|
1375
1391
|
x_time_zone = ensure_not_none(ensure_not_none(x.tzinfo).tzname(x))
|
1376
1392
|
y_time_zone = ensure_not_none(ensure_not_none(y.tzinfo).tzname(y))
|
1377
1393
|
return cast(
|
1378
|
-
"
|
1379
|
-
(x_time_zone > y_time_zone) - (x_time_zone < y_time_zone),
|
1394
|
+
"Sign", (x_time_zone > y_time_zone) - (x_time_zone < y_time_zone)
|
1380
1395
|
)
|
1381
1396
|
case _ as never:
|
1382
1397
|
assert_never(never)
|
1383
1398
|
|
1384
1399
|
|
1385
|
-
def _sort_iterable_cmp_floats(x: float, y: float, /) ->
|
1400
|
+
def _sort_iterable_cmp_floats(x: float, y: float, /) -> Sign:
|
1386
1401
|
"""Compare two floats."""
|
1387
1402
|
x_nan, y_nan = map(isnan, [x, y])
|
1388
1403
|
match x_nan, y_nan:
|
@@ -1393,7 +1408,7 @@ def _sort_iterable_cmp_floats(x: float, y: float, /) -> Literal[-1, 0, 1]:
|
|
1393
1408
|
case False, True:
|
1394
1409
|
return -1
|
1395
1410
|
case False, False:
|
1396
|
-
return cast("
|
1411
|
+
return cast("Sign", (x > y) - (x < y))
|
1397
1412
|
case _ as never:
|
1398
1413
|
assert_never(never)
|
1399
1414
|
|
@@ -1517,6 +1532,7 @@ __all__ = [
|
|
1517
1532
|
"check_superset",
|
1518
1533
|
"check_unique_modulo_case",
|
1519
1534
|
"chunked",
|
1535
|
+
"cmp_nullable",
|
1520
1536
|
"ensure_hashables",
|
1521
1537
|
"ensure_iterable",
|
1522
1538
|
"ensure_iterable_not_str",
|
@@ -10,7 +10,7 @@ from typing import TYPE_CHECKING, Literal, assert_never, overload, override
|
|
10
10
|
from utilities.errors import ImpossibleCaseError
|
11
11
|
|
12
12
|
if TYPE_CHECKING:
|
13
|
-
from utilities.types import Number, RoundMode
|
13
|
+
from utilities.types import Number, RoundMode, Sign
|
14
14
|
|
15
15
|
|
16
16
|
MIN_FLOAT32, MAX_FLOAT32 = -3.4028234663852886e38, 3.4028234663852886e38
|
@@ -860,7 +860,7 @@ class SafeRoundError(Exception):
|
|
860
860
|
|
861
861
|
def sign(
|
862
862
|
x: float, /, *, rel_tol: float | None = None, abs_tol: float | None = None
|
863
|
-
) ->
|
863
|
+
) -> Sign:
|
864
864
|
"""Get the sign of an integer/float."""
|
865
865
|
match x:
|
866
866
|
case int():
|