dycw-utilities 0.108.4__tar.gz → 0.109.1__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.108.4 → dycw_utilities-0.109.1}/PKG-INFO +1 -1
  2. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/pyproject.toml +2 -2
  3. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_dataclasses.py +210 -107
  4. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_operator.py +22 -0
  5. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_orjson.py +20 -0
  6. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_parse.py +10 -1
  7. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_polars.py +0 -184
  8. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_python_dotenv.py +4 -20
  9. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_typing.py +27 -13
  10. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_typing_funcs/no_future.py +4 -0
  11. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_typing_funcs/with_future.py +24 -12
  12. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/__init__.py +1 -1
  13. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/dataclasses.py +202 -104
  14. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/parse.py +2 -2
  15. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/polars.py +0 -99
  16. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/python_dotenv.py +24 -43
  17. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/.gitignore +0 -0
  18. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/LICENSE +0 -0
  19. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/README.md +0 -0
  20. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/__init__.py +0 -0
  21. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/conftest.py +0 -0
  22. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/modules/__init__.py +0 -0
  23. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/modules/package_missing/__init__.py +0 -0
  24. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/modules/package_missing/module.py +0 -0
  25. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/modules/package_with/__init__.py +0 -0
  26. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/modules/package_with/outer_1.py +0 -0
  27. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/modules/package_with/outer_2.py +0 -0
  28. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  29. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  30. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  31. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  32. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/modules/package_without/__init__.py +0 -0
  33. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/modules/package_without/module_1.py +0 -0
  34. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/modules/package_without/module_2.py +0 -0
  35. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/modules/standalone.py +0 -0
  36. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/modules/with_imports.py +0 -0
  37. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  38. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  39. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  40. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  41. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  42. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  43. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  44. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  45. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/scripts/__init__.py +0 -0
  46. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/scripts/test_async_service/__init__.py +0 -0
  47. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/scripts/test_async_service/__main__.py +0 -0
  48. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/scripts/test_async_service/run.sh +0 -0
  49. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/scripts/test_queue_processor/__init__.py +0 -0
  50. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/scripts/test_queue_processor/__main__.py +0 -0
  51. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/scripts/test_queue_processor/run.sh +0 -0
  52. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_altair.py +0 -0
  53. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_astor.py +0 -0
  54. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_asyncio.py +0 -0
  55. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_atomicwrites.py +0 -0
  56. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_atools.py +0 -0
  57. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_cachetools.py +0 -0
  58. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_click.py +0 -0
  59. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_concurrent.py +0 -0
  60. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_contextlib.py +0 -0
  61. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_contextvars.py +0 -0
  62. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_cryptography.py +0 -0
  63. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_cvxpy.py +0 -0
  64. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_datetime.py +0 -0
  65. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_enum.py +0 -0
  66. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_errors.py +0 -0
  67. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_eventkit.py +0 -0
  68. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_fastapi.py +0 -0
  69. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_fpdf2.py +0 -0
  70. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_functions.py +0 -0
  71. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_functools.py +0 -0
  72. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_getpass.py +0 -0
  73. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_git.py +0 -0
  74. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_hashlib.py +0 -0
  75. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_http.py +0 -0
  76. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_hypothesis.py +0 -0
  77. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_ipython.py +0 -0
  78. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_iterables.py +0 -0
  79. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_jupyter.py +0 -0
  80. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_logging.py +0 -0
  81. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_loguru.py +0 -0
  82. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_luigi.py +0 -0
  83. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_math.py +0 -0
  84. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_memory_profiler.py +0 -0
  85. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_modules.py +0 -0
  86. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_more_itertools.py +0 -0
  87. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_numpy.py +0 -0
  88. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_optuna.py +0 -0
  89. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_os.py +0 -0
  90. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_pathlib.py +0 -0
  91. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_period.py +0 -0
  92. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_pickle.py +0 -0
  93. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_platform.py +0 -0
  94. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_pqdm.py +0 -0
  95. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_pydantic.py +0 -0
  96. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_pyinstrument.py +0 -0
  97. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_pyrsistent.py +0 -0
  98. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_pytest.py +0 -0
  99. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_pytest_regressions.py +0 -0
  100. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_random.py +0 -0
  101. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_re.py +0 -0
  102. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_redis.py +0 -0
  103. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_reprlib.py +0 -0
  104. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_rich.py +0 -0
  105. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_scipy.py +0 -0
  106. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_sentinel.py +0 -0
  107. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_shelve.py +0 -0
  108. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_slack_sdk.py +0 -0
  109. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_socket.py +0 -0
  110. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_sqlalchemy.py +0 -0
  111. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_sqlalchemy_polars.py +0 -0
  112. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_streamlit.py +0 -0
  113. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_sys.py +0 -0
  114. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_tempfile.py +0 -0
  115. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_tenacity.py +0 -0
  116. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_text.py +0 -0
  117. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_threading.py +0 -0
  118. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_timer.py +0 -0
  119. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_traceback.py +0 -0
  120. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/__init__.py +0 -0
  121. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/chain.py +0 -0
  122. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
  123. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
  124. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/error_bind.py +0 -0
  125. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/many.py +0 -0
  126. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/one.py +0 -0
  127. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/recursive.py +0 -0
  128. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
  129. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
  130. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/two.py +0 -0
  131. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/untraced.py +0 -0
  132. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_types.py +0 -0
  133. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_typing_funcs/__init__.py +0 -0
  134. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_tzdata.py +0 -0
  135. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_tzlocal.py +0 -0
  136. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_uuid.py +0 -0
  137. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_version.py +0 -0
  138. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_warnings.py +0 -0
  139. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_whenever.py +0 -0
  140. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_zipfile.py +0 -0
  141. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/tests/test_zoneinfo.py +0 -0
  142. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/altair.py +0 -0
  143. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/astor.py +0 -0
  144. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/asyncio.py +0 -0
  145. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/atomicwrites.py +0 -0
  146. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/atools.py +0 -0
  147. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/cachetools.py +0 -0
  148. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/click.py +0 -0
  149. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/concurrent.py +0 -0
  150. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/contextlib.py +0 -0
  151. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/contextvars.py +0 -0
  152. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/cryptography.py +0 -0
  153. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/cvxpy.py +0 -0
  154. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/datetime.py +0 -0
  155. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/enum.py +0 -0
  156. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/errors.py +0 -0
  157. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/eventkit.py +0 -0
  158. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/fastapi.py +0 -0
  159. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/fpdf2.py +0 -0
  160. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/functions.py +0 -0
  161. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/functools.py +0 -0
  162. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/getpass.py +0 -0
  163. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/git.py +0 -0
  164. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/hashlib.py +0 -0
  165. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/http.py +0 -0
  166. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/hypothesis.py +0 -0
  167. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/ipython.py +0 -0
  168. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/iterables.py +0 -0
  169. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/jupyter.py +0 -0
  170. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/logging.py +0 -0
  171. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/loguru.py +0 -0
  172. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/luigi.py +0 -0
  173. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/math.py +0 -0
  174. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/memory_profiler.py +0 -0
  175. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/modules.py +0 -0
  176. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/more_itertools.py +0 -0
  177. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/numpy.py +0 -0
  178. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/operator.py +0 -0
  179. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/optuna.py +0 -0
  180. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/orjson.py +0 -0
  181. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/os.py +0 -0
  182. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/pathlib.py +0 -0
  183. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/period.py +0 -0
  184. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/pickle.py +0 -0
  185. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/platform.py +0 -0
  186. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/pqdm.py +0 -0
  187. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/py.typed +0 -0
  188. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/pydantic.py +0 -0
  189. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/pyinstrument.py +0 -0
  190. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/pyrsistent.py +0 -0
  191. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/pytest.py +0 -0
  192. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/pytest_regressions.py +0 -0
  193. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/random.py +0 -0
  194. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/re.py +0 -0
  195. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/redis.py +0 -0
  196. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/reprlib.py +0 -0
  197. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/rich.py +0 -0
  198. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/scipy.py +0 -0
  199. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/sentinel.py +0 -0
  200. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/shelve.py +0 -0
  201. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/slack_sdk.py +0 -0
  202. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/socket.py +0 -0
  203. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/sqlalchemy.py +0 -0
  204. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/sqlalchemy_polars.py +0 -0
  205. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/streamlit.py +0 -0
  206. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/sys.py +0 -0
  207. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/tempfile.py +0 -0
  208. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/tenacity.py +0 -0
  209. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/text.py +0 -0
  210. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/threading.py +0 -0
  211. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/timer.py +0 -0
  212. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/traceback.py +0 -0
  213. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/types.py +0 -0
  214. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/typing.py +0 -0
  215. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/tzdata.py +0 -0
  216. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/tzlocal.py +0 -0
  217. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/uuid.py +0 -0
  218. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/version.py +0 -0
  219. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/warnings.py +0 -0
  220. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/whenever.py +0 -0
  221. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/zipfile.py +0 -0
  222. {dycw_utilities-0.108.4 → dycw_utilities-0.109.1}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.108.4
