dycw-utilities 0.112.4__tar.gz → 0.112.6__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.4 → dycw_utilities-0.112.6}/PKG-INFO +1 -1
  2. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/pyproject.toml +2 -2
  3. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_dataclasses.py +16 -4
  4. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_parse.py +38 -41
  5. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_typing.py +25 -7
  6. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_typing_funcs/with_future.py +0 -16
  7. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/__init__.py +1 -1
  8. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/dataclasses.py +25 -5
  9. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/parse.py +15 -13
  10. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/typing.py +10 -6
  11. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/.gitignore +0 -0
  12. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/LICENSE +0 -0
  13. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/README.md +0 -0
  14. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/__init__.py +0 -0
  15. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/conftest.py +0 -0
  16. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/modules/__init__.py +0 -0
  17. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/modules/package_missing/__init__.py +0 -0
  18. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/modules/package_missing/module.py +0 -0
  19. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/modules/package_with/__init__.py +0 -0
  20. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/modules/package_with/outer_1.py +0 -0
  21. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/modules/package_with/outer_2.py +0 -0
  22. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  23. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  24. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  25. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  26. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/modules/package_without/__init__.py +0 -0
  27. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/modules/package_without/module_1.py +0 -0
  28. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/modules/package_without/module_2.py +0 -0
  29. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/modules/standalone.py +0 -0
  30. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/modules/with_imports.py +0 -0
  31. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  32. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  33. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  34. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  35. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  36. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  37. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  38. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  39. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/scripts/__init__.py +0 -0
  40. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/scripts/test_async_service/__init__.py +0 -0
  41. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/scripts/test_async_service/__main__.py +0 -0
  42. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/scripts/test_async_service/run.sh +0 -0
  43. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/scripts/test_queue_processor/__init__.py +0 -0
  44. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/scripts/test_queue_processor/__main__.py +0 -0
  45. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/scripts/test_queue_processor/run.sh +0 -0
  46. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_altair.py +0 -0
  47. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_astor.py +0 -0
  48. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_asyncio.py +0 -0
  49. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_atomicwrites.py +0 -0
  50. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_atools.py +0 -0
  51. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_cachetools.py +0 -0
  52. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_click.py +0 -0
  53. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_concurrent.py +0 -0
  54. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_contextlib.py +0 -0
  55. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_contextvars.py +0 -0
  56. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_cryptography.py +0 -0
  57. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_cvxpy.py +0 -0
  58. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_datetime.py +0 -0
  59. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_enum.py +0 -0
  60. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_errors.py +0 -0
  61. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_eventkit.py +0 -0
  62. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_fastapi.py +0 -0
  63. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_fpdf2.py +0 -0
  64. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_functions.py +0 -0
  65. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_functools.py +0 -0
  66. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_getpass.py +0 -0
  67. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_git.py +0 -0
  68. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_hashlib.py +0 -0
  69. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_http.py +0 -0
  70. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_hypothesis.py +0 -0
  71. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_ipython.py +0 -0
  72. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_iterables.py +0 -0
  73. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_jupyter.py +0 -0
  74. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_lightweight_charts.py +0 -0
  75. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_logging.py +0 -0
  76. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_loguru.py +0 -0
  77. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_luigi.py +0 -0
  78. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_math.py +0 -0
  79. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_memory_profiler.py +0 -0
  80. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_modules.py +0 -0
  81. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_more_itertools.py +0 -0
  82. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_numpy.py +0 -0
  83. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_operator.py +0 -0
  84. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_optuna.py +0 -0
  85. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_orjson.py +0 -0
  86. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_os.py +0 -0
  87. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_pathlib.py +0 -0
  88. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_period.py +0 -0
  89. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_pickle.py +0 -0
  90. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_platform.py +0 -0
  91. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_polars.py +0 -0
  92. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_polars_ols.py +0 -0
  93. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_pqdm.py +0 -0
  94. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_pydantic.py +0 -0
  95. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_pyinstrument.py +0 -0
  96. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_pyrsistent.py +0 -0
  97. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_pytest.py +0 -0
  98. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_pytest_regressions.py +0 -0
  99. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_python_dotenv.py +0 -0
  100. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_random.py +0 -0
  101. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_re.py +0 -0
  102. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_redis.py +0 -0
  103. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_reprlib.py +0 -0
  104. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_rich.py +0 -0
  105. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_scipy.py +0 -0
  106. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_sentinel.py +0 -0
  107. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_shelve.py +0 -0
  108. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_slack_sdk.py +0 -0
  109. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_socket.py +0 -0
  110. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_sqlalchemy.py +0 -0
  111. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_sqlalchemy_polars.py +0 -0
  112. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_statsmodel.py +0 -0
  113. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_streamlit.py +0 -0
  114. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_sys.py +0 -0
  115. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_tempfile.py +0 -0
  116. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_tenacity.py +0 -0
  117. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_text.py +0 -0
  118. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_threading.py +0 -0
  119. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_timer.py +0 -0
  120. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_traceback.py +0 -0
  121. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_traceback_funcs/__init__.py +0 -0
  122. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_traceback_funcs/chain.py +0 -0
  123. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
  124. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
  125. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_traceback_funcs/error_bind.py +0 -0
  126. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_traceback_funcs/many.py +0 -0
  127. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_traceback_funcs/one.py +0 -0
  128. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_traceback_funcs/recursive.py +0 -0
  129. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
  130. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
  131. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_traceback_funcs/two.py +0 -0
  132. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_traceback_funcs/untraced.py +0 -0
  133. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_types.py +0 -0
  134. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_typing_funcs/__init__.py +0 -0
  135. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_typing_funcs/no_future.py +0 -0
  136. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_tzdata.py +0 -0
  137. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_tzlocal.py +0 -0
  138. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_uuid.py +0 -0
  139. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_version.py +0 -0
  140. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_warnings.py +0 -0
  141. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_whenever.py +0 -0
  142. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_zipfile.py +0 -0
  143. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/tests/test_zoneinfo.py +0 -0
  144. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/altair.py +0 -0
  145. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/astor.py +0 -0
  146. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/asyncio.py +0 -0
  147. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/atomicwrites.py +0 -0
  148. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/atools.py +0 -0
  149. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/cachetools.py +0 -0
  150. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/click.py +0 -0
  151. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/concurrent.py +0 -0
  152. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/contextlib.py +0 -0
  153. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/contextvars.py +0 -0
  154. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/cryptography.py +0 -0
  155. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/cvxpy.py +0 -0
  156. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/datetime.py +0 -0
  157. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/enum.py +0 -0
  158. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/errors.py +0 -0
  159. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/eventkit.py +0 -0
  160. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/fastapi.py +0 -0
  161. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/fpdf2.py +0 -0
  162. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/functions.py +0 -0
  163. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/functools.py +0 -0
  164. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/getpass.py +0 -0
  165. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/git.py +0 -0
  166. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/hashlib.py +0 -0
  167. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/http.py +0 -0
  168. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/hypothesis.py +0 -0
  169. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/ipython.py +0 -0
  170. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/iterables.py +0 -0
  171. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/jupyter.py +0 -0
  172. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/lightweight_charts.py +0 -0
  173. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/logging.py +0 -0
  174. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/loguru.py +0 -0
  175. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/luigi.py +0 -0
  176. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/math.py +0 -0
  177. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/memory_profiler.py +0 -0
  178. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/modules.py +0 -0
  179. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/more_itertools.py +0 -0
  180. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/numpy.py +0 -0
  181. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/operator.py +0 -0
  182. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/optuna.py +0 -0
  183. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/orjson.py +0 -0
  184. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/os.py +0 -0
  185. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/pathlib.py +0 -0
  186. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/period.py +0 -0
  187. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/pickle.py +0 -0
  188. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/platform.py +0 -0
  189. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/polars.py +0 -0
  190. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/polars_ols.py +0 -0
  191. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/pqdm.py +0 -0
  192. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/py.typed +0 -0
  193. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/pydantic.py +0 -0
  194. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/pyinstrument.py +0 -0
  195. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/pyrsistent.py +0 -0
  196. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/pytest.py +0 -0
  197. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/pytest_regressions.py +0 -0
  198. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/python_dotenv.py +0 -0
  199. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/random.py +0 -0
  200. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/re.py +0 -0
  201. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/redis.py +0 -0
  202. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/reprlib.py +0 -0
  203. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/rich.py +0 -0
  204. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/scipy.py +0 -0
  205. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/sentinel.py +0 -0
  206. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/shelve.py +0 -0
  207. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/slack_sdk.py +0 -0
  208. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/socket.py +0 -0
  209. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/sqlalchemy.py +0 -0
  210. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/sqlalchemy_polars.py +0 -0
  211. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/statsmodels.py +0 -0
  212. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/streamlit.py +0 -0
  213. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/sys.py +0 -0
  214. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/tempfile.py +0 -0
  215. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/tenacity.py +0 -0
  216. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/text.py +0 -0
  217. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/threading.py +0 -0
  218. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/timer.py +0 -0
  219. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/traceback.py +0 -0
  220. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/types.py +0 -0
  221. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/tzdata.py +0 -0
  222. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/tzlocal.py +0 -0
  223. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/uuid.py +0 -0
  224. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/version.py +0 -0
  225. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/warnings.py +0 -0
  226. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/whenever.py +0 -0
  227. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/src/utilities/zipfile.py +0 -0
  228. {dycw_utilities-0.112.4 → dycw_utilities-0.112.6}/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.4
