dycw-utilities 0.109.1__tar.gz → 0.109.3__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.1 → dycw_utilities-0.109.3}/PKG-INFO +1 -1
  2. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/pyproject.toml +2 -2
  3. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_parse.py +19 -0
  4. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_typing.py +60 -6
  5. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/__init__.py +1 -1
  6. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/dataclasses.py +53 -7
  7. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/orjson.py +14 -0
  8. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/parse.py +15 -1
  9. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/polars.py +8 -2
  10. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/pytest_regressions.py +2 -0
  11. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/python_dotenv.py +2 -0
  12. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/typing.py +17 -5
  13. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/.gitignore +0 -0
  14. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/LICENSE +0 -0
  15. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/README.md +0 -0
  16. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/__init__.py +0 -0
  17. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/conftest.py +0 -0
  18. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/modules/__init__.py +0 -0
  19. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/modules/package_missing/__init__.py +0 -0
  20. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/modules/package_missing/module.py +0 -0
  21. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/modules/package_with/__init__.py +0 -0
  22. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/modules/package_with/outer_1.py +0 -0
  23. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/modules/package_with/outer_2.py +0 -0
  24. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  25. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  26. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  27. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  28. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/modules/package_without/__init__.py +0 -0
  29. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/modules/package_without/module_1.py +0 -0
  30. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/modules/package_without/module_2.py +0 -0
  31. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/modules/standalone.py +0 -0
  32. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/modules/with_imports.py +0 -0
  33. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  34. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  35. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  36. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  37. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  38. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  39. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  40. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  41. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/scripts/__init__.py +0 -0
  42. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/scripts/test_async_service/__init__.py +0 -0
  43. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/scripts/test_async_service/__main__.py +0 -0
  44. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/scripts/test_async_service/run.sh +0 -0
  45. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/scripts/test_queue_processor/__init__.py +0 -0
  46. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/scripts/test_queue_processor/__main__.py +0 -0
  47. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/scripts/test_queue_processor/run.sh +0 -0
  48. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_altair.py +0 -0
  49. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_astor.py +0 -0
  50. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_asyncio.py +0 -0
  51. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_atomicwrites.py +0 -0
  52. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_atools.py +0 -0
  53. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_cachetools.py +0 -0
  54. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_click.py +0 -0
  55. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_concurrent.py +0 -0
  56. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_contextlib.py +0 -0
  57. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_contextvars.py +0 -0
  58. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_cryptography.py +0 -0
  59. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_cvxpy.py +0 -0
  60. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_dataclasses.py +0 -0
  61. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_datetime.py +0 -0
  62. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_enum.py +0 -0
  63. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_errors.py +0 -0
  64. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_eventkit.py +0 -0
  65. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_fastapi.py +0 -0
  66. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_fpdf2.py +0 -0
  67. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_functions.py +0 -0
  68. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_functools.py +0 -0
  69. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_getpass.py +0 -0
  70. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_git.py +0 -0
  71. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_hashlib.py +0 -0
  72. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_http.py +0 -0
  73. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_hypothesis.py +0 -0
  74. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_ipython.py +0 -0
  75. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_iterables.py +0 -0
  76. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_jupyter.py +0 -0
  77. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_logging.py +0 -0
  78. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_loguru.py +0 -0
  79. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_luigi.py +0 -0
  80. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_math.py +0 -0
  81. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_memory_profiler.py +0 -0
  82. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_modules.py +0 -0
  83. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_more_itertools.py +0 -0
  84. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_numpy.py +0 -0
  85. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_operator.py +0 -0
  86. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_optuna.py +0 -0
  87. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_orjson.py +0 -0
  88. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_os.py +0 -0
  89. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_pathlib.py +0 -0
  90. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_period.py +0 -0
  91. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_pickle.py +0 -0
  92. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_platform.py +0 -0
  93. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_polars.py +0 -0
  94. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_pqdm.py +0 -0
  95. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_pydantic.py +0 -0
  96. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_pyinstrument.py +0 -0
  97. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_pyrsistent.py +0 -0
  98. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_pytest.py +0 -0
  99. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_pytest_regressions.py +0 -0
  100. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_python_dotenv.py +0 -0
  101. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_random.py +0 -0
  102. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_re.py +0 -0
  103. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_redis.py +0 -0
  104. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_reprlib.py +0 -0
  105. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_rich.py +0 -0
  106. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_scipy.py +0 -0
  107. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_sentinel.py +0 -0
  108. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_shelve.py +0 -0
  109. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_slack_sdk.py +0 -0
  110. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_socket.py +0 -0
  111. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_sqlalchemy.py +0 -0
  112. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_sqlalchemy_polars.py +0 -0
  113. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_streamlit.py +0 -0
  114. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_sys.py +0 -0
  115. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_tempfile.py +0 -0
  116. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_tenacity.py +0 -0
  117. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_text.py +0 -0
  118. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_threading.py +0 -0
  119. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_timer.py +0 -0
  120. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_traceback.py +0 -0
  121. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_traceback_funcs/__init__.py +0 -0
  122. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_traceback_funcs/chain.py +0 -0
  123. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
  124. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
  125. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_traceback_funcs/error_bind.py +0 -0
  126. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_traceback_funcs/many.py +0 -0
  127. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_traceback_funcs/one.py +0 -0
  128. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_traceback_funcs/recursive.py +0 -0
  129. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
  130. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
  131. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_traceback_funcs/two.py +0 -0
  132. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_traceback_funcs/untraced.py +0 -0
  133. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_types.py +0 -0
  134. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_typing_funcs/__init__.py +0 -0
  135. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_typing_funcs/no_future.py +0 -0
  136. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_typing_funcs/with_future.py +0 -0
  137. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_tzdata.py +0 -0
  138. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_tzlocal.py +0 -0
  139. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_uuid.py +0 -0
  140. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_version.py +0 -0
  141. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_warnings.py +0 -0
  142. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_whenever.py +0 -0
  143. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_zipfile.py +0 -0
  144. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/tests/test_zoneinfo.py +0 -0
  145. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/altair.py +0 -0
  146. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/astor.py +0 -0
  147. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/asyncio.py +0 -0
  148. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/atomicwrites.py +0 -0
  149. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/atools.py +0 -0
  150. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/cachetools.py +0 -0
  151. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/click.py +0 -0
  152. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/concurrent.py +0 -0
  153. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/contextlib.py +0 -0
  154. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/contextvars.py +0 -0
  155. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/cryptography.py +0 -0
  156. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/cvxpy.py +0 -0
  157. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/datetime.py +0 -0
  158. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/enum.py +0 -0
  159. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/errors.py +0 -0
  160. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/eventkit.py +0 -0
  161. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/fastapi.py +0 -0
  162. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/fpdf2.py +0 -0
  163. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/functions.py +0 -0
  164. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/functools.py +0 -0
  165. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/getpass.py +0 -0
  166. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/git.py +0 -0
  167. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/hashlib.py +0 -0
  168. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/http.py +0 -0
  169. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/hypothesis.py +0 -0
  170. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/ipython.py +0 -0
  171. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/iterables.py +0 -0
  172. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/jupyter.py +0 -0
  173. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/logging.py +0 -0
  174. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/loguru.py +0 -0
  175. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/luigi.py +0 -0
  176. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/math.py +0 -0
  177. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/memory_profiler.py +0 -0
  178. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/modules.py +0 -0
  179. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/more_itertools.py +0 -0
  180. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/numpy.py +0 -0
  181. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/operator.py +0 -0
  182. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/optuna.py +0 -0
  183. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/os.py +0 -0
  184. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/pathlib.py +0 -0
  185. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/period.py +0 -0
  186. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/pickle.py +0 -0
  187. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/platform.py +0 -0
  188. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/pqdm.py +0 -0
  189. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/py.typed +0 -0
  190. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/pydantic.py +0 -0
  191. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/pyinstrument.py +0 -0
  192. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/pyrsistent.py +0 -0
  193. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/pytest.py +0 -0
  194. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/random.py +0 -0
  195. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/re.py +0 -0
  196. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/redis.py +0 -0
  197. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/reprlib.py +0 -0
  198. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/rich.py +0 -0
  199. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/scipy.py +0 -0
  200. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/sentinel.py +0 -0
  201. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/shelve.py +0 -0
  202. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/slack_sdk.py +0 -0
  203. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/socket.py +0 -0
  204. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/sqlalchemy.py +0 -0
  205. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/sqlalchemy_polars.py +0 -0
  206. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/streamlit.py +0 -0
  207. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/sys.py +0 -0
  208. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/tempfile.py +0 -0
  209. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/tenacity.py +0 -0
  210. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/text.py +0 -0
  211. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/threading.py +0 -0
  212. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/timer.py +0 -0
  213. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/traceback.py +0 -0
  214. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/types.py +0 -0
  215. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/tzdata.py +0 -0
  216. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/tzlocal.py +0 -0
  217. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/uuid.py +0 -0
  218. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/version.py +0 -0
  219. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/warnings.py +0 -0
  220. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/whenever.py +0 -0
  221. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/src/utilities/zipfile.py +0 -0
  222. {dycw_utilities-0.109.1 → dycw_utilities-0.109.3}/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.1
