dycw-utilities 0.109.0__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.109.0 → dycw_utilities-0.109.1}/PKG-INFO +1 -1
  2. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/pyproject.toml +2 -2
  3. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_dataclasses.py +187 -95
  4. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_python_dotenv.py +5 -37
  5. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_typing_funcs/with_future.py +17 -5
  6. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/__init__.py +1 -1
  7. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/dataclasses.py +202 -104
  8. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/python_dotenv.py +24 -43
  9. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/.gitignore +0 -0
  10. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/LICENSE +0 -0
  11. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/README.md +0 -0
  12. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/__init__.py +0 -0
  13. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/conftest.py +0 -0
  14. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/modules/__init__.py +0 -0
  15. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/modules/package_missing/__init__.py +0 -0
  16. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/modules/package_missing/module.py +0 -0
  17. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/modules/package_with/__init__.py +0 -0
  18. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/modules/package_with/outer_1.py +0 -0
  19. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/modules/package_with/outer_2.py +0 -0
  20. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  21. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  22. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  23. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  24. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/modules/package_without/__init__.py +0 -0
  25. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/modules/package_without/module_1.py +0 -0
  26. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/modules/package_without/module_2.py +0 -0
  27. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/modules/standalone.py +0 -0
  28. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/modules/with_imports.py +0 -0
  29. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  30. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  31. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  32. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  33. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  34. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  35. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  36. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  37. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/scripts/__init__.py +0 -0
  38. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/scripts/test_async_service/__init__.py +0 -0
  39. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/scripts/test_async_service/__main__.py +0 -0
  40. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/scripts/test_async_service/run.sh +0 -0
  41. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/scripts/test_queue_processor/__init__.py +0 -0
  42. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/scripts/test_queue_processor/__main__.py +0 -0
  43. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/scripts/test_queue_processor/run.sh +0 -0
  44. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_altair.py +0 -0
  45. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_astor.py +0 -0
  46. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_asyncio.py +0 -0
  47. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_atomicwrites.py +0 -0
  48. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_atools.py +0 -0
  49. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_cachetools.py +0 -0
  50. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_click.py +0 -0
  51. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_concurrent.py +0 -0
  52. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_contextlib.py +0 -0
  53. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_contextvars.py +0 -0
  54. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_cryptography.py +0 -0
  55. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_cvxpy.py +0 -0
  56. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_datetime.py +0 -0
  57. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_enum.py +0 -0
  58. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_errors.py +0 -0
  59. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_eventkit.py +0 -0
  60. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_fastapi.py +0 -0
  61. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_fpdf2.py +0 -0
  62. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_functions.py +0 -0
  63. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_functools.py +0 -0
  64. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_getpass.py +0 -0
  65. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_git.py +0 -0
  66. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_hashlib.py +0 -0
  67. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_http.py +0 -0
  68. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_hypothesis.py +0 -0
  69. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_ipython.py +0 -0
  70. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_iterables.py +0 -0
  71. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_jupyter.py +0 -0
  72. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_logging.py +0 -0
  73. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_loguru.py +0 -0
  74. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_luigi.py +0 -0
  75. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_math.py +0 -0
  76. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_memory_profiler.py +0 -0
  77. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_modules.py +0 -0
  78. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_more_itertools.py +0 -0
  79. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_numpy.py +0 -0
  80. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_operator.py +0 -0
  81. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_optuna.py +0 -0
  82. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_orjson.py +0 -0
  83. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_os.py +0 -0
  84. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_parse.py +0 -0
  85. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_pathlib.py +0 -0
  86. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_period.py +0 -0
  87. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_pickle.py +0 -0
  88. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_platform.py +0 -0
  89. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_polars.py +0 -0
  90. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_pqdm.py +0 -0
  91. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_pydantic.py +0 -0
  92. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_pyinstrument.py +0 -0
  93. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_pyrsistent.py +0 -0
  94. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_pytest.py +0 -0
  95. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_pytest_regressions.py +0 -0
  96. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_random.py +0 -0
  97. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_re.py +0 -0
  98. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_redis.py +0 -0
  99. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_reprlib.py +0 -0
  100. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_rich.py +0 -0
  101. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_scipy.py +0 -0
  102. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_sentinel.py +0 -0
  103. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_shelve.py +0 -0
  104. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_slack_sdk.py +0 -0
  105. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_socket.py +0 -0
  106. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_sqlalchemy.py +0 -0
  107. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_sqlalchemy_polars.py +0 -0
  108. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_streamlit.py +0 -0
  109. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_sys.py +0 -0
  110. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_tempfile.py +0 -0
  111. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_tenacity.py +0 -0
  112. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_text.py +0 -0
  113. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_threading.py +0 -0
  114. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_timer.py +0 -0
  115. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_traceback.py +0 -0
  116. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/__init__.py +0 -0
  117. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/chain.py +0 -0
  118. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
  119. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
  120. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/error_bind.py +0 -0
  121. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/many.py +0 -0
  122. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/one.py +0 -0
  123. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/recursive.py +0 -0
  124. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
  125. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
  126. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/two.py +0 -0
  127. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_traceback_funcs/untraced.py +0 -0
  128. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_types.py +0 -0
  129. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_typing.py +0 -0
  130. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_typing_funcs/__init__.py +0 -0
  131. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_typing_funcs/no_future.py +0 -0
  132. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_tzdata.py +0 -0
  133. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_tzlocal.py +0 -0
  134. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_uuid.py +0 -0
  135. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_version.py +0 -0
  136. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_warnings.py +0 -0
  137. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_whenever.py +0 -0
  138. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_zipfile.py +0 -0
  139. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/tests/test_zoneinfo.py +0 -0
  140. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/altair.py +0 -0
  141. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/astor.py +0 -0
  142. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/asyncio.py +0 -0
  143. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/atomicwrites.py +0 -0
  144. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/atools.py +0 -0
  145. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/cachetools.py +0 -0
  146. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/click.py +0 -0
  147. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/concurrent.py +0 -0
  148. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/contextlib.py +0 -0
  149. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/contextvars.py +0 -0
  150. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/cryptography.py +0 -0
  151. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/cvxpy.py +0 -0
  152. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/datetime.py +0 -0
  153. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/enum.py +0 -0
  154. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/errors.py +0 -0
  155. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/eventkit.py +0 -0
  156. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/fastapi.py +0 -0
  157. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/fpdf2.py +0 -0
  158. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/functions.py +0 -0
  159. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/functools.py +0 -0
  160. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/getpass.py +0 -0
  161. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/git.py +0 -0
  162. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/hashlib.py +0 -0
  163. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/http.py +0 -0
  164. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/hypothesis.py +0 -0
  165. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/ipython.py +0 -0
  166. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/iterables.py +0 -0
  167. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/jupyter.py +0 -0
  168. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/logging.py +0 -0
  169. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/loguru.py +0 -0
  170. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/luigi.py +0 -0
  171. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/math.py +0 -0
  172. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/memory_profiler.py +0 -0
  173. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/modules.py +0 -0
  174. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/more_itertools.py +0 -0
  175. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/numpy.py +0 -0
  176. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/operator.py +0 -0
  177. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/optuna.py +0 -0
  178. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/orjson.py +0 -0
  179. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/os.py +0 -0
  180. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/parse.py +0 -0
  181. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/pathlib.py +0 -0
  182. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/period.py +0 -0
  183. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/pickle.py +0 -0
  184. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/platform.py +0 -0
  185. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/polars.py +0 -0
  186. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/pqdm.py +0 -0
  187. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/py.typed +0 -0
  188. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/pydantic.py +0 -0
  189. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/pyinstrument.py +0 -0
  190. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/pyrsistent.py +0 -0
  191. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/pytest.py +0 -0
  192. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/pytest_regressions.py +0 -0
  193. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/random.py +0 -0
  194. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/re.py +0 -0
  195. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/redis.py +0 -0
  196. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/reprlib.py +0 -0
  197. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/rich.py +0 -0
  198. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/scipy.py +0 -0
  199. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/sentinel.py +0 -0
  200. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/shelve.py +0 -0
  201. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/slack_sdk.py +0 -0
  202. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/socket.py +0 -0
  203. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/sqlalchemy.py +0 -0
  204. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/sqlalchemy_polars.py +0 -0
  205. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/streamlit.py +0 -0
  206. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/sys.py +0 -0
  207. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/tempfile.py +0 -0
  208. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/tenacity.py +0 -0
  209. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/text.py +0 -0
  210. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/threading.py +0 -0
  211. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/timer.py +0 -0
  212. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/traceback.py +0 -0
  213. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/types.py +0 -0
  214. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/typing.py +0 -0
  215. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/tzdata.py +0 -0
  216. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/tzlocal.py +0 -0
  217. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/uuid.py +0 -0
  218. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/version.py +0 -0
  219. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/warnings.py +0 -0
  220. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/whenever.py +0 -0
  221. {dycw_utilities-0.109.0 → dycw_utilities-0.109.1}/src/utilities/zipfile.py +0 -0
  222. {dycw_utilities-0.109.0 → 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.109.0
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.109.0"
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.109.0"
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
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,19 +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,
43
32
  TrueOrFalseFutureLit,
44
33
  TrueOrFalseFutureTypeLit,
45
34
  )