3
+ Version: 0.112.6
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.4"
96
+ version = "0.112.6"
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.4"
339
+ current_version = "0.112.6"
340
340
 
341
341
  [[tool.bumpversion.files]]
342
342
  filename = "src/utilities/__init__.py"
@@ -39,9 +39,10 @@ from utilities.dataclasses import (
39
39
  StrMappingToFieldMappingError,
40
40
  YieldFieldsError,
41
41
  _parse_dataclass_split_key_value_pairs,
42
- _ParseDataClassParseValueError,
43
42
  _ParseDataClassSplitKeyValuePairsDuplicateKeysError,
44
43
  _ParseDataClassSplitKeyValuePairsSplitError,
44
+ _ParseDataClassTextExtraNonUniqueError,
45
+ _ParseDataClassTextParseError,
45
46
  _YieldFieldsClass,
46
47
  _YieldFieldsInstance,
47
48
  dataclass_repr,
@@ -482,13 +483,24 @@ class TestSerializeAndParseDataClass:
482
483
  ):
483
484
  _ = parse_dataclass("a=1,b=22a,b=22b,c=3", DataClassFutureInt)
484
485
 
485
- def test_error_parse_value(self) -> None:
486
+ def test_error_text_parse(self) -> None:
486
487
  with raises(
487
- _ParseDataClassParseValueError,
488
- match="Unable to construct 'DataClassFutureInt'; unable to parse field 'int_' of type <class 'int'>; got 'invalid'",
488
+ _ParseDataClassTextParseError,
489
+ match="Unable to construct 'DataClassFutureInt' since the field 'int_' of type <class 'int'> could not be parsed; got 'invalid'",
489
490
  ):