3
+ Version: 0.109.1
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.108.4"
92
+ version = "0.109.1"
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.108.4"
335
+ current_version = "0.109.1"
336
336
 
337
337
  [[tool.bumpversion.files]]
338
338
  filename = "src/utilities/__init__.py"
@@ -1,22 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
- import re
4
3
  from dataclasses import dataclass, field
5
4
  from pathlib import Path
6
- from re import DOTALL
7
5
  from types import NoneType
8
- from typing import Any, Literal, cast, override
6
+ from typing import Any, cast, override
9
7
 
10
8
  from hypothesis import given
11
- from hypothesis.strategies import (
12
- DataObject,
13
- booleans,
14
- data,
15
- integers,
16
- lists,
17
- none,
18
- sampled_from,
19
- )
9
+ from hypothesis.strategies import booleans, integers, lists, sampled_from
20
10
  from polars import DataFrame
21
11
  from pytest import raises
22
12
 
@@ -27,7 +17,8 @@ from tests.test_typing_funcs.no_future import (
27
17
  from tests.test_typing_funcs.with_future import (
28
18
  DataClassFutureInt,
29
19
  DataClassFutureIntDefault,
30
- DataClassFutureIntNullable,
20
+ DataClassFutureIntLowerAndUpper,
21
+ DataClassFutureIntOneAndTwo,
31
22
  DataClassFutureListInts,
32
23
  DataClassFutureListIntsDefault,
33
24
  DataClassFutureLiteral,
@@ -36,17 +27,17 @@ from tests.test_typing_funcs.with_future import (
36
27
  DataClassFutureNestedOuterFirstOuter,
37
28
  DataClassFutureNone,
38
29
  DataClassFutureNoneDefault,
39
- DataClassFuturePath,
40
- DataClassFutureStr,
41
30
  DataClassFutureTypeLiteral,
42
31
  DataClassFutureTypeLiteralNullable,
32
+ TrueOrFalseFutureLit,
33
+ TrueOrFalseFutureTypeLit,
43
34
  )
44
35
  from utilities.dataclasses import (
36
+ MappingToDataclassError,
37
+ OneFieldEmptyError,
38
+ OneFieldNonUniqueError,
39
+ StrMappingToFieldMappingError,
45
40
  YieldFieldsError,
46
- _MappingToDataclassCaseInsensitiveNonUniqueError,
47
- _MappingToDataclassEmptyError,
48
- _TextToDataClassGetFieldEmptyError,
49
- _TextToDataClassGetFieldNonUniqueError,
50
41
  _TextToDataClassParseValueError,
51
42
  _TextToDataClassSplitKeyValuePairError,
52
43
  _YieldFieldsClass,
@@ -54,12 +45,13 @@ from utilities.dataclasses import (
54
45
  dataclass_repr,
55
46
  dataclass_to_dict,
56
47
  mapping_to_dataclass,
48
+ one_field,
57
49
  replace_non_sentinel,
50
+ str_mapping_to_field_mapping,
58
51
  text_to_dataclass,
59
52
  yield_fields,
60
53
  )
61
54
  from utilities.functions import get_class_name
62
- from utilities.hypothesis import paths, text_ascii
63
55
  from utilities.iterables import one
64
56
  from utilities.orjson import OrjsonLogRecord
65
57
  from utilities.polars import are_frames_equal
@@ -67,8 +59,6 @@ from utilities.sentinel import sentinel
67
59
  from utilities.types import Dataclass, StrMapping
68
60
  from utilities.typing import get_args, is_list_type, is_literal_type, is_optional_type
69
61
 
70
- TruthLit = Literal["true", "false"] # in 3.12, use type TruthLit = ...
71
-
72
62
 
73
63
  class TestDataClassRepr:
74
64
  def test_overriding_repr(self) -> None:
@@ -273,82 +263,102 @@ class TestDataclassToDictAndDataclassRepr:
273
263
 
274
264
 
275
265
  class TestMappingToDataclass:
276
- @given(int_=integers())
277
- def test_int_case_sensitive(self, *, int_: int) -> None:
278
- obj = mapping_to_dataclass(DataClassFutureInt, {"int_": int_})
279
- expected = DataClassFutureInt(int_=int_)
280
- assert obj == expected
281
-
282
266
  @given(key=sampled_from(["int_", "INT_"]), int_=integers())
283
- def test_int_case_insensitive(self, *, key: str, int_: int) -> None:
267
+ def test_exact_match_case_insensitive(self, *, key: str, int_: int) -> None:
284
268
  obj = mapping_to_dataclass(DataClassFutureInt, {key: int_})
285
269
  expected = DataClassFutureInt(int_=int_)
286
270
  assert obj == expected
287
271
 
288
- @given(data=data(), int_=integers() | none())
289
- def test_int_nullable(self, *, data: DataObject, int_: int | None) -> None:
290
- if int_ is None:
291
- mapping = data.draw(sampled_from([{"int_": int_}, {}]))
292
- else:
293
- mapping = {"int_": int_}
294
- obj = mapping_to_dataclass(DataClassFutureIntNullable, mapping)
295
- expected = DataClassFutureIntNullable(int_=int_)
272
+ @given(key=sampled_from(["in", "IN"]), int_=integers())
273
+ def test_head_case_insensitive(self, *, key: str, int_: int) -> None:
274
+ obj = mapping_to_dataclass(DataClassFutureInt, {key: int_}, head=True)
275
+ expected = DataClassFutureInt(int_=int_)
296
276
  assert obj == expected
297
277
 
298
- @given(data=data(), ints=lists(integers()))
299
- def test_list_ints_nullable(self, *, data: DataObject, ints: list[int]) -> None:
300
- if len(ints) == 0:
301
- mapping = data.draw(sampled_from([{"ints": ints}, {}]))
302
- else:
303
- mapping = {"ints": ints}
304
- obj = mapping_to_dataclass(DataClassFutureListIntsDefault, mapping)
305
- expected = DataClassFutureListIntsDefault(ints=ints)
278
+ @given(int_=integers())
279
+ def test_exact_match_case_sensitive(self, *, int_: int) -> None:
280
+ obj = mapping_to_dataclass(
281
+ DataClassFutureInt, {"int_": int_}, case_sensitive=True
282
+ )
283
+ expected = DataClassFutureInt(int_=int_)
306
284
  assert obj == expected
307
285
 
308
- @given(value=paths())
309
- def test_path(self, *, value: Path) -> None:
310
- obj = mapping_to_dataclass(DataClassFuturePath, {"path": value})
311
- expected = DataClassFuturePath(path=value)
286
+ @given(int_=integers())
287
+ def test_head_case_sensitive(self, *, int_: int) -> None:
288
+ obj = mapping_to_dataclass(
289
+ DataClassFutureInt, {"int": int_}, head=True, case_sensitive=True
290
+ )
291
+ expected = DataClassFutureInt(int_=int_)
312
292
  assert obj == expected
313
293
 
314
- @given(value=text_ascii())
315
- def test_post(self, *, value: str) -> None:
294
+ @given(int_=integers())
295
+ def test_extra_key(self, *, int_: int) -> None:
316
296
  obj = mapping_to_dataclass(
317
- DataClassFutureStr, {"str_": value}, post=lambda _, x: x.upper()
297
+ DataClassFutureInt, {"int_": int_, "extra": int_}, allow_extra=True
318
298
  )
319
- expected = DataClassFutureStr(str_=value.upper())
299
+ expected = DataClassFutureInt(int_=int_)
320
300
  assert obj == expected
321
301
 
322
- @given(value=integers())
323
- def test_error_case_sensitive_empty_error(self, *, value: int) -> None:
302
+ def test_error(self) -> None:
303
+ with raises(
304
+ MappingToDataclassError,
305
+ match="Unable to construct 'DataClassFutureInt'; missing values for 'int_'",
306
+ ):
307
+ _ = mapping_to_dataclass(DataClassFutureInt, {})
308
+
309
+
310
+ class TestOneField:
311
+ def test_error_exact_match_case_insensitive_empty_error(self) -> None:
324
312
  with raises(
325
- _MappingToDataclassEmptyError, match=r"Mapping .* does not contain 'int_'"
313
+ OneFieldEmptyError,
314
+ match=r"Dataclass 'DataClassFutureInt' does not contain a field 'invalid' \(modulo case\)",
326
315
  ):
327
- _ = mapping_to_dataclass(
328
- DataClassFutureInt, {"INT_": value}, case_sensitive=True
329
- )
316
+ _ = one_field(DataClassFutureInt, "invalid")
330
317
 
331
- @given(value=integers())
332
- def test_error_case_insensitive_empty_error(self, *, value: int) -> None:
318
+ def test_error_exact_match_case_insensitive_non_unique_error(self) -> None:
333
319
  with raises(
334
- _MappingToDataclassEmptyError,
335
- match=r"Mapping .* does not contain 'int_' \(modulo case\)",
320
+ OneFieldNonUniqueError,
321
+ match=r"Dataclass 'DataClassFutureIntLowerAndUpper' must contain field 'int_' exactly once \(modulo case\); got 'int_', 'INT_' and perhaps more",
336
322
  ):
337
- _ = mapping_to_dataclass(DataClassFutureInt, {"other": value})
323
+ _ = one_field(DataClassFutureIntLowerAndUpper, "int_")
338
324
 
339
- @given(value1=integers(), value2=integers())
340
- def test_error_case_insensitive_non_unique_error(
341
- self, *, value1: int, value2: int
342
- ) -> None:
325
+ def test_error_head_case_insensitive_empty_error(self) -> None:
343
326
  with raises(
344
- _MappingToDataclassCaseInsensitiveNonUniqueError,
345
- match=re.compile(
346
- r"Mapping .* must contain 'int_' exactly once \(modulo case\); got 'int_', 'INT_' and perhaps more",
347
- flags=DOTALL,
348
- ),
327
+ OneFieldEmptyError,
328
+ match=r"Dataclass 'DataClassFutureInt' does not contain any field starting with 'invalid' \(modulo case\)",
349
329
  ):
350
- _ = mapping_to_dataclass(
351
- DataClassFutureInt, {"int_": value1, "INT_": value2}
330
+ _ = one_field(DataClassFutureInt, "invalid", head=True)
331
+
332
+ def test_error_head_case_insensitive_non_unique_error(self) -> None:
333
+ with raises(
334
+ OneFieldNonUniqueError,
335
+ match=r"Dataclass 'DataClassFutureIntOneAndTwo' must contain exactly one field starting with 'int' \(modulo case\); got 'int1', 'int2' and perhaps more",
336
+ ):
337
+ _ = one_field(DataClassFutureIntOneAndTwo, "int", head=True)
338
+
339
+ def test_error_exact_match_case_sensitive_empty_error(self) -> None:
340
+ with raises(
341
+ OneFieldEmptyError,
342
+ match=r"Dataclass 'DataClassFutureInt' does not contain a field 'INT_'",
343
+ ):
344
+ _ = one_field(DataClassFutureInt, "INT_", case_sensitive=True)
345
+
346
+ # there is no head=False, case_sensitive=True, non-unique case
347
+
348
+ def test_error_head_case_sensitive_empty_error(self) -> None:
349
+ with raises(
350
+ OneFieldEmptyError,
351
+ match=r"Dataclass 'DataClassFutureInt' does not contain any field starting with 'INT_'",
352
+ ):
353
+ _ = one_field(DataClassFutureInt, "INT_", head=True, case_sensitive=True)
354
+
355
+ def test_error_head_case_sensitive_non_unique_error(self) -> None:
356
+ with raises(
357
+ OneFieldNonUniqueError,
358
+ match=r"Dataclass 'DataClassFutureIntOneAndTwo' must contain exactly one field starting with 'int'; got 'int1', 'int2' and perhaps more",
359
+ ):
360
+ _ = one_field(
361
+ DataClassFutureIntOneAndTwo, "int", head=True, case_sensitive=True
352
362
  )
353
363
 
354
364
 
@@ -370,16 +380,117 @@ class TestReplaceNonSentinel:
370
380
  assert obj.int_ == 1
371
381
 
372
382
 
383
+ class TestStrMappingToFieldMapping:
384
+ @given(key=sampled_from(["int_", "INT_"]), int_=integers())
385
+ def test_main_text_case_insensitive(self, *, key: str, int_: int) -> None:
386
+ result = str_mapping_to_field_mapping(DataClassFutureInt, {key: int_})
387
+ assert len(result) == 1
388
+ assert one(result) == one(yield_fields(DataClassFutureInt))
389
+ assert one(result.values()) == int_
390
+
391
+ @given(key=sampled_from(["in", "IN"]), int_=integers())
392
+ def test_head_case_insensitive(self, *, key: str, int_: int) -> None:
393
+ result = str_mapping_to_field_mapping(
394
+ DataClassFutureInt, {key: int_}, head=True
395
+ )
396
+ assert len(result) == 1
397
+ assert one(result) == one(yield_fields(DataClassFutureInt))
398
+ assert one(result.values()) == int_
399
+
400
+ @given(int_=integers())
401
+ def test_exact_match_case_sensitive(self, *, int_: int) -> None:
402
+ result = str_mapping_to_field_mapping(
403
+ DataClassFutureInt, {"int_": int_}, case_sensitive=True
404
+ )
405
+ assert len(result) == 1
406
+ assert one(result) == one(yield_fields(DataClassFutureInt))
407
+ assert one(result.values()) == int_
408
+
409
+ @given(int_=integers())
410
+ def test_head_case_sensitive(self, *, int_: int) -> None:
411
+ result = str_mapping_to_field_mapping(
412
+ DataClassFutureInt, {"int": int_}, head=True, case_sensitive=True
413
+ )
414
+ assert len(result) == 1
415
+ assert one(result) == one(yield_fields(DataClassFutureInt))
416
+ assert one(result.values()) == int_
417
+
418
+ @given(int_=integers())
419
+ def test_extra_key(self, *, int_: int) -> None:
420
+ result = str_mapping_to_field_mapping(
421
+ DataClassFutureInt, {"int_": int_, "extra": int_}, allow_extra=True
422
+ )
423
+ assert len(result) == 1
424
+ assert one(result) == one(yield_fields(DataClassFutureInt))
425
+ assert one(result.values()) == int_
426
+
427
+ @given(int_=integers())
428
+ def test_error_exact_match_case_insensitive(self, *, int_: int) -> None:
429
+ with raises(
430
+ StrMappingToFieldMappingError,
431
+ match=r"Dataclass 'DataClassFutureInt' does not contain a field 'invalid' \(modulo case\)",
432
+ ):
433
+ _ = str_mapping_to_field_mapping(
434
+ DataClassFutureInt, {"int_": int_, "invalid": int_}
435
+ )
436
+
437
+ @given(int_=integers())
438
+ def test_error_exact_match_case_sensitive(self, *, int_: int) -> None:
439
+ with raises(
440
+ StrMappingToFieldMappingError,
441
+ match=r"Dataclass 'DataClassFutureInt' does not contain a field 'extra'",
442
+ ):
443
+ _ = str_mapping_to_field_mapping(
444
+ DataClassFutureInt, {"int_": int_, "extra": int_}, case_sensitive=True
445
+ )
446
+
447
+ @given(int_=integers())
448
+ def test_error_head_case_insensitive(self, *, int_: int) -> None:
449
+ with raises(
450
+ StrMappingToFieldMappingError,
451
+ match=r"Dataclass .* does not contain any field starting with 'invalid' \(modulo case\)",
452
+ ):
453
+ _ = str_mapping_to_field_mapping(
454
+ DataClassFutureInt, {"invalid": int_}, head=True
455
+ )
456
+
457
+ @given(int_=integers())
458
+ def test_error_head_case_sensitive(self, *, int_: int) -> None:
459
+ with raises(
460
+ StrMappingToFieldMappingError,
461
+ match=r"Dataclass .* does not contain any field starting with 'invalid'",
462
+ ):
463
+ _ = str_mapping_to_field_mapping(
464
+ DataClassFutureInt, {"invalid": int_}, head=True, case_sensitive=True
465
+ )
466
+
467
+
373
468
  class TestTextToDataClass:
469
+ @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)
472
+ expected = DataClassFutureInt(int_=int_)
473
+ assert result == expected
474
+
374
475
  @given(int_=integers())
375
- def test_main_text(self, *, int_: int) -> None:
376
- result = text_to_dataclass(f"int_={int_}", DataClassFutureInt)
476
+ def test_main_text_case_sensitive(self, *, int_: int) -> None:
477
+ result = text_to_dataclass(
478
+ f"int_={int_}", DataClassFutureInt, case_sensitive=True
479
+ )
480
+ expected = DataClassFutureInt(int_=int_)
481
+ assert result == expected
482
+
483
+ @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)
377
486
  expected = DataClassFutureInt(int_=int_)
378
487
  assert result == expected
379
488
 
380
489
  @given(int_=integers())
381
- def test_main_mapping(self, *, int_: int) -> None:
382
- result = text_to_dataclass({"int_": str(int_)}, DataClassFutureInt)
490
+ def test_main_mapping_case_sensitive(self, *, int_: int) -> None:
491
+ result = text_to_dataclass(
492
+ {"int_": str(int_)}, DataClassFutureInt, case_sensitive=True
493
+ )
383
494
  expected = DataClassFutureInt(int_=int_)
384
495
  assert result == expected
385
496
 
@@ -390,25 +501,6 @@ class TestTextToDataClass:
390
501
  ):
391
502
  _ = text_to_dataclass("keyvalue", DataClassFutureInt)
392
503
 
393
- def test_error_get_field_empty(self) -> None:
394
- with raises(
395
- _TextToDataClassGetFieldEmptyError,
396
- match=r"Dataclass 'DataClassFutureInt' does not contain any field starting with 'k' \(modulo case\)",
397
- ):
398
- _ = text_to_dataclass("k=value", DataClassFutureInt)
399
-
400
- def test_error_get_field_non_unique(self) -> None:
401
- @dataclass(order=True, unsafe_hash=True, kw_only=True)
402
- class Example:
403
- int1: int
404
- int2: int
405
-
406
- with raises(
407
- _TextToDataClassGetFieldNonUniqueError,
408
- match=r"Dataclass 'Example' must contain exactly one field starting with 'int' \(modulo case\); got 'int1', 'int2' and perhaps more",
409
- ):
410
- _ = text_to_dataclass("int=value", Example)
411
-
412
504
  def test_error_parse_value(self) -> None:
413
505
  with raises(
414
506
  _TextToDataClassParseValueError,
@@ -462,21 +554,23 @@ class TestYieldFields:
462
554
  assert get_args(result.type_) == (int,)
463
555
 
464
556
  def test_class_future_literal(self) -> None:
465
- result = one(yield_fields(DataClassFutureLiteral))
466
- expected = _YieldFieldsClass(name="truth", type_=TruthLit, kw_only=True)
557
+ result = one(yield_fields(DataClassFutureLiteral, globalns=globals()))
558
+ expected = _YieldFieldsClass(
559
+ name="truth", type_=TrueOrFalseFutureLit, kw_only=True
560
+ )
467
561
  assert result == expected
468
562
  assert is_literal_type(result.type_)
469
563
  assert get_args(result.type_) == ("true", "false")
470
564
 
471
565
  def test_class_future_literal_nullable(self) -> None:
472
- result = one(yield_fields(DataClassFutureLiteralNullable))
566
+ result = one(yield_fields(DataClassFutureLiteralNullable, globalns=globals()))
473
567
  expected = _YieldFieldsClass(
474
- name="truth", type_=TruthLit | None, default=None, kw_only=True
568
+ name="truth", type_=TrueOrFalseFutureLit | None, default=None, kw_only=True
475
569
  )
476
570
  assert result == expected
477
571
  assert is_optional_type(result.type_)
478
572
  args = get_args(result.type_)
479
- assert args == (Literal["true", "false"],)
573
+ assert args == (TrueOrFalseFutureLit,)
480
574
  arg = one(args)
481
575
  assert get_args(arg) == ("true", "false")
482
576
 
@@ -491,8 +585,14 @@ class TestYieldFields:
491
585
  assert result.type_ is DataClassFutureNestedOuterFirstInner
492
586
 
493
587
  def test_class_future_type_literal(self) -> None:
494
- result = one(yield_fields(DataClassFutureTypeLiteral, globalns=globals()))
495
- expected = _YieldFieldsClass(name="truth", type_=TruthLit, kw_only=True)
588
+ result = one(
589
+ yield_fields(
590
+ DataClassFutureTypeLiteral, globalns=globals(), localns=locals()
591
+ )
592
+ )
593
+ expected = _YieldFieldsClass(
594
+ name="truth", type_=TrueOrFalseFutureTypeLit, kw_only=True
595
+ )
496
596
  assert result == expected
497
597
  assert is_literal_type(result.type_)
498
598
  assert get_args(result.type_) == ("true", "false")
@@ -502,12 +602,15 @@ class TestYieldFields:
502
602
  yield_fields(DataClassFutureTypeLiteralNullable, globalns=globals())
503
603
  )
504
604
  expected = _YieldFieldsClass(
505
- name="truth", type_=TruthLit | None, default=None, kw_only=True
605
+ name="truth",
606
+ type_=TrueOrFalseFutureTypeLit | None,
607
+ default=None,
608
+ kw_only=True,
506
609
  )
507
610
  assert result == expected
508
611
  assert is_optional_type(result.type_)
509
612
  args = get_args(result.type_)
510
- assert args == (Literal["true", "false"],)
613
+ assert args == (TrueOrFalseFutureTypeLit,)
511
614
  arg = one(args)
512
615
  assert get_args(arg) == ("true", "false")
513
616
 
@@ -43,6 +43,8 @@ from tests.test_typing_funcs.with_future import (
43
43
  DataClassFutureNestedInnerFirstOuter,
44
44
  DataClassFutureNestedOuterFirstOuter,
45
45
  DataClassFutureNone,
46
+ DataClassFutureTypeLiteral,
47
+ DataClassFutureTypeLiteralNullable,
46
48
  )
47
49
  from utilities.hypothesis import (
48
50
  assume_does_not_raise,
@@ -76,6 +78,8 @@ def base_objects(
76
78
  dataclass_literal_nullable: bool = False,
77
79
  dataclass_nested: bool = False,
78
80
  dataclass_none: bool = False,
81
+ dataclass_type_literal: bool = False,
82
+ dataclass_type_literal_nullable: bool = False,
79
83
  enum: bool = False,
80
84
  exception_class: bool = False,
81
85
  exception_instance: bool = False,
@@ -132,6 +136,15 @@ def base_objects(
132
136
  )
133
137
  if dataclass_none:
134
138
  base |= builds(DataClassFutureNone)
139
+ if dataclass_type_literal:
140
+ base |= builds(
141
+ DataClassFutureTypeLiteral, truth=sampled_from(["true", "false"])
142
+ )
143
+ if dataclass_type_literal_nullable:
144
+ base |= builds(
145
+ DataClassFutureTypeLiteralNullable,
146
+ truth=sampled_from(["true", "false"]) | none(),
147
+ )
135
148
  if enum:
136
149
  base |= sampled_from(TruthEnum)
137
150
  if exception_class:
@@ -151,6 +164,8 @@ def make_objects(
151
164
  dataclass_literal_nullable: bool = False,
152
165
  dataclass_nested: bool = False,
153
166
  dataclass_none: bool = False,
167
+ dataclass_type_literal: bool = False,
168
+ dataclass_type_literal_nullable: bool = False,
154
169
  enum: bool = False,
155
170
  exception_class: bool = False,
156
171
  exception_instance: bool = False,
@@ -173,6 +188,8 @@ def make_objects(
173
188
  dataclass_literal_nullable=dataclass_literal_nullable,
174
189
  dataclass_nested=dataclass_nested,
175
190
  dataclass_none=dataclass_none,
191
+ dataclass_type_literal=dataclass_type_literal,
192
+ dataclass_type_literal_nullable=dataclass_type_literal_nullable,
176
193
  enum=enum,
177
194
  exception_class=exception_class,
178
195
  exception_instance=exception_instance,
@@ -272,6 +289,8 @@ class TestIsEqual:
272
289
  dataclass_literal_nullable=True,
273
290
  dataclass_nested=True,
274
291
  dataclass_none=True,
292
+ dataclass_type_literal=True,
293
+ dataclass_type_literal_nullable=True,
275
294
  enum=True,
276
295
  sub_frozenset=True,
277
296
  sub_list=True,
@@ -287,12 +306,15 @@ class TestIsEqual:
287
306
  objs=pairs(
288
307
  make_objects(
289
308
  dataclass_custom_equality=True,
309
+ dataclass_default_in_init_child=True,
290
310
  dataclass_int=True,
291
311
  dataclass_int_default=True,
292
312
  dataclass_literal=True,
293
313
  dataclass_literal_nullable=True,
294
314
  dataclass_nested=True,
295
315
  dataclass_none=True,
316
+ dataclass_type_literal=True,
317
+ dataclass_type_literal_nullable=True,
296
318
  enum=True,
297
319
  sub_frozenset=True,
298
320
  sub_list=True,
@@ -48,6 +48,8 @@ from tests.test_typing_funcs.with_future import (
48
48
  DataClassFutureNestedOuterFirstInner,
49
49
  DataClassFutureNestedOuterFirstOuter,
50
50
  DataClassFutureNone,
51
+ DataClassFutureTypeLiteral,
52
+ DataClassFutureTypeLiteralNullable,
51
53
  )
52
54
  from utilities.datetime import MINUTE, SECOND, get_now, get_now_local
53
55
  from utilities.functions import is_sequence_of
@@ -435,12 +437,15 @@ class TestSerializeAndDeserialize:
435
437
  @given(
436
438
  obj=make_objects(
437
439
  dataclass_custom_equality=True,
440
+ dataclass_default_in_init_child=False,
438
441
  dataclass_int=True,
439
442
  dataclass_int_default=True,
440
443
  dataclass_literal=True,
441
444
  dataclass_literal_nullable=True,
442
445
  dataclass_nested=True,
443
446
  dataclass_none=True,
447
+ dataclass_type_literal=True,
448
+ dataclass_type_literal_nullable=True,
444
449
  enum=True,
445
450
  exception_class=True,
446
451
  exception_instance=True,
@@ -467,6 +472,8 @@ class TestSerializeAndDeserialize:
467
472
  DataClassFutureNestedOuterFirstInner,
468
473
  DataClassFutureNestedOuterFirstOuter,
469
474
  DataClassFutureNone,
475
+ DataClassFutureTypeLiteral,
476
+ DataClassFutureTypeLiteralNullable,
470
477
  SubFrozenSet,
471
478
  SubList,
472
479
  SubSet,
@@ -559,6 +566,19 @@ class TestSerializeAndDeserialize:
559
566
  result = deserialize(ser, objects={DataClassFutureNone})
560
567
  assert is_equal(result, obj)
561
568
 
569
+ @given(obj=make_objects(dataclass_type_literal=True))
570
+ def test_dataclass_type_literal(self, *, obj: Any) -> None:
571
+ result = deserialize(serialize(obj), objects={DataClassFutureTypeLiteral})
572
+ assert is_equal(result, obj)
573
+
574
+ @given(obj=make_objects(dataclass_type_literal_nullable=True))
575
+ def test_dataclass_type_literal_nullable(self, *, obj: Any) -> None:
576
+ result = deserialize(
577
+ serialize(obj), objects={DataClassFutureTypeLiteralNullable}
578
+ )
579
+ with assume_does_not_raise(IsEqualError):
580
+ assert is_equal(result, obj)
581
+
562
582
  @given(obj=builds(DataClassFutureNone))
563
583
  def test_dataclass_no_objects_error(self, *, obj: DataClassFutureNone) -> None:
564
584
  ser = serialize(obj)
@@ -12,6 +12,10 @@ from hypothesis.strategies import booleans, dates, floats, integers, sampled_fro
12
12
  from pytest import raises
13
13
 
14
14
  from tests.test_operator import TruthEnum
15
+ from tests.test_typing_funcs.with_future import (
16
+ TrueOrFalseFutureLit,
17
+ TrueOrFalseFutureTypeLit,
18
+ )
15
19
  from utilities.functions import ensure_path
16
20
  from utilities.hypothesis import (
17
21
  local_datetimes,
@@ -72,7 +76,7 @@ class TestParseText:
72
76
 
73
77
  @given(truth=sampled_from(["true", "false"]))
74
78
  def test_literal(self, *, truth: Literal["true", "false"]) -> None:
75
- result = parse_text(Literal["true", "false"], truth)
79
+ result = parse_text(TrueOrFalseFutureLit, truth)
76
80
  assert result == truth
77
81
 
78
82
  def test_nullable_int_none(self) -> None:
@@ -131,6 +135,11 @@ class TestParseText:
131
135
  result = parse_text(dt.timedelta, text)
132
136
  assert result == timedelta
133
137
 
138
+ @given(truth=sampled_from(["true", "false"]))
139
+ def test_type_literal(self, *, truth: Literal["true", "false"]) -> None:
140
+ result = parse_text(TrueOrFalseFutureTypeLit, truth)
141
+ assert result == truth
142
+
134
143
  @given(version=versions())
135
144
  def test_version(self, *, version: Version) -> None:
136
145
  text = str(version)