dycw-utilities 0.112.6__tar.gz → 0.112.8__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.
Files changed (228) hide show
  1. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/PKG-INFO +1 -1
  2. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/pyproject.toml +2 -2
  3. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_dataclasses.py +245 -37
  4. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_logging.py +1 -0
  5. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_redis.py +3 -0
  6. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_text.py +30 -5
  7. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/__init__.py +1 -1
  8. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/dataclasses.py +284 -90
  9. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/parse.py +1 -3
  10. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/python_dotenv.py +2 -2
  11. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/text.py +2 -2
  12. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/.gitignore +0 -0
  13. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/LICENSE +0 -0
  14. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/README.md +0 -0
  15. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/__init__.py +0 -0
  16. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/conftest.py +0 -0
  17. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/modules/__init__.py +0 -0
  18. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/modules/package_missing/__init__.py +0 -0
  19. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/modules/package_missing/module.py +0 -0
  20. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/modules/package_with/__init__.py +0 -0
  21. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/modules/package_with/outer_1.py +0 -0
  22. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/modules/package_with/outer_2.py +0 -0
  23. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  24. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  25. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  26. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  27. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/modules/package_without/__init__.py +0 -0
  28. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/modules/package_without/module_1.py +0 -0
  29. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/modules/package_without/module_2.py +0 -0
  30. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/modules/standalone.py +0 -0
  31. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/modules/with_imports.py +0 -0
  32. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  33. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  34. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  35. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  36. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  37. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  38. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  39. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  40. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/scripts/__init__.py +0 -0
  41. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/scripts/test_async_service/__init__.py +0 -0
  42. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/scripts/test_async_service/__main__.py +0 -0
  43. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/scripts/test_async_service/run.sh +0 -0
  44. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/scripts/test_queue_processor/__init__.py +0 -0
  45. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/scripts/test_queue_processor/__main__.py +0 -0
  46. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/scripts/test_queue_processor/run.sh +0 -0
  47. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_altair.py +0 -0
  48. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_astor.py +0 -0
  49. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_asyncio.py +0 -0
  50. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_atomicwrites.py +0 -0
  51. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_atools.py +0 -0
  52. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_cachetools.py +0 -0
  53. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_click.py +0 -0
  54. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_concurrent.py +0 -0
  55. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_contextlib.py +0 -0
  56. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_contextvars.py +0 -0
  57. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_cryptography.py +0 -0
  58. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_cvxpy.py +0 -0
  59. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_datetime.py +0 -0
  60. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_enum.py +0 -0
  61. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_errors.py +0 -0
  62. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_eventkit.py +0 -0
  63. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_fastapi.py +0 -0
  64. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_fpdf2.py +0 -0
  65. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_functions.py +0 -0
  66. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_functools.py +0 -0
  67. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_getpass.py +0 -0
  68. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_git.py +0 -0
  69. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_hashlib.py +0 -0
  70. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_http.py +0 -0
  71. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_hypothesis.py +0 -0
  72. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_ipython.py +0 -0
  73. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_iterables.py +0 -0
  74. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_jupyter.py +0 -0
  75. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_lightweight_charts.py +0 -0
  76. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_loguru.py +0 -0
  77. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_luigi.py +0 -0
  78. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_math.py +0 -0
  79. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_memory_profiler.py +0 -0
  80. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_modules.py +0 -0
  81. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_more_itertools.py +0 -0
  82. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_numpy.py +0 -0
  83. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_operator.py +0 -0
  84. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_optuna.py +0 -0
  85. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_orjson.py +0 -0
  86. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_os.py +0 -0
  87. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_parse.py +0 -0
  88. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_pathlib.py +0 -0
  89. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_period.py +0 -0
  90. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_pickle.py +0 -0
  91. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_platform.py +0 -0
  92. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_polars.py +0 -0
  93. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_polars_ols.py +0 -0
  94. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_pqdm.py +0 -0
  95. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_pydantic.py +0 -0
  96. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_pyinstrument.py +0 -0
  97. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_pyrsistent.py +0 -0
  98. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_pytest.py +0 -0
  99. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_pytest_regressions.py +0 -0
  100. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_python_dotenv.py +0 -0
  101. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_random.py +0 -0
  102. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_re.py +0 -0
  103. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_reprlib.py +0 -0
  104. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_rich.py +0 -0
  105. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_scipy.py +0 -0
  106. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_sentinel.py +0 -0
  107. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_shelve.py +0 -0
  108. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_slack_sdk.py +0 -0
  109. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_socket.py +0 -0
  110. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_sqlalchemy.py +0 -0
  111. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_sqlalchemy_polars.py +0 -0
  112. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_statsmodel.py +0 -0
  113. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_streamlit.py +0 -0
  114. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_sys.py +0 -0
  115. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_tempfile.py +0 -0
  116. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_tenacity.py +0 -0
  117. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_threading.py +0 -0
  118. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_timer.py +0 -0
  119. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_traceback.py +0 -0
  120. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_traceback_funcs/__init__.py +0 -0
  121. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_traceback_funcs/chain.py +0 -0
  122. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
  123. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
  124. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_traceback_funcs/error_bind.py +0 -0
  125. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_traceback_funcs/many.py +0 -0
  126. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_traceback_funcs/one.py +0 -0
  127. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_traceback_funcs/recursive.py +0 -0
  128. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
  129. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
  130. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_traceback_funcs/two.py +0 -0
  131. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_traceback_funcs/untraced.py +0 -0
  132. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_types.py +0 -0
  133. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_typing.py +0 -0
  134. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_typing_funcs/__init__.py +0 -0
  135. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_typing_funcs/no_future.py +0 -0
  136. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_typing_funcs/with_future.py +0 -0
  137. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_tzdata.py +0 -0
  138. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_tzlocal.py +0 -0
  139. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_uuid.py +0 -0
  140. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_version.py +0 -0
  141. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_warnings.py +0 -0
  142. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_whenever.py +0 -0
  143. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_zipfile.py +0 -0
  144. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/tests/test_zoneinfo.py +0 -0
  145. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/altair.py +0 -0
  146. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/astor.py +0 -0
  147. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/asyncio.py +0 -0
  148. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/atomicwrites.py +0 -0
  149. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/atools.py +0 -0
  150. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/cachetools.py +0 -0
  151. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/click.py +0 -0
  152. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/concurrent.py +0 -0
  153. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/contextlib.py +0 -0
  154. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/contextvars.py +0 -0
  155. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/cryptography.py +0 -0
  156. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/cvxpy.py +0 -0
  157. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/datetime.py +0 -0
  158. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/enum.py +0 -0
  159. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/errors.py +0 -0
  160. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/eventkit.py +0 -0
  161. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/fastapi.py +0 -0
  162. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/fpdf2.py +0 -0
  163. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/functions.py +0 -0
  164. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/functools.py +0 -0
  165. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/getpass.py +0 -0
  166. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/git.py +0 -0
  167. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/hashlib.py +0 -0
  168. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/http.py +0 -0
  169. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/hypothesis.py +0 -0
  170. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/ipython.py +0 -0
  171. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/iterables.py +0 -0
  172. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/jupyter.py +0 -0
  173. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/lightweight_charts.py +0 -0
  174. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/logging.py +0 -0
  175. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/loguru.py +0 -0
  176. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/luigi.py +0 -0
  177. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/math.py +0 -0
  178. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/memory_profiler.py +0 -0
  179. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/modules.py +0 -0
  180. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/more_itertools.py +0 -0
  181. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/numpy.py +0 -0
  182. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/operator.py +0 -0
  183. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/optuna.py +0 -0
  184. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/orjson.py +0 -0
  185. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/os.py +0 -0
  186. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/pathlib.py +0 -0
  187. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/period.py +0 -0
  188. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/pickle.py +0 -0
  189. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/platform.py +0 -0
  190. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/polars.py +0 -0
  191. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/polars_ols.py +0 -0
  192. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/pqdm.py +0 -0
  193. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/py.typed +0 -0
  194. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/pydantic.py +0 -0
  195. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/pyinstrument.py +0 -0
  196. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/pyrsistent.py +0 -0
  197. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/pytest.py +0 -0
  198. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/pytest_regressions.py +0 -0
  199. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/random.py +0 -0
  200. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/re.py +0 -0
  201. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/redis.py +0 -0
  202. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/reprlib.py +0 -0
  203. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/rich.py +0 -0
  204. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/scipy.py +0 -0
  205. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/sentinel.py +0 -0
  206. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/shelve.py +0 -0
  207. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/slack_sdk.py +0 -0
  208. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/socket.py +0 -0
  209. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/sqlalchemy.py +0 -0
  210. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/sqlalchemy_polars.py +0 -0
  211. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/statsmodels.py +0 -0
  212. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/streamlit.py +0 -0
  213. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/sys.py +0 -0
  214. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/tempfile.py +0 -0
  215. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/tenacity.py +0 -0
  216. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/threading.py +0 -0
  217. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/timer.py +0 -0
  218. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/traceback.py +0 -0
  219. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/types.py +0 -0
  220. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/typing.py +0 -0
  221. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/tzdata.py +0 -0
  222. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/tzlocal.py +0 -0
  223. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/uuid.py +0 -0
  224. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/version.py +0 -0
  225. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/warnings.py +0 -0
  226. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/whenever.py +0 -0
  227. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/zipfile.py +0 -0
  228. {dycw_utilities-0.112.6 → dycw_utilities-0.112.8}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.112.6