46
35
  from utilities.dataclasses import (
36
+ MappingToDataclassError,
37
+ OneFieldEmptyError,
38
+ OneFieldNonUniqueError,
39
+ StrMappingToFieldMappingError,
47
40
  YieldFieldsError,
48
- _MappingToDataclassCaseInsensitiveNonUniqueError,
49
- _MappingToDataclassEmptyError,
50
- _TextToDataClassGetFieldEmptyError,
51
- _TextToDataClassGetFieldNonUniqueError,
52
41
  _TextToDataClassParseValueError,
53
42
  _TextToDataClassSplitKeyValuePairError,
54
43
  _YieldFieldsClass,
@@ -56,12 +45,13 @@ from utilities.dataclasses import (
56
45
  dataclass_repr,
57
46
  dataclass_to_dict,
58
47
  mapping_to_dataclass,
48
+ one_field,
59
49
  replace_non_sentinel,
50
+ str_mapping_to_field_mapping,
60
51
  text_to_dataclass,
61
52
  yield_fields,
62
53
  )
63
54
  from utilities.functions import get_class_name
64
- from utilities.hypothesis import paths, text_ascii
65
55
  from utilities.iterables import one
66
56
  from utilities.orjson import OrjsonLogRecord
67
57
  from utilities.polars import are_frames_equal
@@ -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:
324
303
  with raises(
325
- _MappingToDataclassEmptyError, match=r"Mapping .* does not contain 'int_'"
304
+ MappingToDataclassError,
305
+ match="Unable to construct 'DataClassFutureInt'; missing values for 'int_'",
326
306
  ):
327
- _ = mapping_to_dataclass(
328
- DataClassFutureInt, {"INT_": value}, case_sensitive=True
329
- )
307
+ _ = mapping_to_dataclass(DataClassFutureInt, {})
308
+
330
309
 
331
- @given(value=integers())
332
- def test_error_case_insensitive_empty_error(self, *, value: int) -> None:
310
+ class TestOneField:
311
+ def test_error_exact_match_case_insensitive_empty_error(self) -> None:
333
312
  with raises(
334
- _MappingToDataclassEmptyError,
335
- match=r"Mapping .* does not contain 'int_' \(modulo case\)",
313
+ OneFieldEmptyError,
314
+ match=r"Dataclass 'DataClassFutureInt' does not contain a field 'invalid' \(modulo case\)",
336
315
  ):
337
- _ = mapping_to_dataclass(DataClassFutureInt, {"other": value})
316
+ _ = one_field(DataClassFutureInt, "invalid")
338
317
 
339
- @given(value1=integers(), value2=integers())
340
- def test_error_case_insensitive_non_unique_error(
341
- self, *, value1: int, value2: int
342
- ) -> None:
318
+ def test_error_exact_match_case_insensitive_non_unique_error(self) -> None:
343
319
  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
- ),
320
+ OneFieldNonUniqueError,
321
+ match=r"Dataclass 'DataClassFutureIntLowerAndUpper' must contain field 'int_' exactly once \(modulo case\); got 'int_', 'INT_' and perhaps more",
322
+ ):
323
+ _ = one_field(DataClassFutureIntLowerAndUpper, "int_")
324
+
325
+ def test_error_head_case_insensitive_empty_error(self) -> None:
326
+ with raises(
327
+ OneFieldEmptyError,
328
+ match=r"Dataclass 'DataClassFutureInt' does not contain any field starting with 'invalid' \(modulo case\)",
329
+ ):
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_'",
349
352
  ):