3
+ Version: 0.109.3
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.1"
92
+ version = "0.109.3"
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.1"
335
+ current_version = "0.109.3"
336
336
 
337
337
  [[tool.bumpversion.files]]
338
338
  filename = "src/utilities/__init__.py"
@@ -135,6 +135,12 @@ class TestParseText:
135
135
  result = parse_text(dt.timedelta, text)
136
136
  assert result == timedelta
137
137
 
138
+ @given(x=integers(), y=integers())
139
+ def test_tuple(self, *, x: int, y: int) -> None:
140
+ text = f"({x}, {y})"
141
+ result = parse_text(tuple[int, int], text)
142
+ assert result == (x, y)
143
+
138
144
  @given(truth=sampled_from(["true", "false"]))
139
145
  def test_type_literal(self, *, truth: Literal["true", "false"]) -> None:
140
146
  result = parse_text(TrueOrFalseFutureTypeLit, truth)
@@ -228,6 +234,19 @@ class TestParseText:
228
234
  ):
229
235
  _ = parse_text(dt.timedelta, "invalid")
230
236
 
237
+ def test_error_tuple_invalid_text(self) -> None:
238
+ with raises(
239
+ ParseTextError, match=r"Unable to parse tuple\[int, int\]; got 'invalid'"
240
+ ):
241
+ _ = parse_text(tuple[int, int], "invalid")
242
+
243
+ def test_error_tuple_inconsistent_args_and_texts(self) -> None:
244
+ with raises(
245
+ ParseTextError,
246
+ match=r"Unable to parse tuple\[int, int\]; got '\(text1, text2, text3\)'",
247
+ ):
248
+ _ = parse_text(tuple[int, int], "(text1, text2, text3)")
249
+
231
250
  def test_error_unknown_annotation(self) -> None:
232
251
  with raises(ParseTextError, match=r"Unable to parse int \| str; got 'invalid'"):
233
252
  _ = parse_text(int | str, "invalid")
@@ -10,7 +10,7 @@ from uuid import UUID
10
10
 
11
11
  from hypothesis import given
12
12
  from hypothesis.strategies import DataObject, data, just, none, sampled_from
13
- from pytest import mark, param
13
+ from pytest import mark, param, raises
14
14
 
15
15
  from tests.test_typing_funcs.no_future import (
16
16
  DataClassNoFutureNestedInnerFirstInner,
@@ -55,6 +55,7 @@ from utilities.typing import (
55
55
  is_optional_type,
56
56
  is_sequence_type,
57
57
  is_set_type,
58
+ is_tuple_type,
58
59
  is_union_type,
59
60
  )
60
61
 
@@ -318,30 +319,83 @@ class TestGetTypeHints:
318
319
  expected = {"inner": "Inner"}
319
320
  assert hints == expected
320
321
 
322
+ def test_warning(self) -> None:
323
+ @dataclass(kw_only=True, slots=True)
324
+ class Outer:
325
+ inner: Inner
326
+
327
+ @dataclass(kw_only=True, slots=True)
328
+ class Inner:
329
+ int_: int
330
+
331
+ with raises(
332
+ UserWarning,
333
+ match="Error getting type hints for <.*>; name 'Inner' is not defined",
334
+ ):
335
+ _ = get_type_hints(Outer, warn_name_errors=True)
336
+
321
337
 
322
338
  class TestIsAnnotationOfType:
323
339
  @mark.parametrize(
324
340
  ("func", "obj", "expected"),
325
341
  [
342
+ param(is_dict_type, Mapping[int, int], False),
343
+ param(is_dict_type, Sequence[int], False),
326
344
  param(is_dict_type, dict[int, int], True),
345
+ param(is_dict_type, frozenset[int], False),
327
346
  param(is_dict_type, list[int], False),
347
+ param(is_dict_type, set[int], False),
348
+ param(is_dict_type, tuple[int, int], False),
349
+ param(is_frozenset_type, Mapping[int, int], False),
350
+ param(is_frozenset_type, Sequence[int], False),
351
+ param(is_frozenset_type, dict[int, int], False),
328
352
  param(is_frozenset_type, frozenset[int], True),
329
353
  param(is_frozenset_type, list[int], False),
354
+ param(is_frozenset_type, set[int], False),
355
+ param(is_frozenset_type, tuple[int, int], False),
356
+ param(is_list_type, Mapping[int, int], False),
357
+ param(is_list_type, Sequence[int], False),
358
+ param(is_list_type, dict[int, int], False),
359
+ param(is_list_type, frozenset[int], False),
330
360
  param(is_list_type, list[int], True),
331
361
  param(is_list_type, set[int], False),
332
- param(is_mapping_type, Mapping[int, int], True),
333
- param(is_mapping_type, list[int], False),
362
+ param(is_list_type, tuple[int, int], False),
334
363
  param(is_literal_type, Literal["a", "b", "c"], True),
335
364
  param(is_literal_type, list[int], False),
365
+ param(is_mapping_type, Mapping[int, int], True),
366
+ param(is_mapping_type, Sequence[int], False),
367
+ param(is_mapping_type, dict[int, int], False),
368
+ param(is_mapping_type, frozenset[int], False),
369
+ param(is_mapping_type, list[int], False),
370
+ param(is_mapping_type, set[int], False),
371
+ param(is_mapping_type, tuple[int, int], False),
372
+ param(is_optional_type, Literal["a", "b", "c"] | None, True),
373
+ param(is_optional_type, Literal["a", "b", "c"], False),
336
374
  param(is_optional_type, int | None, True),
337
375
  param(is_optional_type, int | str, False),
338
- param(is_optional_type, list[int], False),
339
376
  param(is_optional_type, list[int] | None, True),
340
- param(is_optional_type, Literal["a", "b", "c"], False),
341
- param(is_optional_type, Literal["a", "b", "c"] | None, True),
377
+ param(is_optional_type, list[int], False),
378
+ param(is_sequence_type, Mapping[int, int], False),
342
379
  param(is_sequence_type, Sequence[int], True),
380
+ param(is_sequence_type, dict[int, int], False),
381
+ param(is_sequence_type, frozenset[int], False),
343
382
  param(is_sequence_type, list[int], False),
383
+ param(is_sequence_type, set[int], False),
384
+ param(is_sequence_type, tuple[int, int], False),
385
+ param(is_set_type, Mapping[int, int], False),
386
+ param(is_set_type, Sequence[int], False),
387
+ param(is_set_type, dict[int, int], False),
388
+ param(is_set_type, frozenset[int], False),
344
389
  param(is_set_type, list[int], False),
390
+ param(is_set_type, set[int], True),
391
+ param(is_set_type, tuple[int, int], False),
392
+ param(is_tuple_type, Mapping[int, int], False),
393
+ param(is_tuple_type, Sequence[int], False),
394
+ param(is_tuple_type, dict[int, int], False),
395
+ param(is_tuple_type, frozenset[int], False),
396
+ param(is_tuple_type, list[int], False),
397
+ param(is_tuple_type, set[int], False),
398
+ param(is_tuple_type, tuple[int, int], True),
345
399
  param(is_union_type, int | str, True),
346
400
  param(is_union_type, list[int], False),
347
401
  ],
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.109.1"
3
+ __version__ = "0.109.3"
@@ -48,6 +48,7 @@ def dataclass_repr(
48
48
  exclude: Iterable[str] | None = None,
49
49
  globalns: StrMapping | None = None,
50
50
  localns: StrMapping | None = None,
51
+ warn_name_errors: bool = False,
51
52
  rel_tol: float | None = None,
52
53
  abs_tol: float | None = None,
53
54
  extra: Mapping[type[_T], Callable[[_T, _T], bool]] | None = None,
@@ -56,7 +57,9 @@ def dataclass_repr(
56
57
  ) -> str:
57
58
  """Repr a dataclass, without its defaults."""
58
59
  out: dict[str, str] = {}
59
- for fld in yield_fields(obj, globalns=globalns, localns=localns):
60
+ for fld in yield_fields(
61
+ obj, globalns=globalns, localns=localns, warn_name_errors=warn_name_errors
62
+ ):
60
63
  if (
61
64
  fld.keep(
62
65
  include=include,
@@ -76,6 +79,7 @@ def dataclass_repr(
76
79
  exclude=exclude,
77
80
  globalns=globalns,
78
81
  localns=localns,
82
+ warn_name_errors=warn_name_errors,
79
83
  rel_tol=rel_tol,
80
84
  abs_tol=abs_tol,
81
85
  extra=extra,
@@ -90,6 +94,7 @@ def dataclass_repr(
90
94
  exclude=exclude,
91
95
  globalns=globalns,
92
96
  localns=localns,
97
+ warn_name_errors=warn_name_errors,
93
98
  rel_tol=rel_tol,
94
99
  abs_tol=abs_tol,
95
100
  extra=extra,
@@ -122,6 +127,7 @@ def dataclass_to_dict(
122
127
  exclude: Iterable[str] | None = None,
123
128
  globalns: StrMapping | None = None,
124
129
  localns: StrMapping | None = None,
130
+ warn_name_errors: bool = False,
125
131
  rel_tol: float | None = None,
126
132
  abs_tol: float | None = None,
127
133
  extra: Mapping[type[_T], Callable[[_T, _T], bool]] | None = None,
@@ -131,7 +137,9 @@ def dataclass_to_dict(
131
137
  ) -> StrMapping:
132
138
  """Convert a dataclass to a dictionary."""
133
139
  out: StrMapping = {}
134
- for fld in yield_fields(obj, globalns=globalns, localns=localns):
140
+ for fld in yield_fields(
141
+ obj, globalns=globalns, localns=localns, warn_name_errors=warn_name_errors
142
+ ):
135
143
  if fld.keep(
136
144
  include=include,
137
145
  exclude=exclude,
@@ -146,6 +154,7 @@ def dataclass_to_dict(
146
154
  fld.value,
147
155
  globalns=globalns,
148
156
  localns=localns,
157
+ warn_name_errors=warn_name_errors,
149
158
  rel_tol=rel_tol,
150
159
  abs_tol=abs_tol,
151
160
  extra=extra,
@@ -159,6 +168,7 @@ def dataclass_to_dict(
159
168
  v,
160
169
  globalns=globalns,
161
170
  localns=localns,
171
+ warn_name_errors=warn_name_errors,
162
172
  rel_tol=rel_tol,
163
173
  abs_tol=abs_tol,
164
174
  extra=extra,
@@ -189,13 +199,21 @@ def mapping_to_dataclass(
189
199
  fields: Iterable[_YieldFieldsClass[Any]] | None = None,
190
200
  globalns: StrMapping | None = None,
191
201
  localns: StrMapping | None = None,
202
+ warn_name_errors: bool = False,
192
203
  head: bool = False,
193
204
  case_sensitive: bool = False,
194
205
  allow_extra: bool = False,
195
206
  ) -> TDataclass:
196
207
  """Construct a dataclass from a mapping."""
197
208
  if fields is None:
198
- fields_use = list(yield_fields(cls, globalns=globalns, localns=localns))
209
+ fields_use = list(
210
+ yield_fields(
211
+ cls,
212
+ globalns=globalns,
213
+ localns=localns,
214
+ warn_name_errors=warn_name_errors,
215
+ )
216
+ )
199
217
  else:
200
218
  fields_use = fields
201
219
  fields_to_values = str_mapping_to_field_mapping(
@@ -204,6 +222,7 @@ def mapping_to_dataclass(
204
222
  fields=fields_use,
205
223
  globalns=globalns,
206
224
  localns=localns,
225
+ warn_name_errors=warn_name_errors,
207
226
  head=head,
208
227
  case_sensitive=case_sensitive,
209
228
  allow_extra=allow_extra,
@@ -244,12 +263,20 @@ def one_field(
244
263
  fields: Iterable[_YieldFieldsClass[Any]] | None = None,
245
264
  globalns: StrMapping | None = None,
246
265
  localns: StrMapping | None = None,
266
+ warn_name_errors: bool = False,
247
267
  head: bool = False,
248
268
  case_sensitive: bool = False,
249
269
  ) -> _YieldFieldsClass[Any]:
250
270
  """Get the unique field a key matches to."""
251
271
  if fields is None:
252
- fields_use = list(yield_fields(cls, globalns=globalns, localns=localns))
272
+ fields_use = list(
273
+ yield_fields(
274
+ cls,
275
+ globalns=globalns,
276
+ localns=localns,
277
+ warn_name_errors=warn_name_errors,
278
+ )
279
+ )
253
280
  else:
254
281
  fields_use = fields
255
282
  mapping = {f.name: f for f in fields_use}
@@ -362,6 +389,7 @@ def str_mapping_to_field_mapping(
362
389
  fields: Iterable[_YieldFieldsClass[Any]] | None = None,
363
390
  globalns: StrMapping | None = None,
364
391
  localns: StrMapping | None = None,
392
+ warn_name_errors: bool = False,
365
393
  head: bool = False,
366
394
  case_sensitive: bool = False,
367
395
  allow_extra: bool = False,
@@ -376,6 +404,7 @@ def str_mapping_to_field_mapping(
376
404
  fields=fields,
377
405
  globalns=globalns,
378
406
  localns=localns,
407
+ warn_name_errors=warn_name_errors,
379
408
  head=head,
380
409
  case_sensitive=case_sensitive,
381
410
  )
@@ -421,6 +450,7 @@ def text_to_dataclass(
421
450
  *,
422
451
  globalns: StrMapping | None = None,
423
452
  localns: StrMapping | None = None,
453
+ warn_name_errors: bool = False,
424
454
  head: bool = False,
425
455
  case_sensitive: bool = False,
426
456
  allow_extra: bool = False,
@@ -433,13 +463,18 @@ def text_to_dataclass(
433
463
  ...
434
464
  case _ as never:
435
465
  assert_never(never)
436
- fields = list(yield_fields(cls, globalns=globalns, localns=localns))
466
+ fields = list(
467
+ yield_fields(
468
+ cls, globalns=globalns, localns=localns, warn_name_errors=warn_name_errors
469
+ )
470
+ )
437
471
  fields_to_serializes = str_mapping_to_field_mapping(
438
472
  cls,
439
473
  keys_to_serializes,
440
474
  fields=fields,
441
475
  globalns=globalns,
442
476
  localns=localns,
477
+ warn_name_errors=warn_name_errors,
443
478
  head=head,
444
479
  case_sensitive=case_sensitive,
445
480
  allow_extra=allow_extra,
@@ -454,6 +489,7 @@ def text_to_dataclass(
454
489
  fields=fields,
455
490
  globalns=globalns,
456
491
  localns=localns,
492
+ warn_name_errors=warn_name_errors,
457
493
  head=head,
458
494
  case_sensitive=case_sensitive,
459
495
  allow_extra=allow_extra,
@@ -525,6 +561,7 @@ def yield_fields(
525
561
  *,
526
562
  globalns: StrMapping | None = None,
527
563
  localns: StrMapping | None = None,
564
+ warn_name_errors: bool = False,
528
565
  ) -> Iterator[_YieldFieldsInstance[Any]]: ...
529
566
  @overload
530
567
  def yield_fields(
@@ -533,6 +570,7 @@ def yield_fields(
533
570
  *,
534
571
  globalns: StrMapping | None = None,
535
572
  localns: StrMapping | None = None,
573
+ warn_name_errors: bool = False,
536
574
  ) -> Iterator[_YieldFieldsClass[Any]]: ...
537
575
  def yield_fields(
538
576
  obj: Dataclass | type[Dataclass],
@@ -540,10 +578,16 @@ def yield_fields(
540
578
  *,
541
579
  globalns: StrMapping | None = None,
542
580
  localns: StrMapping | None = None,
581
+ warn_name_errors: bool = False,
543
582
  ) -> Iterator[_YieldFieldsInstance[Any]] | Iterator[_YieldFieldsClass[Any]]:
544
583
  """Yield the fields of a dataclass."""
545
584
  if is_dataclass_instance(obj):
546
- for field in yield_fields(type(obj), globalns=globalns, localns=localns):
585
+ for field in yield_fields(
586
+ type(obj),
587
+ globalns=globalns,
588
+ localns=localns,
589
+ warn_name_errors=warn_name_errors,
590
+ ):
547
591
  yield _YieldFieldsInstance(
548
592
  name=field.name,
549
593
  value=getattr(obj, field.name),
@@ -558,7 +602,9 @@ def yield_fields(
558
602
  kw_only=field.kw_only,
559
603
  )
560
604
  elif is_dataclass_class(obj):
561
- hints = get_type_hints(obj, globalns=globalns, localns=localns)
605
+ hints = get_type_hints(
606
+ obj, globalns=globalns, localns=localns, warn_name_errors=warn_name_errors
607
+ )
562
608
  for field in fields(obj):
563
609
  if isinstance(field.type, type):
564
610
  type_ = field.type
@@ -114,6 +114,7 @@ def serialize(
114
114
  before: Callable[[Any], Any] | None = None,
115
115
  globalns: StrMapping | None = None,
116
116
  localns: StrMapping | None = None,
117
+ warn_name_errors: bool = False,
117
118
  dataclass_hook: _DataclassHook | None = None,
118
119
  dataclass_defaults: bool = False,
119
120
  ) -> bytes:
@@ -123,6 +124,7 @@ def serialize(
123
124
  before=before,
124
125
  globalns=globalns,
125
126
  localns=localns,
127
+ warn_name_errors=warn_name_errors,
126
128
  dataclass_hook=dataclass_hook,
127
129
  dataclass_defaults=dataclass_defaults,
128
130
  )
@@ -139,6 +141,7 @@ def _pre_process(
139
141
  before: Callable[[Any], Any] | None = None,
140
142
  globalns: StrMapping | None = None,
141
143
  localns: StrMapping | None = None,
144
+ warn_name_errors: bool = False,
142
145
  dataclass_hook: _DataclassHook | None = None,
143
146
  dataclass_defaults: bool = False,
144
147
  error: _ErrorMode = "raise",
@@ -150,6 +153,7 @@ def _pre_process(
150
153
  before=before,
151
154
  globalns=globalns,
152
155
  localns=localns,
156
+ warn_name_errors=warn_name_errors,
153
157
  dataclass_hook=dataclass_hook,
154
158
  dataclass_defaults=dataclass_defaults,
155
159
  error=error,
@@ -196,6 +200,7 @@ def _pre_process(
196
200
  dataclass,
197
201
  globalns=globalns,
198
202
  localns=localns,
203
+ warn_name_errors=warn_name_errors,
199
204
  final=partial(_dataclass_final, hook=dataclass_hook),
200
205
  defaults=dataclass_defaults,
201
206
  )
@@ -212,6 +217,7 @@ def _pre_process(
212
217
  before=before,
213
218
  globalns=globalns,
214
219
  localns=localns,
220
+ warn_name_errors=warn_name_errors,
215
221
  dataclass_hook=dataclass_hook,
216
222
  )
217
223
  case list() as list_:
@@ -222,6 +228,7 @@ def _pre_process(
222
228
  before=before,
223
229
  globalns=globalns,
224
230
  localns=localns,
231
+ warn_name_errors=warn_name_errors,
225
232
  dataclass_hook=dataclass_hook,
226
233
  )
227
234
  case Mapping() as mapping:
@@ -234,6 +241,7 @@ def _pre_process(
234
241
  before=before,
235
242
  globalns=globalns,
236
243
  localns=localns,
244
+ warn_name_errors=warn_name_errors,
237
245
  dataclass_hook=dataclass_hook,
238
246
  )
239
247
  case tuple() as tuple_:
@@ -244,6 +252,7 @@ def _pre_process(
244
252
  before=before,
245
253
  globalns=globalns,
246
254
  localns=localns,
255
+ warn_name_errors=warn_name_errors,
247
256
  dataclass_hook=dataclass_hook,
248
257
  )
249
258
  # other
@@ -263,6 +272,7 @@ def _pre_process_container(
263
272
  before: Callable[[Any], Any] | None = None,
264
273
  globalns: StrMapping | None = None,
265
274
  localns: StrMapping | None = None,
275
+ warn_name_errors: bool = False,
266
276
  dataclass_hook: _DataclassHook | None = None,
267
277
  dataclass_include_defaults: bool = False,
268
278
  ) -> Any:
@@ -272,6 +282,7 @@ def _pre_process_container(
272
282
  before=before,
273
283
  globalns=globalns,
274
284
  localns=localns,
285
+ warn_name_errors=warn_name_errors,
275
286
  dataclass_hook=dataclass_hook,
276
287
  dataclass_defaults=dataclass_include_defaults,
277
288
  )
@@ -716,6 +727,7 @@ class OrjsonFormatter(Formatter):
716
727
  before: Callable[[Any], Any] | None = None,
717
728
  globalns: StrMapping | None = None,
718
729
  localns: StrMapping | None = None,
730
+ warn_name_errors: bool = False,
719
731
  dataclass_hook: _DataclassHook | None = None,
720
732
  dataclass_defaults: bool = False,
721
733
  ) -> None:
@@ -723,6 +735,7 @@ class OrjsonFormatter(Formatter):
723
735
  self._before = before
724
736
  self._globalns = globalns
725
737
  self._localns = localns
738
+ self._warn_name_errors = warn_name_errors
726
739
  self._dataclass_hook = dataclass_hook
727
740
  self._dataclass_defaults = dataclass_defaults
728
741
 
@@ -752,6 +765,7 @@ class OrjsonFormatter(Formatter):
752
765
  before=self._before,
753
766
  globalns=self._globalns,
754
767
  localns=self._localns,
768
+ warn_name_errors=self._warn_name_errors,
755
769
  dataclass_hook=self._dataclass_hook,
756
770
  dataclass_defaults=self._dataclass_defaults,
757
771
  ).decode()
@@ -5,6 +5,7 @@ from contextlib import suppress
5
5
  from dataclasses import dataclass
6
6
  from enum import Enum
7
7
  from pathlib import Path
8
+ from re import DOTALL
8
9
  from types import NoneType
9
10
  from typing import Any, override
10
11
 
@@ -12,9 +13,10 @@ from utilities.datetime import is_subclass_date_not_datetime
12
13
  from utilities.enum import ParseEnumError, parse_enum
13
14
  from utilities.functions import is_subclass_int_not_bool
14
15
  from utilities.iterables import one, one_str
16
+ from utilities.re import ExtractGroupError, extract_group
15
17
  from utilities.sentinel import ParseSentinelError, Sentinel, parse_sentinel
16
18
  from utilities.text import ParseBoolError, ParseNoneError, parse_bool, parse_none
17
- from utilities.typing import get_args, is_literal_type, is_optional_type
19
+ from utilities.typing import get_args, is_literal_type, is_optional_type, is_tuple_type
18
20
  from utilities.version import ParseVersionError, Version, parse_version
19
21
 
20
22
 
@@ -42,6 +44,18 @@ def parse_text(
42
44
  return _parse_text_type(inner, text, case_sensitive=case_sensitive)
43
45
  except ParseTextError:
44
46
  raise ParseTextError(obj=obj, text=text) from None
47
+ if is_tuple_type(obj):
48
+ args = get_args(obj)
49
+ try:
50
+ texts = extract_group(r"^\((.*)\)$", text, flags=DOTALL).split(", ")
51
+ except ExtractGroupError:
52
+ raise ParseTextError(obj=obj, text=text) from None
53
+ if len(args) != len(texts):
54
+ raise ParseTextError(obj=obj, text=text)
55
+ return tuple(
56
+ parse_text(arg, text, case_sensitive=case_sensitive, head=head)
57
+ for arg, text in zip(args, texts, strict=True)
58
+ )
45
59
  raise ParseTextError(obj=obj, text=text) from None
46
60
 
47
61
 
@@ -726,10 +726,13 @@ def dataclass_to_schema(
726
726
  *,
727
727
  globalns: StrMapping | None = None,
728
728
  localns: StrMapping | None = None,
729
+ warn_name_errors: bool = False,
729
730
  ) -> SchemaDict:
730
731
  """Cast a dataclass as a schema dict."""
731
732
  out: dict[str, Any] = {}
732
- for field in yield_fields(obj, globalns=globalns, localns=localns):
733
+ for field in yield_fields(
734
+ obj, globalns=globalns, localns=localns, warn_name_errors=warn_name_errors
735
+ ):
733
736
  if is_dataclass_instance(field.value):
734
737
  dtypes = dataclass_to_schema(
735
738
  field.value, globalns=globalns, localns=localns
@@ -1388,12 +1391,15 @@ def struct_from_dataclass(
1388
1391
  *,
1389
1392
  globalns: StrMapping | None = None,
1390
1393
  localns: StrMapping | None = None,
1394
+ warn_name_errors: bool = False,
1391
1395
  time_zone: TimeZoneLike | None = None,
1392
1396
  ) -> Struct:
1393
1397
  """Construct the Struct data type for a dataclass."""
1394
1398
  if not is_dataclass_class(cls):
1395
1399
  raise _StructFromDataClassNotADataclassError(cls=cls)
1396
- anns = get_type_hints(cls, globalns=globalns, localns=localns)
1400
+ anns = get_type_hints(
1401
+ cls, globalns=globalns, localns=localns, warn_name_errors=warn_name_errors
1402
+ )
1397
1403
  data_types = {
1398
1404
  k: _struct_from_dataclass_one(v, time_zone=time_zone) for k, v in anns.items()
1399
1405
  }
@@ -51,6 +51,7 @@ class OrjsonRegressionFixture:
51
51
  *,
52
52
  globalns: StrMapping | None = None,
53
53
  localns: StrMapping | None = None,
54
+ warn_name_errors: bool = False,
54
55
  dataclass_defaults: bool = False,
55
56
  suffix: str | None = None,
56
57
  ) -> None:
@@ -61,6 +62,7 @@ class OrjsonRegressionFixture:
61
62
  obj,
62
63
  globalns=globalns,
63
64
  localns=localns,
65
+ warn_name_errors=warn_name_errors,
64
66
  dataclass_defaults=dataclass_defaults,
65
67
  )
66
68
  basename = self._basename
@@ -27,6 +27,7 @@ def load_settings(
27
27
  cwd: PathLike = PWD,
28
28
  globalns: StrMapping | None = None,
29
29
  localns: StrMapping | None = None,
30
+ warn_name_errors: bool = False,
30
31
  head: bool = False,
31
32
  case_sensitive: bool = False,
32
33
  ) -> TDataclass:
@@ -53,6 +54,7 @@ def load_settings(
53
54
  cls,
54
55
  globalns=globalns,
55
56
  localns=localns,
57
+ warn_name_errors=warn_name_errors,
56
58
  head=head,
57
59
  case_sensitive=case_sensitive,
58
60
  allow_extra=True,
@@ -19,6 +19,7 @@ from typing import (
19
19
  from typing import get_args as _get_args
20
20
  from typing import get_type_hints as _get_type_hints
21
21
  from uuid import UUID
22
+ from warnings import warn
22
23
 
23
24
  from utilities.iterables import unique_everseen
24
25
  from utilities.sentinel import Sentinel
@@ -68,16 +69,18 @@ def get_type_hints(
68
69
  *,
69
70
  globalns: StrMapping | None = None,
70
71
  localns: StrMapping | None = None,
72
+ warn_name_errors: bool = False,
71
73
  ) -> dict[str, Any]:
72
74
  """Get the type hints of an object."""
73
75
  result: dict[str, Any] = cls.__annotations__
74
76
  _ = {Literal, Path, Sentinel, StrMapping, UUID, dt}
75
- globalns = globals() | ({} if globalns is None else dict(globalns))
76
- localns = {} if localns is None else dict(localns)
77
+ globalns_use = globals() | ({} if globalns is None else dict(globalns))
78
+ localns_use = {} if localns is None else dict(localns)
77
79
  try:
78
- hints = _get_type_hints(cls, globalns=globalns, localns=localns)
79
- except NameError:
80
- pass
80
+ hints = _get_type_hints(cls, globalns=globalns_use, localns=localns_use)
81
+ except NameError as error:
82
+ if warn_name_errors:
83
+ warn(f"Error getting type hints for {cls!r}; {error}", stacklevel=2)
81
84
  else:
82
85
  result.update({
83
86
  key: value
@@ -179,6 +182,14 @@ def is_set_type(obj: Any, /) -> bool:
179
182
  ##
180
183
 
181
184
 
185
+ def is_tuple_type(obj: Any, /) -> bool:
186
+ """Check if an object is a tuple type annotation."""
187
+ return _is_annotation_of_type(obj, tuple)
188
+
189
+
190
+ ##
191
+
192
+
182
193
  def is_union_type(obj: Any, /) -> bool:
183
194
  """Check if an object is a union type annotation."""
184
195
  is_old_union = _is_annotation_of_type(obj, Union) # pyright: ignore[reportDeprecated]
@@ -209,5 +220,6 @@ __all__ = [
209
220
  "is_optional_type",
210
221
  "is_sequence_type",
211
222
  "is_set_type",
223
+ "is_tuple_type",
212
224
  "is_union_type",
213
225
  ]