3
+ Version: 0.112.8
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -93,7 +93,7 @@ dependencies = [
93
93
  name = "dycw-utilities"
94
94
  readme = "README.md"
95
95
  requires-python = ">= 3.12"
96
- version = "0.112.6"
96
+ version = "0.112.8"
97
97
 
98
98
  [project.optional-dependencies]
99
99
  test = [
@@ -336,7 +336,7 @@ zzz-test-zoneinfo = [
336
336
  # bump-my-version
337
337
  [tool.bumpversion]
338
338
  allow_dirty = true
339
- current_version = "0.112.6"
339
+ current_version = "0.112.8"
340
340
 
341
341
  [[tool.bumpversion.files]]
342
342
  filename = "src/utilities/__init__.py"
@@ -33,16 +33,22 @@ from tests.test_typing_funcs.with_future import (
33
33
  TrueOrFalseFutureTypeLit,
34
34
  )
35
35
  from utilities.dataclasses import (
36
- MappingToDataclassError,
37
- OneFieldEmptyError,
38
- OneFieldNonUniqueError,
39
- StrMappingToFieldMappingError,
40
36
  YieldFieldsError,
37
+ _MappingToDataClassEmptyError,
38
+ _MappingToDataClassMissingValuesError,
39
+ _MappingToDataClassNonUniqueError,
40
+ _OneFieldEmptyError,
41
+ _OneFieldNonUniqueError,
41
42
  _parse_dataclass_split_key_value_pairs,
43
+ _ParseDataClassMissingValuesError,
42
44
  _ParseDataClassSplitKeyValuePairsDuplicateKeysError,
43
45
  _ParseDataClassSplitKeyValuePairsSplitError,
46
+ _ParseDataClassStrMappingToFieldMappingEmptyError,
47
+ _ParseDataClassStrMappingToFieldMappingNonUniqueError,
44
48
  _ParseDataClassTextExtraNonUniqueError,
45
49
  _ParseDataClassTextParseError,
50
+ _StrMappingToFieldMappingEmptyError,
51
+ _StrMappingToFieldMappingNonUniqueError,
46
52
  _YieldFieldsClass,
47
53
  _YieldFieldsInstance,
48
54
  dataclass_repr,
@@ -101,7 +107,7 @@ class TestDataClassRepr:
101
107
  assert result == expected
102
108
 
103
109
 
104
- class TestDataclassToDictAndDataclassRepr:
110
+ class TestDataClassToDictAndDataClassRepr:
105
111
  @given(x=integers(), defaults=booleans())
106
112
  def test_field_without_defaults(self, *, x: int, defaults: bool) -> None:
107
113
  @dataclass(kw_only=True, slots=True)
@@ -222,7 +228,7 @@ class TestDataclassToDictAndDataclassRepr:
222
228
  dict_exp = {"inner": Inner(), "y": y}
223
229
  assert dict_res == dict_exp
224
230
  repr_res = dataclass_repr(obj, localns=locals())
225
- repr_exp = f"Outer(inner=TestDataclassToDictAndDataclassRepr.test_nested_without_recursive.<locals>.Inner(x=0), y={y})"
231
+ repr_exp = f"Outer(inner=TestDataClassToDictAndDataClassRepr.test_nested_without_recursive.<locals>.Inner(x=0), y={y})"
226
232
  assert repr_res == repr_exp
227
233
 
228
234
  @given(y=lists(integers()), z=integers())
@@ -262,11 +268,11 @@ class TestDataclassToDictAndDataclassRepr:
262
268
  dict_exp = {"inner": [Inner(x=0)], "y": y, "z": z}
263
269
  assert dict_res == dict_exp
264
270
  repr_res = dataclass_repr(obj, localns=locals())
265
- repr_exp = f"Outer(inner=[TestDataclassToDictAndDataclassRepr.test_nested_in_list_without_recursive.<locals>.Inner(x=0)], y={y}, z={z})"
271
+ repr_exp = f"Outer(inner=[TestDataClassToDictAndDataClassRepr.test_nested_in_list_without_recursive.<locals>.Inner(x=0)], y={y}, z={z})"
266
272
  assert repr_res == repr_exp
267
273
 
268
274
 
269
- class TestMappingToDataclass:
275
+ class TestMappingToDataClass:
270
276
  @given(key=sampled_from(["int_", "INT_"]), int_=integers())
271
277
  def test_exact_match_case_insensitive(self, *, key: str, int_: int) -> None:
272
278
  obj = mapping_to_dataclass(DataClassFutureInt, {key: int_})
@@ -303,62 +309,155 @@ class TestMappingToDataclass:
303
309
  expected = DataClassFutureInt(int_=int_)
304
310
  assert obj == expected
305
311
 
306
- def test_error(self) -> None:
312
+ @given(int_=integers())
313
+ def test_error_exact_match_case_insensitive_empty(self, *, int_: int) -> None:
314
+ with raises(
315
+ _MappingToDataClassEmptyError,
316
+ match=r"Dataclass 'DataClassFutureInt' does not contain a field 'invalid' \(modulo case\)",
317
+ ):
318
+ _ = mapping_to_dataclass(
319
+ DataClassFutureInt, {"int_": int_, "invalid": int_}
320
+ )
321
+
322
+ @given(int_=integers())
323
+ def test_error_exact_match_case_insensitive_non_unique(self, *, int_: int) -> None:
324
+ with raises(
325
+ _MappingToDataClassNonUniqueError,
326
+ match=r"Dataclass 'DataClassFutureIntLowerAndUpper' must contain field 'int_' exactly once \(modulo case\); got 'int_', 'INT_' and perhaps more",
327
+ ):
328
+ _ = mapping_to_dataclass(DataClassFutureIntLowerAndUpper, {"int_": int_})
329
+
330
+ @given(int_=integers())
331
+ def test_error_head_case_insensitive_empty(self, *, int_: int) -> None:
307
332
  with raises(
308
- MappingToDataclassError,
333
+ _MappingToDataClassEmptyError,
334
+ match=r"Dataclass 'DataClassFutureInt' does not contain any field starting with 'invalid' \(modulo case\)",
335
+ ):
336
+ _ = mapping_to_dataclass(DataClassFutureInt, {"invalid": int_}, head=True)
337
+
338
+ @given(int_=integers())
339
+ def test_error_head_case_insensitive_non_unique(self, *, int_: int) -> None:
340
+ with raises(
341
+ _MappingToDataClassNonUniqueError,
342
+ match=r"Dataclass 'DataClassFutureIntOneAndTwo' must contain exactly one field starting with 'int' \(modulo case\); got 'int1', 'int2' and perhaps more",
343
+ ):
344
+ _ = mapping_to_dataclass(
345
+ DataClassFutureIntOneAndTwo, {"int": int_}, head=True
346
+ )
347
+
348
+ @given(int_=integers())
349
+ def test_error_exact_match_case_sensitive_empty(self, *, int_: int) -> None:
350
+ with raises(
351
+ _MappingToDataClassEmptyError,
352
+ match=r"Dataclass 'DataClassFutureInt' does not contain a field 'extra'",
353
+ ):
354
+ _ = mapping_to_dataclass(
355
+ DataClassFutureInt, {"int_": int_, "extra": int_}, case_sensitive=True
356
+ )
357
+
358
+ # there is no head=False, case_sensitive=True, non-unique case
359
+
360
+ @given(int_=integers())
361
+ def test_error_head_case_sensitive_empty(self, *, int_: int) -> None:
362
+ with raises(
363
+ _MappingToDataClassEmptyError,
364
+ match=r"Dataclass 'DataClassFutureInt' does not contain any field starting with 'invalid'",
365
+ ):
366
+ _ = mapping_to_dataclass(
367
+ DataClassFutureInt, {"invalid": int_}, head=True, case_sensitive=True
368
+ )
369
+
370
+ @given(int_=integers())
371
+ def test_error_head_case_sensitive_non_unique(self, *, int_: int) -> None:
372
+ with raises(
373
+ _MappingToDataClassNonUniqueError,
374
+ match=r"Dataclass 'DataClassFutureIntOneAndTwo' must contain exactly one field starting with 'int'; got 'int1', 'int2' and perhaps more",
375
+ ):
376
+ _ = mapping_to_dataclass(
377
+ DataClassFutureIntOneAndTwo,
378
+ {"int": int_},
379
+ head=True,
380
+ case_sensitive=True,
381
+ )
382
+
383
+ def test_error_missing_values(self) -> None:
384
+ with raises(
385
+ _MappingToDataClassMissingValuesError,
309
386
  match="Unable to construct 'DataClassFutureInt'; missing values for 'int_'",
310
387
  ):
311
388
  _ = mapping_to_dataclass(DataClassFutureInt, {})
312
389
 
313
390
 
314
391
  class TestOneField:
315
- def test_error_exact_match_case_insensitive_empty_error(self) -> None:
392
+ @given(key=sampled_from(["int_", "INT_"]))
393
+ def test_exact_match_case_insensitive(self, *, key: str) -> None:
394
+ obj = one_field(DataClassFutureInt, key)
395
+ expected = one(yield_fields(DataClassFutureInt))
396
+ assert obj == expected
397
+
398
+ @given(key=sampled_from(["in", "IN"]))
399
+ def test_head_case_insensitive(self, *, key: str) -> None:
400
+ obj = one_field(DataClassFutureInt, key, head=True)
401
+ expected = one(yield_fields(DataClassFutureInt))
402
+ assert obj == expected
403
+
404
+ def test_exact_match_case_sensitive(self) -> None:
405
+ obj = one_field(DataClassFutureInt, "int_", case_sensitive=True)
406
+ expected = one(yield_fields(DataClassFutureInt))
407
+ assert obj == expected
408
+
409
+ def test_head_case_sensitive(self) -> None:
410
+ obj = one_field(DataClassFutureInt, "int", head=True, case_sensitive=True)
411
+ expected = one(yield_fields(DataClassFutureInt))
412
+ assert obj == expected
413
+
414
+ def test_error_exact_match_case_insensitive_empty(self) -> None:
316
415
  with raises(
317
- OneFieldEmptyError,
416
+ _OneFieldEmptyError,
318
417
  match=r"Dataclass 'DataClassFutureInt' does not contain a field 'invalid' \(modulo case\)",
319
418
  ):
320
419
  _ = one_field(DataClassFutureInt, "invalid")
321
420
 
322
- def test_error_exact_match_case_insensitive_non_unique_error(self) -> None:
421
+ def test_error_exact_match_case_insensitive_non_unique(self) -> None:
323
422
  with raises(
324
- OneFieldNonUniqueError,
423
+ _OneFieldNonUniqueError,
325
424
  match=r"Dataclass 'DataClassFutureIntLowerAndUpper' must contain field 'int_' exactly once \(modulo case\); got 'int_', 'INT_' and perhaps more",
326
425
  ):
327
426
  _ = one_field(DataClassFutureIntLowerAndUpper, "int_")
328
427
 
329
- def test_error_head_case_insensitive_empty_error(self) -> None:
428
+ def test_error_head_case_insensitive_empty(self) -> None:
330
429
  with raises(
331
- OneFieldEmptyError,
430
+ _OneFieldEmptyError,
332
431
  match=r"Dataclass 'DataClassFutureInt' does not contain any field starting with 'invalid' \(modulo case\)",
333
432
  ):
334
433
  _ = one_field(DataClassFutureInt, "invalid", head=True)
335
434
 
336
- def test_error_head_case_insensitive_non_unique_error(self) -> None:
435
+ def test_error_head_case_insensitive_non_unique(self) -> None:
337
436
  with raises(
338
- OneFieldNonUniqueError,
437
+ _OneFieldNonUniqueError,
339
438
  match=r"Dataclass 'DataClassFutureIntOneAndTwo' must contain exactly one field starting with 'int' \(modulo case\); got 'int1', 'int2' and perhaps more",
340
439
  ):
341
440
  _ = one_field(DataClassFutureIntOneAndTwo, "int", head=True)
342
441
 
343
- def test_error_exact_match_case_sensitive_empty_error(self) -> None:
442
+ def test_error_exact_match_case_sensitive_empty(self) -> None:
344
443
  with raises(
345
- OneFieldEmptyError,
444
+ _OneFieldEmptyError,
346
445
  match=r"Dataclass 'DataClassFutureInt' does not contain a field 'INT_'",
347
446
  ):
348
447
  _ = one_field(DataClassFutureInt, "INT_", case_sensitive=True)
349
448
 
350
449
  # there is no head=False, case_sensitive=True, non-unique case
351
450
 
352
- def test_error_head_case_sensitive_empty_error(self) -> None:
451
+ def test_error_head_case_sensitive_empty(self) -> None:
353
452
  with raises(
354
- OneFieldEmptyError,
453
+ _OneFieldEmptyError,
355
454
  match=r"Dataclass 'DataClassFutureInt' does not contain any field starting with 'INT_'",
356
455
  ):
357
456
  _ = one_field(DataClassFutureInt, "INT_", head=True, case_sensitive=True)
358
457
 
359
- def test_error_head_case_sensitive_non_unique_error(self) -> None:
458
+ def test_error_head_case_sensitive_non_unique(self) -> None:
360
459
  with raises(
361
- OneFieldNonUniqueError,
460
+ _OneFieldNonUniqueError,
362
461
  match=r"Dataclass 'DataClassFutureIntOneAndTwo' must contain exactly one field starting with 'int'; got 'int1', 'int2' and perhaps more",
363
462
  ):
364
463
  _ = one_field(
@@ -501,10 +600,84 @@ class TestSerializeAndParseDataClass:
501
600
  extra_parsers={int | str: int, int | float: int},
502
601
  )
503
602
 
603
+ @given(int_=integers())
604
+ def test_error_exact_match_case_insensitive_empty(self, *, int_: int) -> None:
605
+ with raises(
606
+ _ParseDataClassStrMappingToFieldMappingEmptyError,
607
+ match=r"Unable to construct 'DataClassFutureInt' since it does not contain a field 'invalid' \(modulo case\)",
608
+ ):
609
+ _ = parse_dataclass(f"int_={int_},invalid={int_}", DataClassFutureInt)
610
+
611
+ @given(int_=integers())
612
+ def test_error_exact_match_case_insensitive_non_unique(self, *, int_: int) -> None:
613
+ with raises(
614
+ _ParseDataClassStrMappingToFieldMappingNonUniqueError,
615
+ match=r"Unable to construct 'DataClassFutureIntLowerAndUpper' since it must contain field 'int_' exactly once \(modulo case\); got 'int_', 'INT_' and perhaps more",
616
+ ):
617
+ _ = parse_dataclass(f"int_={int_}", DataClassFutureIntLowerAndUpper)
618
+
619
+ @given(int_=integers())
620
+ def test_error_head_case_insensitive_empty(self, *, int_: int) -> None:
621
+ with raises(
622
+ _ParseDataClassStrMappingToFieldMappingEmptyError,
623
+ match=r"Unable to construct 'DataClassFutureInt' since it does not contain any field starting with 'invalid' \(modulo case\)",
624
+ ):
625
+ _ = parse_dataclass(f"invalid={int_}", DataClassFutureInt, head=True)
626
+
627
+ @given(int_=integers())
628
+ def test_error_head_case_insensitive_non_unique(self, *, int_: int) -> None:
629
+ with raises(
630
+ _ParseDataClassStrMappingToFieldMappingNonUniqueError,
631
+ match=r"Unable to construct 'DataClassFutureIntOneAndTwo' since it must contain exactly one field starting with 'int' \(modulo case\); got 'int1', 'int2' and perhaps more",
632
+ ):
633
+ _ = parse_dataclass(f"int={int_}", DataClassFutureIntOneAndTwo, head=True)
634
+
635
+ @given(int_=integers())
636
+ def test_error_exact_match_case_sensitive_empty(self, *, int_: int) -> None:
637
+ with raises(
638
+ _ParseDataClassStrMappingToFieldMappingEmptyError,
639
+ match=r"Unable to construct 'DataClassFutureInt' since it does not contain a field 'extra'",
640
+ ):
641
+ _ = parse_dataclass(
642
+ f"int_={int_},extra={int_}", DataClassFutureInt, case_sensitive=True
643
+ )
644
+
645
+ # there is no head=False, case_sensitive=True, non-unique case
646
+
647
+ @given(int_=integers())
648
+ def test_error_head_case_sensitive_empty(self, *, int_: int) -> None:
649
+ with raises(
650
+ _ParseDataClassStrMappingToFieldMappingEmptyError,
651
+ match=r"Unable to construct 'DataClassFutureInt' since it does not contain any field starting with 'invalid'",
652
+ ):
653
+ _ = parse_dataclass(
654
+ f"invalid={int_}", DataClassFutureInt, head=True, case_sensitive=True
655
+ )
656
+
657
+ @given(int_=integers())
658
+ def test_error_head_case_sensitive_non_unique(self, *, int_: int) -> None:
659
+ with raises(
660
+ _ParseDataClassStrMappingToFieldMappingNonUniqueError,
661
+ match=r"Unable to construct 'DataClassFutureIntOneAndTwo' since it must contain exactly one field starting with 'int'; got 'int1', 'int2' and perhaps more",
662
+ ):
663
+ _ = parse_dataclass(
664
+ f"int={int_}",
665
+ DataClassFutureIntOneAndTwo,
666
+ head=True,
667
+ case_sensitive=True,
668
+ )
669
+
670
+ def test_error_missing_values(self) -> None:
671
+ with raises(
672
+ _ParseDataClassMissingValuesError,
673
+ match="Unable to construct 'DataClassFutureInt'; missing values for 'int_'",
674
+ ):
675
+ _ = parse_dataclass("", DataClassFutureInt)
676
+
504
677
 
505
678
  class TestStrMappingToFieldMapping:
506
679
  @given(key=sampled_from(["int_", "INT_"]), int_=integers())
507
- def test_main_text_case_insensitive(self, *, key: str, int_: int) -> None:
680
+ def test_exact_match_case_insensitive(self, *, key: str, int_: int) -> None:
508
681
  result = str_mapping_to_field_mapping(DataClassFutureInt, {key: int_})
509
682
  assert len(result) == 1
510
683
  assert one(result) == one(yield_fields(DataClassFutureInt))
@@ -547,9 +720,9 @@ class TestStrMappingToFieldMapping:
547
720
  assert one(result.values()) == int_
548
721
 
549
722
  @given(int_=integers())
550
- def test_error_exact_match_case_insensitive(self, *, int_: int) -> None:
723
+ def test_error_exact_match_case_insensitive_empty(self, *, int_: int) -> None:
551
724
  with raises(
552
- StrMappingToFieldMappingError,
725
+ _StrMappingToFieldMappingEmptyError,
553
726
  match=r"Dataclass 'DataClassFutureInt' does not contain a field 'invalid' \(modulo case\)",
554
727
  ):
555
728
  _ = str_mapping_to_field_mapping(
@@ -557,35 +730,70 @@ class TestStrMappingToFieldMapping:
557
730
  )
558
731
 
559
732
  @given(int_=integers())
560
- def test_error_exact_match_case_sensitive(self, *, int_: int) -> None:
733
+ def test_error_exact_match_case_insensitive_non_unique(self, *, int_: int) -> None:
561
734
  with raises(
562
- StrMappingToFieldMappingError,
563
- match=r"Dataclass 'DataClassFutureInt' does not contain a field 'extra'",
735
+ _StrMappingToFieldMappingNonUniqueError,
736
+ match=r"Dataclass 'DataClassFutureIntLowerAndUpper' must contain field 'int_' exactly once \(modulo case\); got 'int_', 'INT_' and perhaps more",
564
737
  ):
565
738
  _ = str_mapping_to_field_mapping(
566
- DataClassFutureInt, {"int_": int_, "extra": int_}, case_sensitive=True
739
+ DataClassFutureIntLowerAndUpper, {"int_": int_}
567
740
  )
568
741
 
569
742
  @given(int_=integers())
570
- def test_error_head_case_insensitive(self, *, int_: int) -> None:
743
+ def test_error_head_case_insensitive_empty(self, *, int_: int) -> None:
571
744
  with raises(
572
- StrMappingToFieldMappingError,
573
- match=r"Dataclass .* does not contain any field starting with 'invalid' \(modulo case\)",
745
+ _StrMappingToFieldMappingEmptyError,
746
+ match=r"Dataclass 'DataClassFutureInt' does not contain any field starting with 'invalid' \(modulo case\)",
574
747
  ):
575
748
  _ = str_mapping_to_field_mapping(
576
749
  DataClassFutureInt, {"invalid": int_}, head=True
577
750
  )
578
751
 
579
752
  @given(int_=integers())
580
- def test_error_head_case_sensitive(self, *, int_: int) -> None:
753
+ def test_error_head_case_insensitive_non_unique(self, *, int_: int) -> None:
754
+ with raises(
755
+ _StrMappingToFieldMappingNonUniqueError,
756
+ match=r"Dataclass 'DataClassFutureIntOneAndTwo' must contain exactly one field starting with 'int' \(modulo case\); got 'int1', 'int2' and perhaps more",
757
+ ):
758
+ _ = str_mapping_to_field_mapping(
759
+ DataClassFutureIntOneAndTwo, {"int": int_}, head=True
760
+ )
761
+
762
+ @given(int_=integers())
763
+ def test_error_exact_match_case_sensitive_empty(self, *, int_: int) -> None:
764
+ with raises(
765
+ _StrMappingToFieldMappingEmptyError,
766
+ match=r"Dataclass 'DataClassFutureInt' does not contain a field 'extra'",
767
+ ):
768
+ _ = str_mapping_to_field_mapping(
769
+ DataClassFutureInt, {"int_": int_, "extra": int_}, case_sensitive=True
770
+ )
771
+
772
+ # there is no head=False, case_sensitive=True, non-unique case
773
+
774
+ @given(int_=integers())
775
+ def test_error_head_case_sensitive_empty(self, *, int_: int) -> None:
581
776
  with raises(
582
- StrMappingToFieldMappingError,
583
- match=r"Dataclass .* does not contain any field starting with 'invalid'",
777
+ _StrMappingToFieldMappingEmptyError,
778
+ match=r"Dataclass 'DataClassFutureInt' does not contain any field starting with 'invalid'",
584
779
  ):
585
780
  _ = str_mapping_to_field_mapping(
586
781
  DataClassFutureInt, {"invalid": int_}, head=True, case_sensitive=True
587
782
  )
588
783
 
784
+ @given(int_=integers())
785
+ def test_error_head_case_sensitive_non_unique(self, *, int_: int) -> None:
786
+ with raises(
787
+ _StrMappingToFieldMappingNonUniqueError,
788
+ match=r"Dataclass 'DataClassFutureIntOneAndTwo' must contain exactly one field starting with 'int'; got 'int1', 'int2' and perhaps more",
789
+ ):
790
+ _ = str_mapping_to_field_mapping(
791
+ DataClassFutureIntOneAndTwo,
792
+ {"int": int_},
793
+ head=True,
794
+ case_sensitive=True,
795
+ )
796
+
589
797
 
590
798
  class TestYieldFields:
591
799
  def test_class_no_future_int(self) -> None:
@@ -568,6 +568,7 @@ class TestSizeAndTimeRotatingFileHandler:
568
568
  p for p in files if search(r"^log\.3__[\dT]+__[\dT]+\.txt$", p.name)
569
569
  )
570
570
 
571
+ @mark.flaky
571
572
  @skipif_windows
572
573
  def test_time(self, *, tmp_path: Path) -> None:
573
574
  logger = getLogger(str(tmp_path))
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Any
5
5
 
6
6
  from hypothesis import HealthCheck, Phase, given, settings
7
7
  from hypothesis.strategies import DataObject, booleans, data
8
+ from pytest import mark
8
9
  from redis.asyncio import Redis
9
10
 
10
11
  from tests.conftest import SKIPIF_CI_AND_NOT_LINUX
@@ -40,6 +41,7 @@ class TestPublishAndSubscribe:
40
41
  ),
41
42
  obj=make_objects(),
42
43
  )
44
+ @mark.flaky
43
45
  @settings(
44
46
  max_examples=1,
45
47
  phases={Phase.generate},
@@ -110,6 +112,7 @@ class TestPublisher:
110
112
  ),
111
113
  obj=make_objects(),
112
114
  )
