dycw-utilities 0.109.28__tar.gz → 0.110.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/PKG-INFO +1 -1
  2. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/pyproject.toml +3 -2
  3. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_dataclasses.py +40 -18
  4. dycw_utilities-0.110.0/src/tests/test_parse.py +543 -0
  5. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/__init__.py +1 -1
  6. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/dataclasses.py +182 -96
  7. dycw_utilities-0.110.0/src/utilities/parse.py +572 -0
  8. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/python_dotenv.py +4 -4
  9. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/types.py +2 -2
  10. dycw_utilities-0.109.28/src/tests/test_parse.py +0 -443
  11. dycw_utilities-0.109.28/src/utilities/parse.py +0 -212
  12. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/.gitignore +0 -0
  13. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/LICENSE +0 -0
  14. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/README.md +0 -0
  15. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/__init__.py +0 -0
  16. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/conftest.py +0 -0
  17. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/modules/__init__.py +0 -0
  18. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/modules/package_missing/__init__.py +0 -0
  19. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/modules/package_missing/module.py +0 -0
  20. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/modules/package_with/__init__.py +0 -0
  21. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/modules/package_with/outer_1.py +0 -0
  22. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/modules/package_with/outer_2.py +0 -0
  23. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  24. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  25. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  26. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  27. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/modules/package_without/__init__.py +0 -0
  28. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/modules/package_without/module_1.py +0 -0
  29. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/modules/package_without/module_2.py +0 -0
  30. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/modules/standalone.py +0 -0
  31. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/modules/with_imports.py +0 -0
  32. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  33. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  34. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  35. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  36. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  37. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  38. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  39. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  40. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/scripts/__init__.py +0 -0
  41. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/scripts/test_async_service/__init__.py +0 -0
  42. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/scripts/test_async_service/__main__.py +0 -0
  43. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/scripts/test_async_service/run.sh +0 -0
  44. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/scripts/test_queue_processor/__init__.py +0 -0
  45. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/scripts/test_queue_processor/__main__.py +0 -0
  46. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/scripts/test_queue_processor/run.sh +0 -0
  47. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_altair.py +0 -0
  48. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_astor.py +0 -0
  49. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_asyncio.py +0 -0
  50. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_atomicwrites.py +0 -0
  51. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_atools.py +0 -0
  52. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_cachetools.py +0 -0
  53. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_click.py +0 -0
  54. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_concurrent.py +0 -0
  55. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_contextlib.py +0 -0
  56. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_contextvars.py +0 -0
  57. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_cryptography.py +0 -0
  58. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_cvxpy.py +0 -0
  59. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_datetime.py +0 -0
  60. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_enum.py +0 -0
  61. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_errors.py +0 -0
  62. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_eventkit.py +0 -0
  63. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_fastapi.py +0 -0
  64. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_fpdf2.py +0 -0
  65. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_functions.py +0 -0
  66. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_functools.py +0 -0
  67. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_getpass.py +0 -0
  68. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_git.py +0 -0
  69. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_hashlib.py +0 -0
  70. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_http.py +0 -0
  71. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_hypothesis.py +0 -0
  72. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_ipython.py +0 -0
  73. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_iterables.py +0 -0
  74. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_jupyter.py +0 -0
  75. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_lightweight_charts.py +0 -0
  76. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_logging.py +0 -0
  77. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_loguru.py +0 -0
  78. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_luigi.py +0 -0
  79. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_math.py +0 -0
  80. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_memory_profiler.py +0 -0
  81. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_modules.py +0 -0
  82. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_more_itertools.py +0 -0
  83. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_numpy.py +0 -0
  84. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_operator.py +0 -0
  85. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_optuna.py +0 -0
  86. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_orjson.py +0 -0
  87. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_os.py +0 -0
  88. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_pathlib.py +0 -0
  89. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_period.py +0 -0
  90. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_pickle.py +0 -0
  91. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_platform.py +0 -0
  92. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_polars.py +0 -0
  93. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_polars_ols.py +0 -0
  94. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_pqdm.py +0 -0
  95. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_pydantic.py +0 -0
  96. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_pyinstrument.py +0 -0
  97. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_pyrsistent.py +0 -0
  98. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_pytest.py +0 -0
  99. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_pytest_regressions.py +0 -0
  100. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_python_dotenv.py +0 -0
  101. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_random.py +0 -0
  102. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_re.py +0 -0
  103. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_redis.py +0 -0
  104. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_reprlib.py +0 -0
  105. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_rich.py +0 -0
  106. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_scipy.py +0 -0
  107. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_sentinel.py +0 -0
  108. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_shelve.py +0 -0
  109. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_slack_sdk.py +0 -0
  110. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_socket.py +0 -0
  111. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_sqlalchemy.py +0 -0
  112. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_sqlalchemy_polars.py +0 -0
  113. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_statsmodel.py +0 -0
  114. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_streamlit.py +0 -0
  115. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_sys.py +0 -0
  116. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_tempfile.py +0 -0
  117. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_tenacity.py +0 -0
  118. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_text.py +0 -0
  119. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_threading.py +0 -0
  120. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_timer.py +0 -0
  121. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_traceback.py +0 -0
  122. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_traceback_funcs/__init__.py +0 -0
  123. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_traceback_funcs/chain.py +0 -0
  124. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
  125. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
  126. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_traceback_funcs/error_bind.py +0 -0
  127. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_traceback_funcs/many.py +0 -0
  128. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_traceback_funcs/one.py +0 -0
  129. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_traceback_funcs/recursive.py +0 -0
  130. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
  131. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
  132. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_traceback_funcs/two.py +0 -0
  133. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_traceback_funcs/untraced.py +0 -0
  134. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_types.py +0 -0
  135. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_typing.py +0 -0
  136. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_typing_funcs/__init__.py +0 -0
  137. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_typing_funcs/no_future.py +0 -0
  138. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_typing_funcs/with_future.py +0 -0
  139. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_tzdata.py +0 -0
  140. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_tzlocal.py +0 -0
  141. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_uuid.py +0 -0
  142. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_version.py +0 -0
  143. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_warnings.py +0 -0
  144. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_whenever.py +0 -0
  145. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_zipfile.py +0 -0
  146. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/tests/test_zoneinfo.py +0 -0
  147. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/altair.py +0 -0
  148. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/astor.py +0 -0
  149. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/asyncio.py +0 -0
  150. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/atomicwrites.py +0 -0
  151. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/atools.py +0 -0
  152. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/cachetools.py +0 -0
  153. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/click.py +0 -0
  154. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/concurrent.py +0 -0
  155. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/contextlib.py +0 -0
  156. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/contextvars.py +0 -0
  157. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/cryptography.py +0 -0
  158. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/cvxpy.py +0 -0
  159. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/datetime.py +0 -0
  160. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/enum.py +0 -0
  161. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/errors.py +0 -0
  162. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/eventkit.py +0 -0
  163. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/fastapi.py +0 -0
  164. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/fpdf2.py +0 -0
  165. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/functions.py +0 -0
  166. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/functools.py +0 -0
  167. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/getpass.py +0 -0
  168. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/git.py +0 -0
  169. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/hashlib.py +0 -0
  170. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/http.py +0 -0
  171. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/hypothesis.py +0 -0
  172. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/ipython.py +0 -0
  173. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/iterables.py +0 -0
  174. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/jupyter.py +0 -0
  175. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/lightweight_charts.py +0 -0
  176. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/logging.py +0 -0
  177. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/loguru.py +0 -0
  178. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/luigi.py +0 -0
  179. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/math.py +0 -0
  180. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/memory_profiler.py +0 -0
  181. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/modules.py +0 -0
  182. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/more_itertools.py +0 -0
  183. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/numpy.py +0 -0
  184. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/operator.py +0 -0
  185. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/optuna.py +0 -0
  186. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/orjson.py +0 -0
  187. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/os.py +0 -0
  188. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/pathlib.py +0 -0
  189. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/period.py +0 -0
  190. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/pickle.py +0 -0
  191. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/platform.py +0 -0
  192. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/polars.py +0 -0
  193. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/polars_ols.py +0 -0
  194. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/pqdm.py +0 -0
  195. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/py.typed +0 -0
  196. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/pydantic.py +0 -0
  197. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/pyinstrument.py +0 -0
  198. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/pyrsistent.py +0 -0
  199. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/pytest.py +0 -0
  200. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/pytest_regressions.py +0 -0
  201. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/random.py +0 -0
  202. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/re.py +0 -0
  203. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/redis.py +0 -0
  204. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/reprlib.py +0 -0
  205. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/rich.py +0 -0
  206. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/scipy.py +0 -0
  207. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/sentinel.py +0 -0
  208. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/shelve.py +0 -0
  209. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/slack_sdk.py +0 -0
  210. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/socket.py +0 -0
  211. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/sqlalchemy.py +0 -0
  212. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/sqlalchemy_polars.py +0 -0
  213. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/statsmodels.py +0 -0
  214. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/streamlit.py +0 -0
  215. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/sys.py +0 -0
  216. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/tempfile.py +0 -0
  217. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/tenacity.py +0 -0
  218. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/text.py +0 -0
  219. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/threading.py +0 -0
  220. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/timer.py +0 -0
  221. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/traceback.py +0 -0
  222. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/typing.py +0 -0
  223. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/tzdata.py +0 -0
  224. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/tzlocal.py +0 -0
  225. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/uuid.py +0 -0
  226. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/version.py +0 -0
  227. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/warnings.py +0 -0
  228. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/whenever.py +0 -0
  229. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/src/utilities/zipfile.py +0 -0
  230. {dycw_utilities-0.109.28 → dycw_utilities-0.110.0}/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.28
