dycw-utilities 0.109.3__tar.gz → 0.109.4__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 (222) hide show
  1. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/PKG-INFO +1 -1
  2. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/pyproject.toml +2 -2
  3. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_parse.py +73 -19
  4. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/__init__.py +1 -1
  5. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/parse.py +64 -23
  6. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/.gitignore +0 -0
  7. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/LICENSE +0 -0
  8. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/README.md +0 -0
  9. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/__init__.py +0 -0
  10. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/conftest.py +0 -0
  11. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/modules/__init__.py +0 -0
  12. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/modules/package_missing/__init__.py +0 -0
  13. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/modules/package_missing/module.py +0 -0
  14. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/modules/package_with/__init__.py +0 -0
  15. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/modules/package_with/outer_1.py +0 -0
  16. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/modules/package_with/outer_2.py +0 -0
  17. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  18. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  19. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  20. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  21. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/modules/package_without/__init__.py +0 -0
  22. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/modules/package_without/module_1.py +0 -0
  23. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/modules/package_without/module_2.py +0 -0
  24. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/modules/standalone.py +0 -0
  25. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/modules/with_imports.py +0 -0
  26. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  27. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  28. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  29. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  30. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  31. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  32. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  33. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  34. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/scripts/__init__.py +0 -0
  35. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/scripts/test_async_service/__init__.py +0 -0
  36. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/scripts/test_async_service/__main__.py +0 -0
  37. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/scripts/test_async_service/run.sh +0 -0
  38. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/scripts/test_queue_processor/__init__.py +0 -0
  39. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/scripts/test_queue_processor/__main__.py +0 -0
  40. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/scripts/test_queue_processor/run.sh +0 -0
  41. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_altair.py +0 -0
  42. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_astor.py +0 -0
  43. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_asyncio.py +0 -0
  44. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_atomicwrites.py +0 -0
  45. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_atools.py +0 -0
  46. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_cachetools.py +0 -0
  47. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_click.py +0 -0
  48. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_concurrent.py +0 -0
  49. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_contextlib.py +0 -0
  50. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_contextvars.py +0 -0
  51. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_cryptography.py +0 -0
  52. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_cvxpy.py +0 -0
  53. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_dataclasses.py +0 -0
  54. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_datetime.py +0 -0
  55. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_enum.py +0 -0
  56. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_errors.py +0 -0
  57. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_eventkit.py +0 -0
  58. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_fastapi.py +0 -0
  59. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_fpdf2.py +0 -0
  60. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_functions.py +0 -0
  61. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_functools.py +0 -0
  62. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_getpass.py +0 -0
  63. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_git.py +0 -0
  64. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_hashlib.py +0 -0
  65. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_http.py +0 -0
  66. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_hypothesis.py +0 -0
  67. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_ipython.py +0 -0
  68. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_iterables.py +0 -0
  69. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_jupyter.py +0 -0
  70. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_logging.py +0 -0
  71. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_loguru.py +0 -0
  72. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_luigi.py +0 -0
  73. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_math.py +0 -0
  74. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_memory_profiler.py +0 -0
  75. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_modules.py +0 -0
  76. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_more_itertools.py +0 -0
  77. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_numpy.py +0 -0
  78. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_operator.py +0 -0
  79. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_optuna.py +0 -0
  80. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_orjson.py +0 -0
  81. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_os.py +0 -0
  82. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_pathlib.py +0 -0
  83. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_period.py +0 -0
  84. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_pickle.py +0 -0
  85. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_platform.py +0 -0
  86. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_polars.py +0 -0
  87. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_pqdm.py +0 -0
  88. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_pydantic.py +0 -0
  89. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_pyinstrument.py +0 -0
  90. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_pyrsistent.py +0 -0
  91. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_pytest.py +0 -0
  92. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_pytest_regressions.py +0 -0
  93. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_python_dotenv.py +0 -0
  94. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_random.py +0 -0
  95. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_re.py +0 -0
  96. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_redis.py +0 -0
  97. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_reprlib.py +0 -0
  98. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_rich.py +0 -0
  99. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_scipy.py +0 -0
  100. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_sentinel.py +0 -0
  101. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_shelve.py +0 -0
  102. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_slack_sdk.py +0 -0
  103. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_socket.py +0 -0
  104. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_sqlalchemy.py +0 -0
  105. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_sqlalchemy_polars.py +0 -0
  106. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_streamlit.py +0 -0
  107. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_sys.py +0 -0
  108. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_tempfile.py +0 -0
  109. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_tenacity.py +0 -0
  110. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_text.py +0 -0
  111. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_threading.py +0 -0
  112. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_timer.py +0 -0
  113. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_traceback.py +0 -0
  114. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_traceback_funcs/__init__.py +0 -0
  115. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_traceback_funcs/chain.py +0 -0
  116. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
  117. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
  118. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_traceback_funcs/error_bind.py +0 -0
  119. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_traceback_funcs/many.py +0 -0
  120. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_traceback_funcs/one.py +0 -0
  121. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_traceback_funcs/recursive.py +0 -0
  122. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
  123. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
  124. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_traceback_funcs/two.py +0 -0
  125. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_traceback_funcs/untraced.py +0 -0
  126. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_types.py +0 -0
  127. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_typing.py +0 -0
  128. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_typing_funcs/__init__.py +0 -0
  129. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_typing_funcs/no_future.py +0 -0
  130. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_typing_funcs/with_future.py +0 -0
  131. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_tzdata.py +0 -0
  132. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_tzlocal.py +0 -0
  133. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_uuid.py +0 -0
  134. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_version.py +0 -0
  135. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_warnings.py +0 -0
  136. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_whenever.py +0 -0
  137. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_zipfile.py +0 -0
  138. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/tests/test_zoneinfo.py +0 -0
  139. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/altair.py +0 -0
  140. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/astor.py +0 -0
  141. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/asyncio.py +0 -0
  142. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/atomicwrites.py +0 -0
  143. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/atools.py +0 -0
  144. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/cachetools.py +0 -0
  145. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/click.py +0 -0
  146. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/concurrent.py +0 -0
  147. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/contextlib.py +0 -0
  148. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/contextvars.py +0 -0
  149. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/cryptography.py +0 -0
  150. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/cvxpy.py +0 -0
  151. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/dataclasses.py +0 -0
  152. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/datetime.py +0 -0
  153. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/enum.py +0 -0
  154. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/errors.py +0 -0
  155. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/eventkit.py +0 -0
  156. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/fastapi.py +0 -0
  157. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/fpdf2.py +0 -0
  158. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/functions.py +0 -0
  159. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/functools.py +0 -0
  160. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/getpass.py +0 -0
  161. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/git.py +0 -0
  162. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/hashlib.py +0 -0
  163. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/http.py +0 -0
  164. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/hypothesis.py +0 -0
  165. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/ipython.py +0 -0
  166. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/iterables.py +0 -0
  167. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/jupyter.py +0 -0
  168. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/logging.py +0 -0
  169. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/loguru.py +0 -0
  170. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/luigi.py +0 -0
  171. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/math.py +0 -0
  172. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/memory_profiler.py +0 -0
  173. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/modules.py +0 -0
  174. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/more_itertools.py +0 -0
  175. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/numpy.py +0 -0
  176. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/operator.py +0 -0
  177. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/optuna.py +0 -0
  178. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/orjson.py +0 -0
  179. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/os.py +0 -0
  180. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/pathlib.py +0 -0
  181. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/period.py +0 -0
  182. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/pickle.py +0 -0
  183. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/platform.py +0 -0
  184. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/polars.py +0 -0
  185. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/pqdm.py +0 -0
  186. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/py.typed +0 -0
  187. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/pydantic.py +0 -0
  188. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/pyinstrument.py +0 -0
  189. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/pyrsistent.py +0 -0
  190. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/pytest.py +0 -0
  191. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/pytest_regressions.py +0 -0
  192. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/python_dotenv.py +0 -0
  193. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/random.py +0 -0
  194. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/re.py +0 -0
  195. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/redis.py +0 -0
  196. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/reprlib.py +0 -0
  197. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/rich.py +0 -0
  198. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/scipy.py +0 -0
  199. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/sentinel.py +0 -0
  200. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/shelve.py +0 -0
  201. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/slack_sdk.py +0 -0
  202. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/socket.py +0 -0
  203. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/sqlalchemy.py +0 -0
  204. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/sqlalchemy_polars.py +0 -0
  205. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/streamlit.py +0 -0
  206. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/sys.py +0 -0
  207. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/tempfile.py +0 -0
  208. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/tenacity.py +0 -0
  209. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/text.py +0 -0
  210. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/threading.py +0 -0
  211. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/timer.py +0 -0
  212. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/traceback.py +0 -0
  213. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/types.py +0 -0
  214. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/typing.py +0 -0
  215. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/tzdata.py +0 -0
  216. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/tzlocal.py +0 -0
  217. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/uuid.py +0 -0
  218. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/version.py +0 -0
  219. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/warnings.py +0 -0
  220. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/whenever.py +0 -0
  221. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/zipfile.py +0 -0
  222. {dycw_utilities-0.109.3 → dycw_utilities-0.109.4}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.109.3