115
+ @mark.flaky
113
116
  @settings(
114
117
  max_examples=1,
115
118
  phases={Phase.generate},
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from itertools import chain
3
4
  from typing import TYPE_CHECKING
4
5
 
5
6
  from hypothesis import given
@@ -44,14 +45,38 @@ if TYPE_CHECKING:
44
45
  class TestParseBool:
45
46
  @given(data=data(), value=booleans())
46
47
  def test_main(self, *, data: DataObject, value: bool) -> None:
47
- text = str(value)
48
- text_use = data.draw(
49
- sampled_from([str(int(value)), text, text.lower(), text.upper()])
48
+ match value:
49
+ case True:
50
+ extra_cased_texts = ["Y", "Yes", "On"]
51
+ case False:
52
+ extra_cased_texts = ["N", "No", "Off"]
53
+ all_cased_texts = list(chain([str(value), str(int(value))], extra_cased_texts))
54
+ all_texts = list(
55
+ chain(
56
+ extra_cased_texts,
57
+ map(str.lower, all_cased_texts),
58
+ map(str.upper, all_cased_texts),
59
+ )
50
60
  )
51
- result = parse_bool(text_use)
61
+ text = data.draw(sampled_from(all_texts))
62
+ result = parse_bool(text)
52
63
  assert result is value
53
64
 
54
- @given(text=sampled_from(["invalid", "11", "00", "ttruee", "ffalsee"]))
65
+ @given(
66
+ text=sampled_from([
67
+ "00",
68
+ "11",
69
+ "ffalsee",
70
+ "invalid",
71
+ "nn",
72
+ "nnoo",
73
+ "oofff",
74
+ "oonn",
75
+ "ttruee",
76
+ "yy",
77
+ "yyess",
78
+ ])
79
+ )
55
80
  def test_error(self, *, text: str) -> None:
56
81
  with raises(ParseBoolError, match="Unable to parse boolean value; got '.*'"):
57
82
  _ = parse_bool(text)
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.112.6"
3
+ __version__ = "0.112.8"