3
+ Version: 0.110.0
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -40,6 +40,7 @@ dev = [
40
40
  "optuna >= 4.3.0, < 4.4",
41
41
  "orjson >= 3.10.16, < 3.11",
42
42
  "pathvalidate >= 3.2.3, < 3.3",
43
+ "polars >= 1.27.1, < 1.28",
43
44
  "polars-lts-cpu >= 1.27.1, < 1.28",
44
45
  "polars-ols >= 0.3.5, < 0.4",
45
46
  "pqdm >= 0.2.0, < 0.3",
@@ -93,7 +94,7 @@ dependencies = [
93
94
  name = "dycw-utilities"
94
95
  readme = "README.md"
95
96
  requires-python = ">= 3.12"
96
- version = "0.109.28"
97
+ version = "0.110.0"
97
98
 
98
99
  [project.optional-dependencies]
99
100
  test = [
@@ -336,7 +337,7 @@ zzz-test-zoneinfo = [
336
337
  # bump-my-version
337
338
  [tool.bumpversion]
338
339
  allow_dirty = true
339
- current_version = "0.109.28"
340
+ current_version = "0.110.0"
340
341
 
341
342
  [[tool.bumpversion.files]]
342
343
  filename = "src/utilities/__init__.py"
@@ -38,17 +38,19 @@ from utilities.dataclasses import (
38
38
  OneFieldNonUniqueError,
39
39
  StrMappingToFieldMappingError,
40
40
  YieldFieldsError,
41
- _TextToDataClassParseValueError,
42
- _TextToDataClassSplitKeyValuePairError,
41
+ _ParseDataClassParseValueError,
42
+ _ParseDataClassSplitKeyValuePairsDuplicateKeysError,
43
+ _ParseDataClassSplitKeyValuePairsSplitError,
43
44
  _YieldFieldsClass,
44
45
  _YieldFieldsInstance,
45
46
  dataclass_repr,
46
47
  dataclass_to_dict,
47
48
  mapping_to_dataclass,
48
49
  one_field,
50
+ parse_dataclass,
49
51
  replace_non_sentinel,
52
+ serialize_dataclass,
50
53
  str_mapping_to_field_mapping,
51
- text_to_dataclass,
52
54
  yield_fields,
53
55
  )
54
56
  from utilities.functions import get_class_name
@@ -465,48 +467,68 @@ class TestStrMappingToFieldMapping:
465
467
  )
466
468
 
467
469
 
468
- class TestTextToDataClass:
470
+ class TestSerializeAndParseDataClass:
471
+ @given(int_=integers())
472
+ def test_main_future_int(self, *, int_: int) -> None:
473
+ obj = DataClassFutureInt(int_=int_)
474
+ serialized = serialize_dataclass(obj)
475
+ result = parse_dataclass(serialized, DataClassFutureInt)
476
+ assert result == obj
477
+
478
+ def test_main_future_int_default(self) -> None:
479
+ obj = DataClassFutureIntDefault()
480
+ serialized = serialize_dataclass(obj)
481
+ result = parse_dataclass(serialized, DataClassFutureIntDefault)
482
+ assert result == obj
483
+
469
484
  @given(key=sampled_from(["int_", "INT_"]), int_=integers())
470
- def test_main_text_case_insensitive(self, *, key: str, int_: int) -> None:
471
- result = text_to_dataclass(f"{key}={int_}", DataClassFutureInt)
485
+ def test_parse_text_case_insensitive(self, *, key: str, int_: int) -> None:
486
+ result = parse_dataclass(f"{key}={int_}", DataClassFutureInt)
472
487
  expected = DataClassFutureInt(int_=int_)
473
488
  assert result == expected
474
489
 
475
490
  @given(int_=integers())
476
- def test_main_text_case_sensitive(self, *, int_: int) -> None:
477
- result = text_to_dataclass(
491
+ def test_parse_text_case_sensitive(self, *, int_: int) -> None:
492
+ result = parse_dataclass(
478
493
  f"int_={int_}", DataClassFutureInt, case_sensitive=True
479
494
  )
480
495
  expected = DataClassFutureInt(int_=int_)
481
496
  assert result == expected
482
497
 
483
498
  @given(key=sampled_from(["int_", "INT_"]), int_=integers())
484
- def test_main_mapping_case_insensitive(self, *, key: str, int_: int) -> None:
485
- result = text_to_dataclass({key: str(int_)}, DataClassFutureInt)
499
+ def test_parse_mapping_case_insensitive(self, *, key: str, int_: int) -> None:
500
+ result = parse_dataclass({key: str(int_)}, DataClassFutureInt)
486
501
  expected = DataClassFutureInt(int_=int_)
487
502
  assert result == expected
488
503
 
489
504
  @given(int_=integers())
490
- def test_main_mapping_case_sensitive(self, *, int_: int) -> None:
491
- result = text_to_dataclass(
505
+ def test_parse_mapping_case_sensitive(self, *, int_: int) -> None:
506
+ result = parse_dataclass(
492
507
  {"int_": str(int_)}, DataClassFutureInt, case_sensitive=True
493
508
  )
494
509
  expected = DataClassFutureInt(int_=int_)
495
510
  assert result == expected
496
511
 
497
- def test_error_split_key_value_pair(self) -> None:
512
+ def test_parser_split_key_value_pairs_split(self) -> None:
513
+ with raises(
514
+ _ParseDataClassSplitKeyValuePairsSplitError,
515
+ match="Unable to construct 'DataClassFutureInt'; failed to split key-value pair 'bbb'",
516
+ ):
517
+ _ = parse_dataclass("a=1,bbb,c=333", DataClassFutureInt)
518
+
519
+ def test_error_parse_split_key_value_pairs_duplicate(self) -> None:
498
520
  with raises(
499
- _TextToDataClassSplitKeyValuePairError,
500
- match="Unable to construct 'DataClassFutureInt'; failed to split key-value pair 'keyvalue'",
521
+ _ParseDataClassSplitKeyValuePairsDuplicateKeysError,
522
+ match=r"Unable to construct 'DataClassFutureInt' since there are duplicate keys; got \{'b': 2\}",
501
523
  ):
502
- _ = text_to_dataclass("keyvalue", DataClassFutureInt)
524
+ _ = parse_dataclass("a=1,b=22a,b=22b,c=3", DataClassFutureInt)
503
525
 
504
526
  def test_error_parse_value(self) -> None:
505
527
  with raises(
506
- _TextToDataClassParseValueError,
528
+ _ParseDataClassParseValueError,
507
529
  match="Unable to construct 'DataClassFutureInt'; unable to parse field 'int_' of type <class 'int'>; got 'invalid'",
508
530
  ):
509
- _ = text_to_dataclass("int_=invalid", DataClassFutureInt)
531
+ _ = parse_dataclass("int_=invalid", DataClassFutureInt)
510
532
 
511
533
 
512
534
  class TestYieldFields:
@@ -0,0 +1,543 @@
1
+ from __future__ import annotations
2
+
3
+ import datetime as dt
4
+ from collections.abc import Iterable
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+ from types import NoneType
8
+ from typing import Final, Literal
9
+
10
+ from hypothesis import given
11
+ from hypothesis.strategies import (
12
+ booleans,
13
+ dates,
14
+ dictionaries,
15
+ floats,
16
+ frozensets,
17
+ integers,
18
+ lists,
19
+ sampled_from,
20
+ sets,
21
+ times,
22
+ )
23
+ from pytest import raises
24
+
25
+ from tests.test_operator import TruthEnum
26
+ from tests.test_typing_funcs.with_future import (
27
+ DataClassFutureInt,
28
+ DataClassFutureIntEven,
29
+ DataClassFutureIntEvenOrOddTypeUnion,
30
+ DataClassFutureIntEvenOrOddUnion,
31
+ DataClassFutureIntOdd,
32
+ TrueOrFalseFutureLit,
33
+ TrueOrFalseFutureTypeLit,
34
+ )
35
+ from utilities.errors import ImpossibleCaseError
36
+ from utilities.functions import ensure_path
37
+ from utilities.hypothesis import (
38
+ datetime_durations,
39
+ local_datetimes,
40
+ numbers,
41
+ paths,
42
+ text_ascii,
43
+ timedeltas_2w,
44
+ versions,
45
+ zoned_datetimes,
46
+ )
47
+ from utilities.math import is_equal
48
+ from utilities.parse import (
49
+ _ParseObjectExtraNonUniqueError,
50
+ _ParseObjectParseError,
51
+ parse_object,
52
+ serialize_object,
53
+ )
54
+ from utilities.sentinel import Sentinel, sentinel
55
+ from utilities.types import Duration, Number
56
+ from utilities.version import Version
57
+
58
+
59
+ class TestSerializeAndParseObject:
60
+ @given(value=booleans())
61
+ def test_bool(self, *, value: bool) -> None:
62
+ serialized = serialize_object(value)
63
+ result = parse_object(bool, serialized)
64
+ assert result is value
65
+
66
+ @given(date=dates())
67
+ def test_date(self, *, date: dt.date) -> None:
68
+ serialized = serialize_object(date)
69
+ result = parse_object(dt.date, serialized)
70
+ assert result == date
71
+
72
+ @given(datetime=local_datetimes() | zoned_datetimes())
73
+ def test_datetime(self, *, datetime: dt.datetime) -> None:
74
+ serialized = serialize_object(datetime)
75
+ result = parse_object(dt.datetime, serialized)
76
+ assert result == datetime
77
+
78
+ @given(value=dictionaries(dates(), zoned_datetimes()))
79
+ def test_dict(self, *, value: dict[dt.date, dt.datetime]) -> None:
80
+ serialized = serialize_object(value)
81
+ result = parse_object(dict[dt.date, dt.datetime], serialized)
82
+ assert result == value
83
+
84
+ @given(duration=datetime_durations(two_way=True))
85
+ def test_duration(self, *, duration: Duration) -> None:
86
+ serialized = serialize_object(duration)
87
+ result = parse_object(Duration, serialized)
88
+ assert result == duration
89
+
90
+ @given(truth=sampled_from(TruthEnum))
91
+ def test_enum(self, *, truth: TruthEnum) -> None:
92
+ serialized = serialize_object(truth)
93
+ result = parse_object(TruthEnum, serialized)
94
+ assert result is truth
95
+
96
+ @given(value=integers())
97
+ def test_extra_type(self, *, value: int) -> None:
98
+ serialized = serialize_object(value)
99
+ result = parse_object(
100
+ DataClassFutureInt,
101
+ serialized,
102
+ extra={
103
+ DataClassFutureInt: lambda serialized: DataClassFutureInt(
104
+ int_=int(serialized)
105
+ )
106
+ },
107
+ )
108
+ expected = DataClassFutureInt(int_=value)
109
+ assert result == expected
110
+
111
+ @given(value=floats())
112
+ def test_float(self, *, value: float) -> None:
113
+ serialized = serialize_object(value)
114
+ result = parse_object(float, serialized)
115
+ assert is_equal(result, value)
116
+
117
+ @given(values=frozensets(dates()))
118
+ def test_frozenset(self, *, values: frozenset[dt.date]) -> None:
119
+ serialized = serialize_object(values)
120
+ result = parse_object(frozenset[dt.date], serialized)
121
+ assert result == values
122
+
123
+ @given(value=integers())
124
+ def test_int(self, *, value: int) -> None:
125
+ serialized = serialize_object(value)
126
+ result = parse_object(int, serialized)
127
+ assert result == value
128
+
129
+ @given(values=lists(dates()))
130
+ def test_list(self, *, values: list[dt.date]) -> None:
131
+ serialized = serialize_object(values)
132
+ result = parse_object(list[dt.date], serialized)
133
+ assert result == values
134
+
135
+ @given(truth=sampled_from(["true", "false"]))
136
+ def test_literal(self, *, truth: Literal["true", "false"]) -> None:
137
+ result = parse_object(TrueOrFalseFutureLit, truth)
138
+ assert result == truth
139
+
140
+ def test_none(self) -> None:
141
+ serialized = serialize_object(None)
142
+ result = parse_object(None, serialized)
143
+ assert result is None
144
+
145
+ def test_none_type(self) -> None:
146
+ serialized = serialize_object(None)
147
+ result = parse_object(NoneType, serialized)
148
+ assert result is None
149
+
150
+ @given(number=numbers())
151
+ def test_number(self, *, number: Number) -> None:
152
+ serialized = serialize_object(number)
153
+ result = parse_object(Number, serialized)
154
+ assert result == number
155
+
156
+ @given(path=paths())
157
+ def test_path(self, *, path: Path) -> None:
158
+ serialized = serialize_object(path)
159
+ result = parse_object(Path, serialized)
160
+ assert result == path
161
+
162
+ @given(path=paths())
163
+ def test_path_expanded(self, *, path: Path) -> None:
164
+ path_use = Path("~", path)
165
+ serialized = serialize_object(path_use)
166
+ result = ensure_path(parse_object(Path, serialized))
167
+ assert result == result.expanduser()
168
+
169
+ def test_nullable_number_none(self) -> None:
170
+ serialized = serialize_object(None)
171
+ result = parse_object(Number | None, serialized)
172
+ assert result is None
173
+
174
+ @given(number=numbers())
175
+ def test_nullable_number_number(self, *, number: Number) -> None:
176
+ serialized = serialize_object(number)
177
+ result = parse_object(Number | None, serialized)
178
+ assert result == number
179
+
180
+ def test_nullable_duration_none(self) -> None:
181
+ serialized = serialize_object(None)
182
+ result = parse_object(Duration | None, serialized)
183
+ assert result is None
184
+
185
+ @given(duration=datetime_durations(two_way=True))
186
+ def test_nullable_duration_duration(self, *, duration: Duration) -> None:
187
+ serialized = serialize_object(duration)
188
+ result = parse_object(Duration | None, serialized)
189
+ assert result == duration
190
+
191
+ def test_nullable_int_none(self) -> None:
192
+ serialized = serialize_object(None)
193
+ result = parse_object(int | None, serialized)
194
+ assert result is None
195
+
196
+ @given(value=integers())
197
+ def test_nullable_int_int(self, *, value: int) -> None:
198
+ serialized = serialize_object(value)
199
+ result = parse_object(int | None, serialized)
200
+ assert result == value
201
+
202
+ def test_sentinel(self) -> None:
203
+ serialized = serialize_object(sentinel)
204
+ result = parse_object(Sentinel, serialized)
205
+ assert result is sentinel
206
+
207
+ @given(values=sets(dates()))
208
+ def test_set(self, *, values: set[dt.date]) -> None:
209
+ serialized = serialize_object(values)
210
+ result = parse_object(set[dt.date], serialized)
211
+ assert result == values
212
+
213
+ @given(serialized=text_ascii())
214
+ def test_to_serialized(self, *, serialized: str) -> None:
215
+ result = parse_object(str, serialized)
216
+ assert result == serialized
217
+
218
+ @given(time=times())
219
+ def test_time(self, *, time: dt.time) -> None:
220
+ serialized = serialize_object(time)
221
+ result = parse_object(dt.time, serialized)
222
+ assert result == time
223
+
224
+ @given(timedelta=timedeltas_2w())
225
+ def test_timedelta(self, *, timedelta: dt.timedelta) -> None:
226
+ serialized = serialize_object(timedelta)
227
+ result = parse_object(dt.timedelta, serialized)
228
+ assert result == timedelta
229
+
230
+ @given(x=integers(), y=integers())
231
+ def test_tuple(self, *, x: int, y: int) -> None:
232
+ serialized = serialize_object((x, y))
233
+ result = parse_object(tuple[int, int], serialized)
234
+ assert result == (x, y)
235
+
236
+ @given(truth=sampled_from(["true", "false"]))
237
+ def test_type_literal(self, *, truth: Literal["true", "false"]) -> None:
238
+ result = parse_object(TrueOrFalseFutureTypeLit, truth)
239
+ assert result == truth
240
+
241
+ @given(value=integers())
242
+ def test_type_union_with_extra(self, *, value: int) -> None:
243
+ def parse_even_or_odd(text: str, /) -> DataClassFutureIntEvenOrOddTypeUnion:
244
+ value = int(text)
245
+ match value % 2:
246
+ case 0:
247
+ return DataClassFutureIntEven(even_int=value)
248
+ case 1:
249
+ return DataClassFutureIntOdd(odd_int=value)
250
+ case _:
251
+ raise ImpossibleCaseError(case=[f"{value=}"])
252
+
253
+ serialized = serialize_object(value)
254
+ result = parse_object(
255
+ DataClassFutureIntEvenOrOddTypeUnion,
256
+ serialized,
257
+ extra={DataClassFutureIntEvenOrOddTypeUnion: parse_even_or_odd},
258
+ )
259
+ match value % 2:
260
+ case 0:
261
+ expected = DataClassFutureIntEven(even_int=value)
262
+ case 1:
263
+ expected = DataClassFutureIntOdd(odd_int=value)
264
+ case _:
265
+ raise ImpossibleCaseError(case=[f"{value=}"])
266
+ assert result == expected
267
+
268
+ @given(value=integers())
269
+ def test_union_with_extra(self, *, value: int) -> None:
270
+ def parse_even_or_odd(text: str, /) -> DataClassFutureIntEvenOrOddUnion:
271
+ value = int(text)
272
+ match value % 2:
273
+ case 0:
274
+ return DataClassFutureIntEven(even_int=value)
275
+ case 1:
276
+ return DataClassFutureIntOdd(odd_int=value)
277
+ case _:
278
+ raise ImpossibleCaseError(case=[f"{value=}"])
279
+
280
+ serialized = serialize_object(value)
281
+ result = parse_object(
282
+ DataClassFutureIntEvenOrOddUnion,
283
+ serialized,
284
+ extra={DataClassFutureIntEvenOrOddUnion: parse_even_or_odd},
285
+ )
286
+ match value % 2:
287
+ case 0:
288
+ expected = DataClassFutureIntEven(even_int=value)
289
+ case 1:
290
+ expected = DataClassFutureIntOdd(odd_int=value)
291
+ case _:
292
+ raise ImpossibleCaseError(case=[f"{value=}"])
293
+ assert result == expected
294
+
295
+ @given(version=versions())
296
+ def test_version(self, *, version: Version) -> None:
297
+ serialized = serialize_object(version)
298
+ result = parse_object(Version, serialized)
299
+ assert result == version
300
+
301
+
302
+ class TestParseSerialized:
303
+ def test_error_bool(self) -> None:
304
+ with raises(
305
+ _ParseObjectParseError,
306
+ match="Unable to parse <class 'bool'>; got 'invalid'",
307
+ ):
308
+ _ = parse_object(bool, "invalid")
309
+
310
+ def test_error_date(self) -> None:
311
+ with raises(
312
+ _ParseObjectParseError,
313
+ match=r"Unable to parse <class 'datetime\.date'>; got 'invalid'",
314
+ ):
315
+ _ = parse_object(dt.date, "invalid")
316
+
317
+ def test_error_datetime(self) -> None:
318
+ with raises(
319
+ _ParseObjectParseError,
320
+ match=r"Unable to parse <class 'datetime\.datetime'>; got 'invalid'",
321
+ ):
322
+ _ = parse_object(dt.datetime, "invalid")
323
+
324
+ def test_error_dict_extract_group(self) -> None:
325
+ with raises(
326
+ _ParseObjectParseError,
327
+ match=r"Unable to parse dict\[int, int\]; got 'invalid'",
328
+ ):
329
+ _ = parse_object(dict[int, int], "invalid")
330
+
331
+ def test_error_dict_internal(self) -> None:
332
+ with raises(
333
+ _ParseObjectParseError,
334
+ match=r"Unable to parse dict\[int, int\]; got '\{invalid=invalid\}'",
335
+ ):
336
+ _ = parse_object(dict[int, int], "{invalid=invalid}")
337
+
338
+ def test_error_duration(self) -> None:
339
+ with raises(
340
+ _ParseObjectParseError, match=r"Unable to parse Duration; got 'invalid'"
341
+ ):
342
+ _ = parse_object(Duration, "invalid")
343
+
344
+ def test_error_enum(self) -> None:
345
+ with raises(
346
+ _ParseObjectParseError,
347
+ match="Unable to parse <enum 'TruthEnum'>; got 'invalid'",
348
+ ):
349
+ _ = parse_object(TruthEnum, "invalid")
350
+
351
+ def test_error_extra_empty(self) -> None:
352
+ with raises(
353
+ _ParseObjectParseError,
354
+ match="Unable to parse <class 'tests.test_typing_funcs.with_future.DataClassFutureInt'>; got 'invalid'",
355
+ ):
356
+ _ = parse_object(DataClassFutureInt, "invalid", extra={})
357
+
358
+ @given(value=integers())
359
+ def test_error_extra_non_unique(self, *, value: int) -> None:
360
+ @dataclass(kw_only=True)
361
+ class Parent1:
362
+ x: int = 0
363
+
364
+ @dataclass(kw_only=True)
365
+ class Parent2:
366
+ y: int = 0
367
+
368
+ @dataclass(kw_only=True)
369
+ class Child(Parent1, Parent2): ...
370
+
371
+ with raises(
372
+ _ParseObjectExtraNonUniqueError,
373
+ match="Unable to parse <class '.*'> since `extra` must contain exactly one parent class; got <function .*>, <function .*> and perhaps more",
374
+ ):
375
+ _ = parse_object(
376
+ Child,
377
+ serialize_object(value),
378
+ extra={
379
+ Parent1: lambda serialized: Child(x=int(serialized)),
380
+ Parent2: lambda serialized: Child(y=int(serialized)),
381
+ },
382
+ )
383
+
384
+ def test_error_union_type_extra(self) -> None:
385
+ with raises(
386
+ _ParseObjectParseError,
387
+ match=r"Unable to parse tests\.test_typing_funcs\.with_future\.DataClassFutureIntEven \| tests\.test_typing_funcs\.with_future\.DataClassFutureIntOdd; got 'invalid'",
388
+ ):
389
+ _ = parse_object(DataClassFutureIntEvenOrOddUnion, "invalid", extra={})
390
+
391
+ def test_error_float(self) -> None:
392
+ with raises(
393
+ _ParseObjectParseError,
394
+ match="Unable to parse <class 'float'>; got 'invalid'",
395
+ ):
396
+ _ = parse_object(float, "invalid")
397
+
398
+ def test_error_frozenset_extract_group(self) -> None:
399
+ with raises(
400
+ _ParseObjectParseError,
401
+ match=r"Unable to parse frozenset\[int\]; got 'invalid'",
402
+ ):
403
+ _ = parse_object(frozenset[int], "invalid")
404
+
405
+ def test_error_frozenset_internal(self) -> None:
406
+ with raises(
407
+ _ParseObjectParseError,
408
+ match=r"Unable to parse frozenset\[int\]; got '\{invalid\}'",
409
+ ):
410
+ _ = parse_object(frozenset[int], "{invalid}")
411
+
412
+ def test_error_int(self) -> None:
413
+ with raises(
414
+ _ParseObjectParseError, match="Unable to parse <class 'int'>; got 'invalid'"
415
+ ):
416
+ _ = parse_object(int, "invalid")
417
+
418
+ def test_error_list_extract_group(self) -> None:
419
+ with raises(
420
+ _ParseObjectParseError, match=r"Unable to parse list\[int\]; got 'invalid'"
421
+ ):
422
+ _ = parse_object(list[int], "invalid")
423
+
424
+ def test_error_list_internal(self) -> None:
425
+ with raises(
426
+ _ParseObjectParseError,
427
+ match=r"Unable to parse list\[int\]; got '\[invalid\]'",
428
+ ):
429
+ _ = parse_object(list[int], "[invalid]")
430
+
431
+ def test_error_none(self) -> None:
432
+ with raises(
433
+ _ParseObjectParseError, match="Unable to parse None; got 'invalid'"
434
+ ):
435
+ _ = parse_object(None, "invalid")
436
+
437
+ def test_error_none_type(self) -> None:
438
+ with raises(
439
+ _ParseObjectParseError,
440
+ match="Unable to parse <class 'NoneType'>; got 'invalid'",
441
+ ):
442
+ _ = parse_object(NoneType, "invalid")
443
+
444
+ def test_error_nullable_int(self) -> None:
445
+ with raises(
446
+ _ParseObjectParseError, match=r"Unable to parse int \| None; got 'invalid'"
447
+ ):
448
+ _ = parse_object(int | None, "invalid")
449
+
450
+ def test_error_nullable_not_type(self) -> None:
451
+ with raises(
452
+ _ParseObjectParseError,
453
+ match=r"Unable to parse collections\.abc\.Iterable\[None\] \| None; got 'invalid'",
454
+ ):
455
+ _ = parse_object(Iterable[None] | None, "invalid")
456
+
457
+ def test_error_number(self) -> None:
458
+ with raises(
459
+ _ParseObjectParseError, match=r"Unable to parse Number; got 'invalid'"
460
+ ):
461
+ _ = parse_object(Number, "invalid")
462
+
463
+ def test_error_sentinel(self) -> None:
464
+ with raises(
465
+ _ParseObjectParseError,
466
+ match=r"Unable to parse <class 'utilities\.sentinel\.Sentinel'>; got 'invalid'",
467
+ ):
468
+ _ = parse_object(Sentinel, "invalid")
469
+
470
+ def test_error_set_extract_group(self) -> None:
471
+ with raises(
472
+ _ParseObjectParseError, match=r"Unable to parse set\[int\]; got 'invalid'"
473
+ ):
474
+ _ = parse_object(set[int], "invalid")
475
+
476
+ def test_error_set_internal(self) -> None:
477
+ with raises(
478
+ _ParseObjectParseError,
479
+ match=r"Unable to parse set\[int\]; got '\{invalid\}'",
480
+ ):
481
+ _ = parse_object(set[int], "{invalid}")
482
+
483
+ def test_error_time(self) -> None:
484
+ with raises(
485
+ _ParseObjectParseError,
486
+ match=r"Unable to parse <class 'datetime\.time'>; got 'invalid'",
487
+ ):
488
+ _ = parse_object(dt.time, "invalid")
489
+
490
+ def test_error_timedelta(self) -> None:
491
+ with raises(
492
+ _ParseObjectParseError,
493
+ match=r"Unable to parse <class 'datetime\.timedelta'>; got 'invalid'",
494
+ ):
495
+ _ = parse_object(dt.timedelta, "invalid")
496
+
497
+ def test_error_tuple_extract_group(self) -> None:
498
+ with raises(
499
+ _ParseObjectParseError,
500
+ match=r"Unable to parse tuple\[int, int\]; got 'invalid'",
501
+ ):
502
+ _ = parse_object(tuple[int, int], "invalid")
503
+
504
+ def test_error_tuple_internal(self) -> None:
505
+ with raises(
506
+ _ParseObjectParseError,
507
+ match=r"Unable to parse tuple\[int, int\]; got '\(invalid,invalid\)'",
508
+ ):
509
+ _ = parse_object(tuple[int, int], "(invalid,invalid)")
510
+
511
+ def test_error_tuple_inconsistent_args_and_serializeds(self) -> None:
512
+ with raises(
513
+ _ParseObjectParseError,
514
+ match=r"Unable to parse tuple\[int, int\]; got '\(serialized1, serialized2, serialized3\)'",
515
+ ):
516
+ _ = parse_object(tuple[int, int], "(serialized1, serialized2, serialized3)")
517
+
518
+ def test_error_type_not_implemented(self) -> None:
519
+ with raises(
520
+ _ParseObjectParseError,
521
+ match=r"Unable to parse <class 'tests\.test_typing_funcs\.with_future\.DataClassFutureInt'>; got 'invalid'",
522
+ ):
523
+ _ = parse_object(DataClassFutureInt, "invalid")
524
+
525
+ def test_error_union_not_implemented(self) -> None:
526
+ with raises(
527
+ _ParseObjectParseError,
528
+ match=r"Unable to parse tests\.test_typing_funcs\.with_future\.DataClassFutureIntEven \| tests\.test_typing_funcs\.with_future\.DataClassFutureIntOdd; got 'invalid'",
529
+ ):
530
+ _ = parse_object(DataClassFutureIntEvenOrOddUnion, "invalid")
531
+
532
+ def test_error_version(self) -> None:
533
+ with raises(
534
+ _ParseObjectParseError,
535
+ match=r"Unable to parse <class 'utilities\.version\.Version'>; got 'invalid'",
536
+ ):
537
+ _ = parse_object(Version, "invalid")
538
+
539
+
540
+ class TestSerializeObject:
541
+ def test_error_not_implemented(self) -> None:
542
+ with raises(NotImplementedError):
543
+ _ = serialize_object(Final)
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.109.28"
3
+ __version__ = "0.110.0"