3
+ Version: 0.109.4
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -89,7 +89,7 @@ dependencies = [
89
89
  name = "dycw-utilities"
90
90
  readme = "README.md"
91
91
  requires-python = ">= 3.12"
92
- version = "0.109.3"
92
+ version = "0.109.4"
93
93
 
94
94
  [project.optional-dependencies]
95
95
  test = [
@@ -332,7 +332,7 @@ zzz-test-zoneinfo = [
332
332
  # bump-my-version
333
333
  [tool.bumpversion]
334
334
  allow_dirty = true
335
- current_version = "0.109.3"
335
+ current_version = "0.109.4"
336
336
 
337
337
  [[tool.bumpversion.files]]
338
338
  filename = "src/utilities/__init__.py"
@@ -13,6 +13,7 @@ from pytest import raises
13
13
 
14
14
  from tests.test_operator import TruthEnum
15
15
  from tests.test_typing_funcs.with_future import (
16
+ DataClassFutureInt,
16
17
  TrueOrFalseFutureLit,
17
18
  TrueOrFalseFutureTypeLit,
18
19
  )
@@ -26,7 +27,11 @@ from utilities.hypothesis import (
26
27
  zoned_datetimes,
27
28
  )
28
29
  from utilities.math import is_equal
29
- from utilities.parse import ParseTextError, parse_text
30
+ from utilities.parse import (
31
+ _ParseTextExtraNonUniqueError,
32
+ _ParseTextParseError,
33
+ parse_text,
34
+ )
30
35
  from utilities.sentinel import Sentinel, sentinel
31
36
  from utilities.version import Version
32
37
  from utilities.whenever import (
@@ -62,6 +67,17 @@ class TestParseText:
62
67
  result = parse_text(TruthEnum, text)
63
68
  assert result is truth
64
69
 
70
+ @given(value=integers())
71
+ def test_extra(self, *, value: int) -> None:
72
+ text = str(value)
73
+ result = parse_text(
74
+ DataClassFutureInt,
75
+ text,
76
+ extra={DataClassFutureInt: lambda text: DataClassFutureInt(int_=int(text))},
77
+ )
78
+ expected = DataClassFutureInt(int_=value)
79
+ assert result == expected
80
+
65
81
  @given(value=floats())
66
82
  def test_float(self, *, value: float) -> None:
67
83
  text = str(value)
@@ -154,101 +170,139 @@ class TestParseText:
154
170
 
155
171
  def test_error_bool(self) -> None:
156
172
  with raises(
157
- ParseTextError, match="Unable to parse <class 'bool'>; got 'invalid'"
173
+ _ParseTextParseError, match="Unable to parse <class 'bool'>; got 'invalid'"
158
174
  ):
159
175
  _ = parse_text(bool, "invalid")
160
176
 
161
177
  def test_error_date(self) -> None:
162
178
  with raises(
163
- ParseTextError,
179
+ _ParseTextParseError,
164
180
  match=r"Unable to parse <class 'datetime\.date'>; got 'invalid'",
165
181
  ):
166
182
  _ = parse_text(dt.date, "invalid")
167
183
 
168
184
  def test_error_datetime(self) -> None:
169
185
  with raises(
170
- ParseTextError,
186
+ _ParseTextParseError,
171
187
  match=r"Unable to parse <class 'datetime\.datetime'>; got 'invalid'",
172
188
  ):
173
189
  _ = parse_text(dt.datetime, "invalid")
174
190
 
175
191
  def test_error_enum(self) -> None:
176
192
  with raises(
177
- ParseTextError, match="Unable to parse <enum 'TruthEnum'>; got 'invalid'"
193
+ _ParseTextParseError,
194
+ match="Unable to parse <enum 'TruthEnum'>; got 'invalid'",
178
195
  ):
179
196
  _ = parse_text(TruthEnum, "invalid")
180
197
 
198
+ def test_error_extra_empty(self) -> None:
199
+ with raises(
200
+ _ParseTextParseError,
201
+ match="Unable to parse <class 'tests.test_typing_funcs.with_future.DataClassFutureInt'>; got 'invalid'",
202
+ ):
203
+ _ = parse_text(DataClassFutureInt, "invalid", extra={})
204
+
205
+ @given(value=integers())
206
+ def test_error_extra_non_unique(self, *, value: int) -> None:
207
+ @dataclass(kw_only=True)
208
+ class Parent1:
209
+ x: int = 0
210
+
211
+ @dataclass(kw_only=True)
212
+ class Parent2:
213
+ y: int = 0
214
+
215
+ @dataclass(kw_only=True)
216
+ class Child(Parent1, Parent2): ...
217
+
218
+ with raises(
219
+ _ParseTextExtraNonUniqueError,
220
+ match="Unable to parse <class '.*'> since `extra` must contain exactly one parent class; got <function .*>, <function .*> and perhaps more",
221
+ ):
222
+ _ = parse_text(
223
+ Child,
224
+ str(value),
225
+ extra={
226
+ Parent1: lambda text: Child(x=int(text)),
227
+ Parent2: lambda text: Child(y=int(text)),
228
+ },
229
+ )
230
+
181
231
  def test_error_float(self) -> None:
182
232
  with raises(
183
- ParseTextError, match="Unable to parse <class 'float'>; got 'invalid'"
233
+ _ParseTextParseError, match="Unable to parse <class 'float'>; got 'invalid'"
184
234
  ):
185
235
  _ = parse_text(float, "invalid")
186
236
 
187
237
  def test_error_int(self) -> None:
188
238
  with raises(
189
- ParseTextError, match="Unable to parse <class 'int'>; got 'invalid'"
239
+ _ParseTextParseError, match="Unable to parse <class 'int'>; got 'invalid'"
190
240
  ):
191
241
  _ = parse_text(int, "invalid")
192
242
 
193
243
  def test_error_none(self) -> None:
194
- with raises(ParseTextError, match="Unable to parse None; got 'invalid'"):
244
+ with raises(_ParseTextParseError, match="Unable to parse None; got 'invalid'"):
195
245
  _ = parse_text(None, "invalid")
196
246
 
197
247
  def test_error_none_type(self) -> None:
198
248
  with raises(
199
- ParseTextError, match="Unable to parse <class 'NoneType'>; got 'invalid'"
249
+ _ParseTextParseError,
250
+ match="Unable to parse <class 'NoneType'>; got 'invalid'",
200
251
  ):
201
252
  _ = parse_text(NoneType, "invalid")
202
253
 
203
254
  def test_error_nullable_int(self) -> None:
204
255
  with raises(
205
- ParseTextError, match=r"Unable to parse int \| None; got 'invalid'"
256
+ _ParseTextParseError, match=r"Unable to parse int \| None; got 'invalid'"
206
257
  ):
207
258
  _ = parse_text(int | None, "invalid")
208
259
 
209
260
  def test_error_nullable_not_type(self) -> None:
210
261
  with raises(
211
- ParseTextError,
262
+ _ParseTextParseError,
212
263
  match=r"Unable to parse collections\.abc\.Iterable\[None\] \| None; got 'invalid'",
213
264
  ):
214
265
  _ = parse_text(Iterable[None] | None, "invalid")
215
266
 
216
267
  def test_error_sentinel(self) -> None:
217
268
  with raises(
218
- ParseTextError,
269
+ _ParseTextParseError,
219
270
  match=r"Unable to parse <class 'utilities\.sentinel\.Sentinel'>; got 'invalid'",
220
271
  ):
221
272
  _ = parse_text(Sentinel, "invalid")
222
273
 
223
274
  def test_error_time(self) -> None:
224
275
  with raises(
225
- ParseTextError,
276
+ _ParseTextParseError,
226
277
  match=r"Unable to parse <class 'datetime\.time'>; got 'invalid'",
227
278
  ):
228
279
  _ = parse_text(dt.time, "invalid")
229
280
 
230
281
  def test_error_timedelta(self) -> None:
231
282
  with raises(
232
- ParseTextError,
283
+ _ParseTextParseError,
233
284
  match=r"Unable to parse <class 'datetime\.timedelta'>; got 'invalid'",
234
285
  ):
235
286
  _ = parse_text(dt.timedelta, "invalid")
236
287
 
237
288
  def test_error_tuple_invalid_text(self) -> None:
238
289
  with raises(
239
- ParseTextError, match=r"Unable to parse tuple\[int, int\]; got 'invalid'"
290
+ _ParseTextParseError,
291
+ match=r"Unable to parse tuple\[int, int\]; got 'invalid'",
240
292
  ):
241
293
  _ = parse_text(tuple[int, int], "invalid")
242
294
 
243
295
  def test_error_tuple_inconsistent_args_and_texts(self) -> None:
244
296
  with raises(
245
- ParseTextError,
297
+ _ParseTextParseError,
246
298
  match=r"Unable to parse tuple\[int, int\]; got '\(text1, text2, text3\)'",
247
299
  ):
248
300
  _ = parse_text(tuple[int, int], "(text1, text2, text3)")
249
301
 
250
302
  def test_error_unknown_annotation(self) -> None:
251
- with raises(ParseTextError, match=r"Unable to parse int \| str; got 'invalid'"):
303
+ with raises(
304
+ _ParseTextParseError, match=r"Unable to parse int \| str; got 'invalid'"
305
+ ):
252
306
  _ = parse_text(int | str, "invalid")
253
307
 
254
308
  def test_error_unknown_type(self) -> None:
@@ -257,14 +311,14 @@ class TestParseText:
257
311
  pass
258
312
 
259
313
  with raises(
260
- ParseTextError,
314
+ _ParseTextParseError,
261
315
  match=r"Unable to parse <class 'tests\.test_parse\.TestParseText\.test_error_unknown_type\.<locals>\.Example'>; got 'invalid'",
262
316
  ):
263
317
  _ = parse_text(Example, "invalid")
264
318
 
265
319
  def test_error_version(self) -> None:
266
320
  with raises(
267
- ParseTextError,
321
+ _ParseTextParseError,
268
322
  match=r"Unable to parse <class 'utilities\.version\.Version'>; got 'invalid'",
269
323
  ):
270
324
  _ = parse_text(Version, "invalid")
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.109.3"
3
+ __version__ = "0.109.4"
@@ -7,30 +7,42 @@ from enum import Enum
7
7
  from pathlib import Path
8
8
  from re import DOTALL
9
9
  from types import NoneType
10
- from typing import Any, override
10
+ from typing import TYPE_CHECKING, Any, TypeVar, override
11
11
 
12
12
  from utilities.datetime import is_subclass_date_not_datetime
13
13
  from utilities.enum import ParseEnumError, parse_enum
14
14
  from utilities.functions import is_subclass_int_not_bool
15
- from utilities.iterables import one, one_str
15
+ from utilities.iterables import OneEmptyError, OneNonUniqueError, one, one_str
16
16
  from utilities.re import ExtractGroupError, extract_group
17
17
  from utilities.sentinel import ParseSentinelError, Sentinel, parse_sentinel
18
18
  from utilities.text import ParseBoolError, ParseNoneError, parse_bool, parse_none
19
19
  from utilities.typing import get_args, is_literal_type, is_optional_type, is_tuple_type
20
20
  from utilities.version import ParseVersionError, Version, parse_version
21
21
 
22
+ if TYPE_CHECKING:
23
+ from collections.abc import Callable, Mapping
24
+
25
+
26
+ _T = TypeVar("_T")
27
+
22
28
 
23
29
  def parse_text(
24
- obj: Any, text: str, /, *, case_sensitive: bool = False, head: bool = False
30
+ obj: Any,
31
+ text: str,
32
+ /,
33
+ *,
34
+ case_sensitive: bool = False,
35
+ head: bool = False,
36
+ extra: Mapping[type[_T], Callable[[str], _T]] | None = None,
25
37
  ) -> Any:
26
38
  """Parse text."""
27
39
  if obj is None:
28
40
  try:
29
41
  return parse_none(text)
30
42
  except ParseNoneError:
31
- raise ParseTextError(obj=obj, text=text) from None
43
+ raise _ParseTextParseError(obj=obj, text=text) from None
32
44
  if isinstance(obj, type):
33
- return _parse_text_type(obj, text, case_sensitive=case_sensitive)
45
+ return _parse_text_type(obj, text, case_sensitive=case_sensitive, extra=extra)
34
46
  if is_literal_type(obj):
35
47
  return one_str(get_args(obj), text, head=head, case_sensitive=case_sensitive)
36
48
  if is_optional_type(obj):
@@ -42,95 +54,111 @@ def parse_text(
42
54
  ):
43
55
  try:
44
56
  return _parse_text_type(inner, text, case_sensitive=case_sensitive)
45
- except ParseTextError:
46
- raise ParseTextError(obj=obj, text=text) from None
57
+ except _ParseTextParseError:
58
+ raise _ParseTextParseError(obj=obj, text=text) from None
47
59
  if is_tuple_type(obj):
48
60
  args = get_args(obj)
49
61
  try:
50
62
  texts = extract_group(r"^\((.*)\)$", text, flags=DOTALL).split(", ")
51
63
  except ExtractGroupError:
52
- raise ParseTextError(obj=obj, text=text) from None
64
+ raise _ParseTextParseError(obj=obj, text=text) from None
53
65
  if len(args) != len(texts):
54
- raise ParseTextError(obj=obj, text=text)
66
+ raise _ParseTextParseError(obj=obj, text=text)
55
67
  return tuple(
56
68
  parse_text(arg, text, case_sensitive=case_sensitive, head=head)
57
69
  for arg, text in zip(args, texts, strict=True)
58
70
  )
59
- raise ParseTextError(obj=obj, text=text) from None
71
+ raise _ParseTextParseError(obj=obj, text=text) from None
60
72
 
61
73
 
62
74
  def _parse_text_type(
63
- cls: type[Any], text: str, /, *, case_sensitive: bool = False
75
+ cls: type[Any],
76
+ text: str,
77
+ /,
78
+ *,
79
+ case_sensitive: bool = False,
80
+ extra: Mapping[type[_T], Callable[[str], _T]] | None = None,
64
81
  ) -> Any:
65
82
  """Parse text."""
66
83
  if issubclass(cls, NoneType):
67
84
  try:
68
85
  return parse_none(text)
69
86
  except ParseNoneError:
70
- raise ParseTextError(obj=cls, text=text) from None
87
+ raise _ParseTextParseError(obj=cls, text=text) from None
71
88
  if issubclass(cls, str):
72
89
  return text
73
90
  if issubclass(cls, bool):
74
91
  try:
75
92
  return parse_bool(text)
76
93
  except ParseBoolError:
77
- raise ParseTextError(obj=cls, text=text) from None
94
+ raise _ParseTextParseError(obj=cls, text=text) from None
78
95
  if is_subclass_int_not_bool(cls):
79
96
  try:
80
97
  return int(text)
81
98
  except ValueError:
82
- raise ParseTextError(obj=cls, text=text) from None
99
+ raise _ParseTextParseError(obj=cls, text=text) from None
83
100
  if issubclass(cls, float):
84
101
  try:
85
102
  return float(text)
86
103
  except ValueError:
87
- raise ParseTextError(obj=cls, text=text) from None
104
+ raise _ParseTextParseError(obj=cls, text=text) from None
88
105
  if issubclass(cls, Enum):
89
106
  try:
90
107
  return parse_enum(text, cls, case_sensitive=case_sensitive)
91
108
  except ParseEnumError:
92
- raise ParseTextError(obj=cls, text=text) from None
109
+ raise _ParseTextParseError(obj=cls, text=text) from None
93
110
  if issubclass(cls, Path):
94
111
  return Path(text).expanduser()
95
112
  if issubclass(cls, Sentinel):
96
113
  try:
97
114
  return parse_sentinel(text)
98
115
  except ParseSentinelError:
99
- raise ParseTextError(obj=cls, text=text) from None
116
+ raise _ParseTextParseError(obj=cls, text=text) from None
100
117
  if issubclass(cls, Version):
101
118
  try:
102
119
  return parse_version(text)
103
120
  except ParseVersionError:
104
- raise ParseTextError(obj=cls, text=text) from None
121
+ raise _ParseTextParseError(obj=cls, text=text) from None
105
122
  if is_subclass_date_not_datetime(cls):
106
123
  from utilities.whenever import ParseDateError, parse_date
107
124
 
108
125
  try:
109
126
  return parse_date(text)
110
127
  except ParseDateError:
111
- raise ParseTextError(obj=cls, text=text) from None
128
+ raise _ParseTextParseError(obj=cls, text=text) from None
112
129
  if issubclass(cls, dt.datetime):
113
130
  from utilities.whenever import ParseDateTimeError, parse_datetime
114
131
 
115
132
  try:
116
133
  return parse_datetime(text)
117
134
  except ParseDateTimeError:
118
- raise ParseTextError(obj=cls, text=text) from None
135
+ raise _ParseTextParseError(obj=cls, text=text) from None
119
136
  if issubclass(cls, dt.time):
120
137
  from utilities.whenever import ParseTimeError, parse_time
121
138
 
122
139
  try:
123
140
  return parse_time(text)
124
141
  except ParseTimeError:
125
- raise ParseTextError(obj=cls, text=text) from None
142
+ raise _ParseTextParseError(obj=cls, text=text) from None
126
143
  if issubclass(cls, dt.timedelta):
127
144
  from utilities.whenever import ParseTimedeltaError, parse_timedelta
128
145
 
129
146
  try:
130
147
  return parse_timedelta(text)
131
148
  except ParseTimedeltaError:
132
- raise ParseTextError(obj=cls, text=text) from None
133
- raise ParseTextError(obj=cls, text=text) from None
149
+ raise _ParseTextParseError(obj=cls, text=text) from None
150
+ if extra is not None:
151
+ try:
152
+ parser = one(p for c, p in extra.items() if issubclass(cls, c))
153
+ except OneEmptyError:
154
+ pass
155
+ except OneNonUniqueError as error:
156
+ raise _ParseTextExtraNonUniqueError(
157
+ obj=cls, text=text, first=error.first, second=error.second
158
+ ) from None
159
+ else:
160
+ return parser(text)
161
+ raise _ParseTextParseError(obj=cls, text=text) from None
134
162
 
135
163
 
136
164
  @dataclass
@@ -138,6 +166,19 @@ class ParseTextError(Exception):
138
166
  obj: Any
139
167
  text: str
140
168
 
169
+
170
+ @dataclass
171
+ class _ParseTextParseError(ParseTextError):
141
172
  @override
142
173
  def __str__(self) -> str:
143
174
  return f"Unable to parse {self.obj!r}; got {self.text!r}"
175
+
176
+
177
+ @dataclass
178
+ class _ParseTextExtraNonUniqueError(ParseTextError):
179
+ first: type[Any]
180
+ second: type[Any]
181
+
182
+ @override
183
+ def __str__(self) -> str:
184
+ return f"Unable to parse {self.obj!r} since `extra` must contain exactly one parent class; got {self.first!r}, {self.second!r} and perhaps more"