490
491
  _ = parse_dataclass("int_=invalid", DataClassFutureInt)
491
492
 
493
+ def test_error_text_extra_non_unique(self) -> None:
494
+ with raises(
495
+ _ParseDataClassTextExtraNonUniqueError,
496
+ match="Unable to construct 'DataClassFutureInt' since the field 'int_' of type <class 'int'> must contain exactly one parent class in `extra`; got <class 'int'>, <class 'int'> and perhaps more",
497
+ ):
498
+ _ = parse_dataclass(
499
+ "int_=0",
500
+ DataClassFutureInt,
501
+ extra_parsers={int | str: int, int | float: int},
502
+ )
503
+
492
504
 
493
505
  class TestStrMappingToFieldMapping:
494
506
  @given(key=sampled_from(["int_", "INT_"]), int_=integers())
@@ -25,13 +25,10 @@ from pytest import raises
25
25
  from tests.test_operator import TruthEnum
26
26
  from tests.test_typing_funcs.with_future import (
27
27
  DataClassFutureInt,
28
- DataClassFutureIntChild,
29
28
  DataClassFutureIntEven,
30
29
  DataClassFutureIntEvenOrOddTypeUnion,
31
30
  DataClassFutureIntEvenOrOddUnion,
32
31
  DataClassFutureIntOdd,
33
- DataClassFutureIntParentFirst,
34
- DataClassFutureIntParentSecond,
35
32
  TrueOrFalseFutureLit,
36
33
  TrueOrFalseFutureTypeLit,
37
34
  )