350
- _ = mapping_to_dataclass(
351
- DataClassFutureInt, {"int_": value1, "INT_": value2}
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,
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import re
4
4
  from dataclasses import dataclass
5
5
  from re import DOTALL
6
- from typing import TYPE_CHECKING, Literal
6
+ from typing import TYPE_CHECKING
7
7
 
8
8
  from hypothesis import given
9
9
  from hypothesis.strategies import DataObject, booleans, data, integers, sampled_from
@@ -14,9 +14,8 @@ from utilities.hypothesis import git_repos, settings_with_reduced_examples, text
14
14
  from utilities.os import temp_environ
15
15
  from utilities.python_dotenv import (
16
16
  _LoadSettingsDuplicateKeysError,
17
- _LoadSettingsEmptyError,
18
17
  _LoadSettingsFileNotFoundError,
19
- _LoadSettingsParseTextError,
18
+ _LoadSettingsMissingKeysError,
20
19
  load_settings,
21
20
  )
22
21
 
@@ -87,22 +86,6 @@ class TestLoadSettings:
87
86
  expected = Settings(key=value)
88
87
  assert settings == expected
89
88
 
90
- @given(root=git_repos(), value=sampled_from(["true", "false"]))
91
- @settings_with_reduced_examples()
92
- def test_literal_value(
93
- self, *, root: Path, value: Literal["true", "false"]
94
- ) -> None:
95
- @dataclass(kw_only=True, slots=True)
96
- class Settings:
97
- key: Literal["true", "false"]
98
-
99
- with root.joinpath(".env").open(mode="w") as fh:
100
- _ = fh.write(f"key = {value}\n")
101
-
102
- settings = load_settings(Settings, cwd=root)
103
- expected = Settings(key=value)
104
- assert settings == expected
105
-
106
89
  @given(root=git_repos())
107
90
  @settings_with_reduced_examples()
108
91
  def test_error_file_not_found(self, *, root: Path) -> None:
@@ -135,7 +118,7 @@ class TestLoadSettings:
135
118
 
136
119
  @given(root=git_repos())
137
120
  @settings_with_reduced_examples()
138
- def test_error_field_missing(self, *, root: Path) -> None:
121
+ def test_error_missing_keys(self, *, root: Path) -> None:
139
122
  @dataclass(kw_only=True, slots=True)
140
123
  class Settings:
141
124
  key: str
@@ -143,22 +126,7 @@ class TestLoadSettings:
143
126
  root.joinpath(".env").touch()
144
127
 
145
128
  with raises(
146
- _LoadSettingsEmptyError, match=r"Field 'key' must exist \(modulo case\)"
147
- ):
148
- _ = load_settings(Settings, cwd=root)
149
-
150
- @given(root=git_repos())
151
- @settings_with_reduced_examples()
152
- def test_error_parse_text(self, *, root: Path) -> None:
153
- @dataclass(kw_only=True, slots=True)
154
- class Settings:
155
- key: int
156
-
157
- with root.joinpath(".env").open(mode="w") as fh:
158
- _ = fh.write("key = '...'\n")
159
-
160
- with raises(
161
- _LoadSettingsParseTextError,
162
- match=r"Unable to parse field 'key' of type <class 'int'>; got '...'",
129
+ _LoadSettingsMissingKeysError,
130
+ match=r"Unable to load '.*'; missing value\(s\) for 'key'",
163
131
  ):
164
132
  _ = load_settings(Settings, cwd=root)
@@ -33,11 +33,6 @@ class DataClassFutureDate:
33
33
  date: dt.date
34
34
 
35
35
 
36
- @dataclass(order=True, unsafe_hash=True, kw_only=True)
37
- class DataClassFutureInt:
38
- int_: int
39
-
40
-
41
36
  @dataclass(order=True, unsafe_hash=True, kw_only=True)
42
37
  class DataClassFutureDefaultInInitParent:
43
38
  int_: int
@@ -49,6 +44,11 @@ class DataClassFutureDefaultInInitChild(DataClassFutureDefaultInInitParent):
49
44
  DataClassFutureDefaultInInitParent.__init__(self, int_=0)
50
45
 
51
46
 
47
+ @dataclass(order=True, unsafe_hash=True, kw_only=True)
48
+ class DataClassFutureInt:
49
+ int_: int
50
+
51
+
52
52
  @dataclass(order=True, unsafe_hash=True, kw_only=True)
53
53
  class DataClassFutureIntDefault:
54
54
  int_: int = 0
@@ -59,6 +59,18 @@ class DataClassFutureIntNullable:
59
59
  int_: int | None = None
60
60
 
61
61
 
62
+ @dataclass(order=True, unsafe_hash=True, kw_only=True)
63
+ class DataClassFutureIntLowerAndUpper:
64
+ int_: int
65
+ INT_: int
66
+
67
+
68
+ @dataclass(order=True, unsafe_hash=True, kw_only=True)
69
+ class DataClassFutureIntOneAndTwo:
70
+ int1: int
71
+ int2: int
72
+
73
+
62
74
  @dataclass(order=True, unsafe_hash=True, kw_only=True)
63
75
  class DataClassFutureListInts:
64
76
  ints: list[int]
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.109.0"
3
+ __version__ = "0.109.1"