@@ -309,7 +306,7 @@ class TestSerializeAndParseObject:
309
306
 
310
307
  class TestParseObject:
311
308
  @given(text=sampled_from(["F_a_l_s_e", "T_r_u_e"]))
312
- def test_bool_custom(self, *, text: str) -> None:
309
+ def test_extra(self, *, text: str) -> None:
313
310
  def parser(text: str, /) -> bool:
314
311
  match text:
315
312
  case "F_a_l_s_e":
@@ -330,7 +327,7 @@ class TestParseObject:
330
327
  assert bool_ is expected
331
328
 
332
329
  @given(text=sampled_from(["F_a_l_s_e", "T_r_u_e"]))
333
- def test_bool_extra_not_used(self, *, text: str) -> None:
330
+ def test_extra_both_exact_match_and_non_unique_parents(self, *, text: str) -> None:
334
331
  def parser(text: str, /) -> bool:
335
332
  match text:
336
333
  case "F_a_l_s_e":
@@ -340,10 +337,17 @@ class TestParseObject:
340
337
  case _:
341
338
  raise ImpossibleCaseError(case=[f"{text=}"])
342
339
 
343
- with raises(
344
- _ParseObjectParseError, match="Unable to parse <class 'bool'>; got '.*'"
345
- ):
346
- _ = parse_object(bool, text, extra={int: parser})
340
+ result = parse_object(
341
+ bool, text, extra={bool: parser, bool | int: bool, bool | float: bool}
342
+ )
343
+ match text:
344
+ case "F_a_l_s_e":
345
+ expected = False
346
+ case "T_r_u_e":
347
+ expected = True
348
+ case _:
349
+ raise ImpossibleCaseError(case=[f"{text=}"])
350
+ assert result is expected
347
351
 
348
352
  @given(value=text_ascii(min_size=10) | none())
349
353
  def test_optional_type_with_union_extra_not_used(
@@ -412,24 +416,29 @@ class TestParseObject:
412
416
  ):
413
417
  _ = parse_object(DataClassFutureInt, "invalid", extra={})
414
418
 
419
+ @given(text=sampled_from(["F_a_l_s_e", "T_r_u_e"]))
420
+ def test_error_extra_empty_bool_does_not_use_int(self, *, text: str) -> None:
421
+ def parser(text: str, /) -> bool:
422
+ match text:
423
+ case "F_a_l_s_e":
424
+ return False
425
+ case "T_r_u_e":
426
+ return True
427
+ case _:
428
+ raise ImpossibleCaseError(case=[f"{text=}"])
429
+
430
+ with raises(
431
+ _ParseObjectParseError, match="Unable to parse <class 'bool'>; got '.*'"
432
+ ):
433
+ _ = parse_object(bool, text, extra={int: parser})
434
+
415
435
  @given(int_=integers())
416
436
  def test_error_extra_non_unique(self, *, int_: int) -> None:
417
437
  with raises(
418
438
  _ParseObjectExtraNonUniqueError,
419
- match="Unable to parse <class '.*'> since `extra` must contain exactly one parent class; got <function .*>, <function .*> and perhaps more",
420
- ):
421
- _ = parse_object(
422
- DataClassFutureIntChild,
423
- serialize_object(int_),
424
- extra={
425
- DataClassFutureIntParentFirst: lambda text: DataClassFutureIntChild(
426
- int1=int(text), int2=0
427
- ),
428
- DataClassFutureIntParentSecond: lambda text: DataClassFutureIntChild(
429
- int1=0, int2=int(text)
430
- ),
431
- },
432
- )
439
+ match="Unable to parse <class 'int'> since `extra` must contain exactly one parent class; got <class 'int'>, <class 'int'> and perhaps more",
440
+ ):
441
+ _ = parse_object(int, str(int_), extra={int | bool: int, int | float: int})
433
442
 
434
443
  def test_error_union_type_extra(self) -> None:
435
444
  with raises(
@@ -674,29 +683,17 @@ class TestSerializeObject:
674
683
  def test_error_extra_empty(self) -> None:
675
684
  with raises(
676
685
  _SerializeObjectSerializeError,
677
- match=r"Unable to serialize object typing\.Final",
686
+ match=r"Unable to serialize object typing\.Final of type <class 'typing\._SpecialForm'>",
678
687
  ):
679
688
  _ = serialize_object(Final, extra={})
680
689
 
681
- @given(int1=integers(), int2=integers())
682
- def test_error_extra_non_unique(self, *, int1: int, int2: int) -> None:
683
- def serializer1(obj: DataClassFutureIntParentFirst, /) -> str:
684
- return str(obj.int1)
685
-
686
- def serializer2(obj: DataClassFutureIntParentSecond, /) -> str:
687
- return str(obj.int2)
688
-
690
+ @given(bool_=booleans())
691
+ def test_error_extra_non_unique(self, *, bool_: bool) -> None:
689
692
  with raises(
690
693
  _SerializeObjectExtraNonUniqueError,
691
- match=r"Unable to serialize object DataClassFutureIntChild\(.*\) since `extra` must contain exactly one parent class; got <function .*>, <function .*> and perhaps more",
692
- ):
693
- _ = serialize_object(
694
- DataClassFutureIntChild(int1=int1, int2=int2),
695
- extra={
696
- DataClassFutureIntParentFirst: serializer1,
697
- DataClassFutureIntParentSecond: serializer2,
698
- },
699
- )
694
+ match=r"Unable to serialize object (True|False) of type <class 'bool'> since `extra` must contain exactly one parent class; got <class 'str'>, <class 'str'> and perhaps more",
695
+ ):
696
+ _ = serialize_object(bool_, extra={bool | int: str, bool | float: str})
700
697
 
701
698
  def test_error_not_implemented(self) -> None:
702
699
  with raises(_SerializeObjectSerializeError):
@@ -53,6 +53,7 @@ from tests.test_typing_funcs.with_future import (
53
53
  TrueOrFalseFutureLit,
54
54
  TrueOrFalseFutureTypeLit,
55
55
  )
56
+ from utilities.hypothesis import text_ascii
56
57
  from utilities.sentinel import Sentinel
57
58
  from utilities.types import Duration, LogLevel, Number, Parallelism, Seed
58
59
  from utilities.typing import (
@@ -167,14 +168,14 @@ class TestGetTypeClasses:
167
168
  def test_error_type(self) -> None:
168
169
  with raises(
169
170
  _GetTypeClassesTypeError,
170
- match="Object must be a type, tuple or Union type; got None",
171
+ match="Object must be a type, tuple or Union type; got None of type <class 'NoneType'>",
171
172
  ):
172
173
  _ = get_type_classes(None)
173
174
 
174
175
  def test_error_tuple(self) -> None:
175
176
  with raises(
176
177
  _GetTypeClassesTupleError,
177
- match="Tuple must contain types, tuples or Union types only; got None",
178
+ match="Tuple must contain types, tuples or Union types only; got None of type <class 'NoneType'>",
178
179
  ):
179
180
  _ = get_type_classes((None,))
180
181
 
@@ -416,14 +417,14 @@ class TestGetUnionTypeClasses:
416
417
  def test_error_union_type(self) -> None:
417
418
  with raises(
418
419
  _GetUnionTypeClassesUnionTypeError,
419
- match="Object must be a Union type; got None",
420
+ match="Object must be a Union type; got None of type <class 'NoneType'>",
420
421
  ):
421
422
  _ = get_union_type_classes(None)
422
423
 
423
- def test_error_interal_type(self) -> None:
424
+ def test_error_internal_type(self) -> None:
424
425
  with raises(
425
426
  _GetUnionTypeClassesInternalTypeError,
426
- match=r"Union type must contain types only; got typing\.Literal\[True\]",
427
+ match=r"Union type must contain types only; got typing\.Literal\[True\] of type <class 'typing\._LiteralGenericAlias'>",
427
428
  ):
428
429
  _ = get_union_type_classes(Literal[True] | None)
429
430
 
@@ -530,6 +531,7 @@ class TestIsInstanceGen:
530
531
  (sampled_from([1, "2", 3]), int, 3, False),
531
532
  (sampled_from([1, "2", 3]), str, 3, False),
532
533
  (booleans(), Literal[1, 2, 3], None, False),
534
+ (text_ascii(), Literal["a", "b", "c"], 4, False),
533
535
  # tuple types
534
536
  (tuples(booleans()), tuple[bool], None, True),
535
537
  (tuples(booleans()), tuple[int], None, False),
@@ -552,6 +554,10 @@ class TestIsInstanceGen:
552
554
  False,
553
555
  ),
554
556
  (tuples(just("a"), integers()), tuple[Literal["a", "b"], int], None, True),
557
+ (booleans(), tuple[bool], 2, False),
558
+ (booleans() | none(), tuple[bool], 3, False),
559
+ (text_ascii(), tuple[bool], None, False),
560
+ (text_ascii() | none(), tuple[bool], None, False),
555
561
  ]),
556
562
  )
557
563
  def test_main(
@@ -586,7 +592,8 @@ class TestIsInstanceGen:
586
592
 
587
593
  def test_error(self) -> None:
588
594
  with raises(
589
- IsInstanceGenError, match=r"Invalid arguments; got None and typing\.Final"
595
+ IsInstanceGenError,
596
+ match=r"Invalid arguments; got None of type <class 'NoneType'> and typing\.Final of type <class 'typing\._SpecialForm'>",
590
597
  ):
591
598
  _ = is_instance_gen(None, Final)
592
599
 
@@ -639,6 +646,9 @@ class TestIsSubclassGen:
639
646
  (bool, bool | None, True),
640
647
  (bool | None, bool, False),
641
648
  (bool | None, bool | None, True),
649
+ (Number, int, False),
650
+ (Number, float, False),
651
+ (Number, Number, True),
642
652
  # literals
643
653
  (Literal[1, 2], Literal[1, 2, 3], True),
644
654
  (Literal[1, 2, 3], Literal[1, 2, 3], True),
@@ -651,6 +661,7 @@ class TestIsSubclassGen:
651
661
  (Literal[1, "2", 3], int, False),
652
662
  (Literal[1, "2", 3], str, False),
653
663
  (bool, Literal[1, 2, 3], False),
664
+ (str, Literal["a", "b", "c"], False),
654
665
  # tuple types
655
666
  (tuple[bool], tuple[bool], True),
656
667
  (tuple[bool], tuple[int], False),
@@ -668,6 +679,10 @@ class TestIsSubclassGen:
668
679
  (tuple[Literal["a"], bool], tuple[Literal["a", "b"], int], False),
669
680
  (tuple[Literal["a"], int], tuple[Literal["a", "b"], bool], False),
670
681
  (tuple[Literal["a"], int], tuple[Literal["a", "b"], int], True),
682
+ (bool, tuple[bool], False),
683
+ (bool | None, tuple[bool], False),
684
+ (str, tuple[Literal["a", "b", "c"]], False),
685
+ (str | None, tuple[Literal["a", "b", "c"]], False),
671
686
  ])
672
687
  )
673
688
  def test_main(self, *, case: tuple[type[Any], Any, bool]) -> None:
@@ -684,5 +699,8 @@ class TestIsSubclassGen:
684
699
  assert is_subclass_gen(MyInt, MyInt)
685
700
 
686
701
  def test_error(self) -> None:
687
- with raises(IsSubclassGenError, match="Argument must be a class; got None"):
702
+ with raises(
703
+ IsSubclassGenError,
704
+ match="Argument must be a class; got None of type <class 'NoneType'>",
705
+ ):
688
706
  _ = is_subclass_gen(None, NoneType)
@@ -87,22 +87,6 @@ class DataClassFutureIntOneAndTwo:
87
87
  int2: int
88
88
 
89
89
 
90
- @dataclass(order=True, unsafe_hash=True, kw_only=True)
91
- class DataClassFutureIntParentFirst:
92
- int1: int
93
-
94
-
95
- @dataclass(order=True, unsafe_hash=True, kw_only=True)
96
- class DataClassFutureIntParentSecond:
97
- int2: int
98
-
99
-
100
- @dataclass(order=True, unsafe_hash=True, kw_only=True)
101
- class DataClassFutureIntChild(
102
- DataClassFutureIntParentFirst, DataClassFutureIntParentSecond
103
- ): ...
104
-
105
-
106
90
  @dataclass(order=True, unsafe_hash=True, kw_only=True)
107
91
  class DataClassFutureListInts:
108
92
  ints: list[int]
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.112.4"
3
+ __version__ = "0.112.6"
@@ -22,7 +22,12 @@ from utilities.functions import (
22
22
  )
23
23
  from utilities.iterables import OneStrEmptyError, OneStrNonUniqueError, one_str
24
24
  from utilities.operator import is_equal
25
- from utilities.parse import ParseObjectError, parse_object, serialize_object
25
+ from utilities.parse import (
26
+ _ParseObjectExtraNonUniqueError,
27
+ _ParseObjectParseError,
28
+ parse_object,
29
+ serialize_object,
30
+ )
26
31
  from utilities.re import ExtractGroupError, extract_group
27
32
  from utilities.sentinel import Sentinel, sentinel
28
33
  from utilities.text import (
@@ -570,8 +575,12 @@ def _parse_dataclass_parse_text(
570
575
  case_sensitive=case_sensitive,
571
576
  extra=extra,
572
577
  )
573
- except ParseObjectError:
574
- raise _ParseDataClassParseValueError(cls=cls, field=field, text=text) from None
578
+ except _ParseObjectParseError:
579
+ raise _ParseDataClassTextParseError(cls=cls, field=field, text=text) from None
580
+ except _ParseObjectExtraNonUniqueError as error:
581
+ raise _ParseDataClassTextExtraNonUniqueError(
582
+ cls=cls, field=field, text=text, first=error.first, second=error.second
583
+ ) from None
575
584
 
576
585
 
577
586
  @dataclass(kw_only=True, slots=True)
@@ -597,12 +606,23 @@ class _ParseDataClassSplitKeyValuePairsDuplicateKeysError(ParseDataClassError):
597
606
 
598
607
 
599
608
  @dataclass(kw_only=True, slots=True)
600
- class _ParseDataClassParseValueError(ParseDataClassError[TDataclass]):
609
+ class _ParseDataClassTextParseError(ParseDataClassError[TDataclass]):
610
+ field: _YieldFieldsClass[Any]
611
+
612
+ @override
613
+ def __str__(self) -> str:
614
+ return f"Unable to construct {get_class_name(self.cls)!r} since the field {self.field.name!r} of type {self.field.type_!r} could not be parsed; got {self.text!r}"
615
+
616
+
617
+ @dataclass(kw_only=True, slots=True)
618
+ class _ParseDataClassTextExtraNonUniqueError(ParseDataClassError[TDataclass]):
601
619
  field: _YieldFieldsClass[Any]
620
+ first: type[Any]
621
+ second: type[Any]
602
622
 
603
623
  @override
604
624
  def __str__(self) -> str:
605
- return f"Unable to construct {get_class_name(self.cls)!r}; unable to parse field {self.field.name!r} of type {self.field.type_!r}; got {self.text!r}"
625
+ return f"Unable to construct {get_class_name(self.cls)!r} since the field {self.field.name!r} of type {self.field.type_!r} must contain exactly one parent class in `extra`; got {self.first!r}, {self.second!r} and perhaps more"
606
626
 
607
627
 
608
628
  ##
@@ -283,17 +283,19 @@ def _parse_object_dict_type(
283
283
 
284
284
  def _parse_object_extra(cls: Any, text: str, extra: ParseObjectExtra, /) -> Any:
285
285
  try:
286
- parser = one(
287
- p for c, p in extra.items() if (cls is c) or is_subclass_gen(cls, c)
288
- )
289
- except (OneEmptyError, TypeError):
290
- raise _ParseObjectParseError(type_=cls, text=text) from None
291
- except OneNonUniqueError as error:
292
- raise _ParseObjectExtraNonUniqueError(
293
- type_=cls, text=text, first=error.first, second=error.second
294
- ) from None
295
- else:
296
- return parser(text)
286
+ parser = extra[cls]
287
+ except KeyError:
288
+ try:
289
+ parser = one(
290
+ p for c, p in extra.items() if (cls is c) or is_subclass_gen(cls, c)
291
+ )
292
+ except (OneEmptyError, TypeError):
293
+ raise _ParseObjectParseError(type_=cls, text=text) from None
294
+ except OneNonUniqueError as error:
295
+ raise _ParseObjectExtraNonUniqueError(
296
+ type_=cls, text=text, first=error.first, second=error.second
297
+ ) from None
298
+ return parser(text)
297
299
 
298
300
 
299
301
  def _parse_object_list_type(
@@ -600,7 +602,7 @@ class SerializeObjectError(Exception):
600
602
  class _SerializeObjectSerializeError(SerializeObjectError):
601
603
  @override
602
604
  def __str__(self) -> str:
603
- return f"Unable to serialize object {self.obj!r}"
605
+ return f"Unable to serialize object {self.obj!r} of type {type(self.obj)!r}"
604
606
 
605
607
 
606
608
  @dataclass
@@ -610,7 +612,7 @@ class _SerializeObjectExtraNonUniqueError(SerializeObjectError):
610
612
 
611
613
  @override
612
614
  def __str__(self) -> str:
613
- return f"Unable to serialize object {self.obj!r} since `extra` must contain exactly one parent class; got {self.first!r}, {self.second!r} and perhaps more"
615
+ return f"Unable to serialize object {self.obj!r} of type {type(self.obj)!r} since `extra` must contain exactly one parent class; got {self.first!r}, {self.second!r} and perhaps more"
614
616
 
615
617
 
616
618
  __all__ = ["parse_object", "serialize_object"]
@@ -108,7 +108,7 @@ class GetTypeClassesError(Exception):
108
108
  class _GetTypeClassesTypeError(GetTypeClassesError):
109
109
  @override
110
110
  def __str__(self) -> str:
111
- return f"Object must be a type, tuple or Union type; got {self.obj}"
111
+ return f"Object must be a type, tuple or Union type; got {self.obj!r} of type {type(self.obj)!r}"
112
112
 
113
113
 
114
114
  @dataclass(kw_only=True, slots=True)
@@ -117,7 +117,7 @@ class _GetTypeClassesTupleError(GetTypeClassesError):
117
117
 
118
118
  @override
119
119
  def __str__(self) -> str:
120
- return f"Tuple must contain types, tuples or Union types only; got {self.inner}"
120
+ return f"Tuple must contain types, tuples or Union types only; got {self.inner} of type {type(self.inner)!r}"
121
121
 
122
122
 
123
123
  ##
@@ -177,7 +177,9 @@ class GetUnionTypeClassesError(Exception):
177
177
  class _GetUnionTypeClassesUnionTypeError(GetUnionTypeClassesError):
178
178
  @override
179
179
  def __str__(self) -> str:
180
- return f"Object must be a Union type; got {self.obj}"
180
+ return (
181
+ f"Object must be a Union type; got {self.obj!r} of type {type(self.obj)!r}"
182
+ )
181
183
 
182
184
 
183
185
  @dataclass(kw_only=True, slots=True)
@@ -186,7 +188,7 @@ class _GetUnionTypeClassesInternalTypeError(GetUnionTypeClassesError):
186
188
 
187
189
  @override
188
190
  def __str__(self) -> str:
189
- return f"Union type must contain types only; got {self.inner}"
191
+ return f"Union type must contain types only; got {self.inner} of type {type(self.inner)!r}"
190
192
 
191
193
 
192
194
  ##
@@ -243,6 +245,8 @@ def is_instance_gen(obj: Any, type_: Any, /) -> bool:
243
245
  return (len(obj) == len(type_args)) and all(
244
246
  is_instance_gen(o, t) for o, t in zip(obj, type_args, strict=True)
245
247
  )
248
+ if isinstance(obj, tuple) is not is_tuple_type(type_):
249
+ return False
246
250
  # basic
247
251
  if isinstance(type_, type):
248
252
  return any(_is_instance_gen_type(obj, t) for t in get_type_classes(type_))
@@ -272,7 +276,7 @@ class IsInstanceGenError(Exception):
272
276
 
273
277
  @override
274
278
  def __str__(self) -> str:
275
- return f"Invalid arguments; got {self.obj!r} and {self.type_!r}"
279
+ return f"Invalid arguments; got {self.obj!r} of type {type(self.obj)!r} and {self.type_!r} of type {type(self.type_)!r}"
276
280
 
277
281
 
278
282
  ##
@@ -432,7 +436,7 @@ class IsSubclassGenError(Exception):
432
436
 
433
437
  @override
434
438
  def __str__(self) -> str:
435
- return f"Argument must be a class; got {self.cls!r}"
439
+ return f"Argument must be a class; got {self.cls!r} of type {type(self.cls)!r}"
436
440
 
437
441
 
438
442
  ##