dycw-utilities 0.163.1__tar.gz → 0.164.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/PKG-INFO +1 -1
  2. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/pyproject.toml +2 -2
  3. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_functions.py +0 -233
  4. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_iterables.py +1 -7
  5. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_orjson.py +1 -2
  6. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_typing.py +228 -10
  7. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_typing_funcs/with_future.py +6 -1
  8. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/__init__.py +1 -1
  9. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/dataclasses.py +2 -6
  10. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/functions.py +5 -266
  11. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/iterables.py +1 -16
  12. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/operator.py +1 -1
  13. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/orjson.py +2 -1
  14. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/polars.py +4 -6
  15. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/polars_ols.py +1 -1
  16. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/redis.py +2 -11
  17. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/sqlalchemy.py +7 -9
  18. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/typing.py +418 -14
  19. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/.gitignore +0 -0
  20. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/LICENSE +0 -0
  21. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/README.md +0 -0
  22. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/__init__.py +0 -0
  23. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/conftest.py +0 -0
  24. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/modules/__init__.py +0 -0
  25. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/modules/package_missing/__init__.py +0 -0
  26. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/modules/package_missing/module.py +0 -0
  27. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/modules/package_with/__init__.py +0 -0
  28. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/modules/package_with/outer_1.py +0 -0
  29. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/modules/package_with/outer_2.py +0 -0
  30. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  31. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  32. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  33. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  34. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/modules/package_without/__init__.py +0 -0
  35. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/modules/package_without/module_1.py +0 -0
  36. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/modules/package_without/module_2.py +0 -0
  37. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/modules/standalone.py +0 -0
  38. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/modules/with_imports.py +0 -0
  39. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  40. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  41. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  42. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  43. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  44. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  45. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  46. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  47. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_aeventkit.py +0 -0
  48. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_altair.py +0 -0
  49. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_asyncio.py +0 -0
  50. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_atomicwrites.py +0 -0
  51. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_atools.py +0 -0
  52. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_cachetools.py +0 -0
  53. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_click.py +0 -0
  54. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_concurrent.py +0 -0
  55. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_contextlib.py +0 -0
  56. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_contextvars.py +0 -0
  57. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_cryptography.py +0 -0
  58. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_cvxpy.py +0 -0
  59. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_dataclasses.py +0 -0
  60. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_enum.py +0 -0
  61. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_errors.py +0 -0
  62. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_fastapi.py +0 -0
  63. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_fpdf2.py +0 -0
  64. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_functools.py +0 -0
  65. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_getpass.py +0 -0
  66. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_gzip.py +0 -0
  67. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_hashlib.py +0 -0
  68. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_http.py +0 -0
  69. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_hypothesis.py +0 -0
  70. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_importlib.py +0 -0
  71. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_inflect.py +0 -0
  72. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_ipython.py +0 -0
  73. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_json.py +0 -0
  74. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_jupyter.py +0 -0
  75. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_libcst.py +0 -0
  76. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_lightweight_charts.py +0 -0
  77. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_logging.py +0 -0
  78. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_math.py +0 -0
  79. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_memory_profiler.py +0 -0
  80. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_modules.py +0 -0
  81. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_more_itertools.py +0 -0
  82. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_numpy.py +0 -0
  83. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_objects/__init__.py +0 -0
  84. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_objects/objects.py +0 -0
  85. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_operator.py +0 -0
  86. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_optuna.py +0 -0
  87. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_os.py +0 -0
  88. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_parse.py +0 -0
  89. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_pathlib.py +0 -0
  90. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_pickle.py +0 -0
  91. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_platform.py +0 -0
  92. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_polars.py +0 -0
  93. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_polars_ols.py +0 -0
  94. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_postgres.py +0 -0
  95. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_pottery.py +0 -0
  96. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_pqdm.py +0 -0
  97. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_psutil.py +0 -0
  98. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_pyinstrument.py +0 -0
  99. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_pytest.py +0 -0
  100. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_pytest_randomly.py +0 -0
  101. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_pytest_regressions.py +0 -0
  102. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_random.py +0 -0
  103. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_re.py +0 -0
  104. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_redis.py +0 -0
  105. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_reprlib.py +0 -0
  106. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_scipy.py +0 -0
  107. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_sentinel.py +0 -0
  108. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_shelve.py +0 -0
  109. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_slack_sdk.py +0 -0
  110. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_socket.py +0 -0
  111. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_sqlalchemy.py +0 -0
  112. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_sqlalchemy_polars.py +0 -0
  113. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_statsmodels.py +0 -0
  114. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_string.py +0 -0
  115. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_tempfile.py +0 -0
  116. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_testbook.py +0 -0
  117. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_text.py +0 -0
  118. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_threading.py +0 -0
  119. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_timer.py +0 -0
  120. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_traceback.py +0 -0
  121. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_typed_settings.py +0 -0
  122. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_types.py +0 -0
  123. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_typing_funcs/__init__.py +0 -0
  124. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_typing_funcs/no_future.py +0 -0
  125. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_tzdata.py +0 -0
  126. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_tzlocal.py +0 -0
  127. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_uuid.py +0 -0
  128. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_version.py +0 -0
  129. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_warnings.py +0 -0
  130. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_whenever.py +0 -0
  131. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_zipfile.py +0 -0
  132. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/tests/test_zoneinfo.py +0 -0
  133. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/aeventkit.py +0 -0
  134. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/altair.py +0 -0
  135. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/asyncio.py +0 -0
  136. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/atomicwrites.py +0 -0
  137. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/atools.py +0 -0
  138. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/cachetools.py +0 -0
  139. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/click.py +0 -0
  140. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/concurrent.py +0 -0
  141. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/contextlib.py +0 -0
  142. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/contextvars.py +0 -0
  143. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/cryptography.py +0 -0
  144. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/cvxpy.py +0 -0
  145. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/enum.py +0 -0
  146. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/errors.py +0 -0
  147. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/fastapi.py +0 -0
  148. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/fpdf2.py +0 -0
  149. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/functools.py +0 -0
  150. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/getpass.py +0 -0
  151. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/gzip.py +0 -0
  152. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/hashlib.py +0 -0
  153. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/http.py +0 -0
  154. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/hypothesis.py +0 -0
  155. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/importlib.py +0 -0
  156. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/inflect.py +0 -0
  157. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/ipython.py +0 -0
  158. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/json.py +0 -0
  159. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/jupyter.py +0 -0
  160. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/libcst.py +0 -0
  161. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/lightweight_charts.py +0 -0
  162. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/logging.py +0 -0
  163. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/math.py +0 -0
  164. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/memory_profiler.py +0 -0
  165. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/modules.py +0 -0
  166. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/more_itertools.py +0 -0
  167. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/numpy.py +0 -0
  168. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/optuna.py +0 -0
  169. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/os.py +0 -0
  170. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/parse.py +0 -0
  171. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/pathlib.py +0 -0
  172. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/pickle.py +0 -0
  173. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/platform.py +0 -0
  174. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/postgres.py +0 -0
  175. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/pottery.py +0 -0
  176. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/pqdm.py +0 -0
  177. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/psutil.py +0 -0
  178. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/py.typed +0 -0
  179. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/pyinstrument.py +0 -0
  180. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/pytest.py +0 -0
  181. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/pytest_plugins/__init__.py +0 -0
  182. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/pytest_plugins/pytest_randomly.py +0 -0
  183. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/pytest_plugins/pytest_regressions.py +0 -0
  184. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/pytest_regressions.py +0 -0
  185. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/random.py +0 -0
  186. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/re.py +0 -0
  187. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/reprlib.py +0 -0
  188. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/scipy.py +0 -0
  189. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/sentinel.py +0 -0
  190. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/shelve.py +0 -0
  191. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/slack_sdk.py +0 -0
  192. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/socket.py +0 -0
  193. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/sqlalchemy_polars.py +0 -0
  194. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/statsmodels.py +0 -0
  195. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/string.py +0 -0
  196. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/tempfile.py +0 -0
  197. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/testbook.py +0 -0
  198. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/text.py +0 -0
  199. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/threading.py +0 -0
  200. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/timer.py +0 -0
  201. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/traceback.py +0 -0
  202. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/typed_settings.py +0 -0
  203. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/types.py +0 -0
  204. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/tzdata.py +0 -0
  205. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/tzlocal.py +0 -0
  206. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/uuid.py +0 -0
  207. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/version.py +0 -0
  208. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/warnings.py +0 -0
  209. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/whenever.py +0 -0
  210. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/zipfile.py +0 -0
  211. {dycw_utilities-0.163.1 → dycw_utilities-0.164.0}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.163.1
3
+ Version: 0.164.0
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -232,7 +232,7 @@ dependencies = [
232
232
  name = "dycw-utilities"
233
233
  readme = "README.md"
234
234
  requires-python = ">= 3.12"
235
- version = "0.163.1"
235
+ version = "0.164.0"
236
236
 
237
237
  [project.entry-points.pytest11]
238
238
  pytest-randomly = "utilities.pytest_plugins.pytest_randomly"
@@ -265,7 +265,7 @@ test = [
265
265
  # bump-my-version
266
266
  [tool.bumpversion]
267
267
  allow_dirty = true
268
- current_version = "0.163.1"
268
+ current_version = "0.164.0"
269
269
 
270
270
  [[tool.bumpversion.files]]
271
271
  filename = "src/utilities/__init__.py"
@@ -33,15 +33,12 @@ from utilities.functions import (
33
33
  EnsureClassError,
34
34
  EnsureDateError,
35
35
  EnsureFloatError,
36
- EnsureHashableError,
37
36
  EnsureIntError,
38
37
  EnsureMemberError,
39
38
  EnsureNotNoneError,
40
39
  EnsureNumberError,
41
40
  EnsurePathError,
42
41
  EnsurePlainDateTimeError,
43
- EnsureSizedError,
44
- EnsureSizedNotStrError,
45
42
  EnsureStrError,
46
43
  EnsureTimeDeltaError,
47
44
  EnsureTimeError,
@@ -54,15 +51,12 @@ from utilities.functions import (
54
51
  ensure_class,
55
52
  ensure_date,
56
53
  ensure_float,
57
- ensure_hashable,
58
54
  ensure_int,
59
55
  ensure_member,
60
56
  ensure_not_none,
61
57
  ensure_number,
62
58
  ensure_path,
63
59
  ensure_plain_date_time,
64
- ensure_sized,
65
- ensure_sized_not_str,
66
60
  ensure_str,
67
61
  ensure_time,
68
62
  ensure_time_delta,
@@ -73,20 +67,8 @@ from utilities.functions import (
73
67
  get_func_name,
74
68
  get_func_qualname,
75
69
  identity,
76
- is_dataclass_class,
77
- is_dataclass_instance,
78
- is_hashable,
79
- is_iterable_of,
80
70
  is_none,
81
71
  is_not_none,
82
- is_sequence_of,
83
- is_sequence_of_tuple_or_str_mapping,
84
- is_sized,
85
- is_sized_not_str,
86
- is_string_mapping,
87
- is_tuple,
88
- is_tuple_or_str_mapping,
89
- make_isinstance,
90
72
  map_object,
91
73
  max_nullable,
92
74
  min_nullable,
@@ -232,18 +214,6 @@ class TestEnsureFloat:
232
214
  _ = ensure_float(sentinel, nullable=nullable)
233
215
 
234
216
 
235
- class TestEnsureHashable:
236
- @given(obj=sampled_from([0, (1, 2, 3)]))
237
- def test_main(self, *, obj: Any) -> None:
238
- assert ensure_hashable(obj) == obj
239
-
240
- def test_error(self) -> None:
241
- with raises(
242
- EnsureHashableError, match=r"Object '.*' of type '.*' must be hashable"
243
- ):
244
- _ = ensure_hashable([1, 2, 3])
245
-
246
-
247
217
  class TestEnsureInt:
248
218
  @given(case=sampled_from([(0, False), (0, True), (None, True)]))
249
219
  def test_main(self, *, case: tuple[int | None, bool]) -> None:
@@ -363,30 +333,6 @@ class TestEnsurePlainDateTime:
363
333
  _ = ensure_plain_date_time(sentinel, nullable=nullable)
364
334
 
365
335
 
366
- class TestEnsureSized:
367
- @given(obj=sampled_from([[], (), ""]))
368
- def test_main(self, *, obj: Any) -> None:
369
- _ = ensure_sized(obj)
370
-
371
- def test_error(self) -> None:
372
- with raises(EnsureSizedError, match=r"Object '.*' of type '.*' must be sized"):
373
- _ = ensure_sized(None)
374
-
375
-
376
- class TestEnsureSizedNotStr:
377
- @given(obj=sampled_from([[], ()]))
378
- def test_main(self, *, obj: Any) -> None:
379
- _ = ensure_sized_not_str(obj)
380
-
381
- @given(obj=sampled_from([None, '""']))
382
- def test_error(self, *, obj: Any) -> None:
383
- with raises(
384
- EnsureSizedNotStrError,
385
- match="Object '.*' of type '.*' must be sized and not a string",
386
- ):
387
- _ = ensure_sized_not_str(obj)
388
-
389
-
390
336
  class TestEnsureStr:
391
337
  @given(case=sampled_from([("", False), ("", True), (None, True)]))
392
338
  def test_main(self, *, case: tuple[bool | None, bool]) -> None:
@@ -610,72 +556,6 @@ class TestIdentity:
610
556
  assert identity(x) == x
611
557
 
612
558
 
613
- class TestIsDataClassClass:
614
- def test_main(self) -> None:
615
- @dataclass(kw_only=True, slots=True)
616
- class Example:
617
- x: None = None
618
-
619
- assert is_dataclass_class(Example)
620
- assert not is_dataclass_class(Example())
621
-
622
- @given(obj=sampled_from([None, type(None)]))
623
- def test_others(self, *, obj: Any) -> None:
624
- assert not is_dataclass_class(obj)
625
-
626
-
627
- class TestIsDataClassInstance:
628
- def test_main(self) -> None:
629
- @dataclass(kw_only=True, slots=True)
630
- class Example:
631
- x: None = None
632
-
633
- assert not is_dataclass_instance(Example)
634
- assert is_dataclass_instance(Example())
635
-
636
- @given(obj=sampled_from([None, type(None)]))
637
- def test_others(self, *, obj: Any) -> None:
638
- assert not is_dataclass_instance(obj)
639
-
640
-
641
- class TestIsHashable:
642
- @given(case=sampled_from([(0, True), ((1, 2, 3), True), ([1, 2, 3], False)]))
643
- def test_main(self, *, case: tuple[Any, bool]) -> None:
644
- obj, expected = case
645
- assert is_hashable(obj) is expected
646
-
647
-
648
- class TestIsIterableOf:
649
- @given(
650
- case=sampled_from([
651
- ([0], True),
652
- (["0"], False),
653
- ({0}, True),
654
- ({0: 0}, True),
655
- (None, False),
656
- ([None], False),
657
- ])
658
- )
659
- def test_single(self, *, case: tuple[Any, bool]) -> None:
660
- obj, expected = case
661
- result = is_iterable_of(obj, int)
662
- assert result is expected
663
-
664
- @given(
665
- case=sampled_from([
666
- ([0], True),
667
- (["0"], True),
668
- ([0, "0"], True),
669
- (None, False),
670
- ([None], False),
671
- ])
672
- )
673
- def test_multiple(self, *, case: tuple[Any, bool]) -> None:
674
- obj, expected = case
675
- result = is_iterable_of(obj, (int, str))
676
- assert result is expected
677
-
678
-
679
559
  class TestIsNoneAndIsNotNone:
680
560
  @given(
681
561
  case=sampled_from([
@@ -691,119 +571,6 @@ class TestIsNoneAndIsNotNone:
691
571
  assert result is expected
692
572
 
693
573
 
694
- class TestIsSequenceOf:
695
- @given(
696
- case=sampled_from([
697
- ([0], True),
698
- (["0"], False),
699
- ({0}, False),
700
- ({0: 0}, False),
701
- (None, False),
702
- ([None], False),
703
- ])
704
- )
705
- def test_single(self, *, case: tuple[Any, bool]) -> None:
706
- obj, expected = case
707
- result = is_sequence_of(obj, int)
708
- assert result is expected
709
-
710
- @given(
711
- case=sampled_from([
712
- ([0], True),
713
- (["0"], True),
714
- ([0, "0"], True),
715
- (None, False),
716
- ([None], False),
717
- ])
718
- )
719
- def test_multiple(self, *, case: tuple[Any, bool]) -> None:
720
- obj, expected = case
721
- result = is_sequence_of(obj, (int, str))
722
- assert result is expected
723
-
724
-
725
- class TestIsSequenceOfTupleOrStrgMapping:
726
- @given(
727
- case=sampled_from([
728
- (None, False),
729
- ([(1, 2, 3)], True),
730
- ([{"a": 1, "b": 2, "c": 3}], True),
731
- ([(1, 2, 3), {"a": 1, "b": 2, "c": 3}], True),
732
- ])
733
- )
734
- def test_main(self, *, case: tuple[Any, bool]) -> None:
735
- obj, expected = case
736
- result = is_sequence_of_tuple_or_str_mapping(obj)
737
- assert result is expected
738
-
739
-
740
- class TestIsSized:
741
- @given(case=sampled_from([(None, False), ([], True), ((), True), ("", True)]))
742
- def test_main(self, *, case: tuple[Any, bool]) -> None:
743
- obj, expected = case
744
- assert is_sized(obj) is expected
745
-
746
-
747
- class TestIsSizedNotStr:
748
- @given(case=sampled_from([(None, False), ([], True), ((), True), ("", False)]))
749
- def test_main(self, *, case: tuple[Any, bool]) -> None:
750
- obj, expected = case
751
- assert is_sized_not_str(obj) is expected
752
-
753
-
754
- class TestIsStringMapping:
755
- @given(
756
- case=sampled_from([
757
- (None, False),
758
- ({"a": 1, "b": 2, "c": 3}, True),
759
- ({1: "a", 2: "b", 3: "c"}, False),
760
- ])
761
- )
762
- def test_main(self, *, case: tuple[Any, bool]) -> None:
763
- obj, expected = case
764
- result = is_string_mapping(obj)
765
- assert result is expected
766
-
767
-
768
- class TestIsTuple:
769
- @given(case=sampled_from([(None, False), ((1, 2, 3), True), ([1, 2, 3], False)]))
770
- def test_main(self, *, case: tuple[Any, bool]) -> None:
771
- obj, expected = case
772
- result = is_tuple(obj)
773
- assert result is expected
774
-
775
-
776
- class TestIsTupleOrStringMapping:
777
- @given(
778
- case=sampled_from([
779
- (None, False),
780
- ((1, 2, 3), True),
781
- ({"a": 1, "b": 2, "c": 3}, True),
782
- ({1: "a", 2: "b", 3: "c"}, False),
783
- ])
784
- )
785
- def test_main(self, *, case: tuple[Any, bool]) -> None:
786
- obj, expected = case
787
- result = is_tuple_or_str_mapping(obj)
788
- assert result is expected
789
-
790
-
791
- class TestMakeIsInstance:
792
- @given(case=sampled_from([(True, True), (False, True), (None, False)]))
793
- def test_single(self, *, case: tuple[bool | None, bool]) -> None:
794
- obj, expected = case
795
- func = make_isinstance(bool)
796
- result = func(obj)
797
- assert result is expected
798
-
799
- @given(case=sampled_from([(0, True), ("0", True), (None, False)]))
800
- def test_multiple(self, *, case: tuple[bool | None, bool]) -> None:
801
- obj, expected = case
802
- func = make_isinstance((int, str))
803
- result = func(obj)
804
- assert result is expected
805
-
806
-
807
574
  class TestMapObject:
808
575
  @given(x=integers())
809
576
  def test_int(self, *, x: int) -> None:
@@ -32,7 +32,6 @@ from hypothesis.strategies import (
32
32
  from pytest import mark, param, raises
33
33
 
34
34
  from tests.test_objects.objects import objects
35
- from utilities.functions import is_sequence_of
36
35
  from utilities.hypothesis import pairs, sentinels, sets_fixed_length, text_ascii
37
36
  from utilities.iterables import (
38
37
  CheckBijectionError,
@@ -88,7 +87,6 @@ from utilities.iterables import (
88
87
  check_unique_modulo_case,
89
88
  chunked,
90
89
  cmp_nullable,
91
- ensure_hashables,
92
90
  ensure_iterable,
93
91
  ensure_iterable_not_str,
94
92
  enumerate_with_edge,
@@ -119,6 +117,7 @@ from utilities.iterables import (
119
117
  unique_everseen,
120
118
  )
121
119
  from utilities.sentinel import Sentinel, sentinel
120
+ from utilities.typing import is_sequence_of
122
121
 
123
122
  if TYPE_CHECKING:
124
123
  from collections.abc import Iterable, Iterator, Mapping, Sequence
@@ -609,11 +608,6 @@ class TestCmpNullable:
609
608
  assert result == expected
610
609
 
611
610
 
612
- class TestEnsureHashables:
613
- def test_main(self) -> None:
614
- assert ensure_hashables(1, 2, a=3, b=4) == ([1, 2], {"a": 3, "b": 4})
615
-
616
-
617
611
  class TestEnsureIterable:
618
612
  @mark.parametrize("obj", [param([]), param(()), param("")])
619
613
  def test_main(self, *, obj: Any) -> None:
@@ -50,7 +50,6 @@ from tests.test_typing_funcs.with_future import (
50
50
  DataClassFutureTypeLiteral,
51
51
  DataClassFutureTypeLiteralNullable,
52
52
  )
53
- from utilities.functions import is_sequence_of
54
53
  from utilities.hypothesis import (
55
54
  date_periods,
56
55
  dates,
@@ -86,7 +85,7 @@ from utilities.orjson import (
86
85
  from utilities.polars import check_polars_dataframe, zoned_date_time_dtype
87
86
  from utilities.sentinel import Sentinel, sentinel
88
87
  from utilities.types import LogLevel, MaybeIterable, PathLike
89
- from utilities.typing import get_args
88
+ from utilities.typing import get_args, is_sequence_of
90
89
  from utilities.tzlocal import LOCAL_TIME_ZONE
91
90
  from utilities.whenever import (
92
91
  HOUR,
@@ -6,7 +6,15 @@ from dataclasses import dataclass
6
6
  from pathlib import Path
7
7
  from random import Random
8
8
  from types import NoneType
9
- from typing import TYPE_CHECKING, Any, Final, Literal, NamedTuple
9
+ from typing import (
10
+ TYPE_CHECKING,
11
+ Any,
12
+ Final,
13
+ Literal,
14
+ NamedTuple,
15
+ TypedDict,
16
+ assert_never,
17
+ )
10
18
  from uuid import UUID
11
19
 
12
20
  import whenever
@@ -71,6 +79,7 @@ from tests.test_typing_funcs.with_future import (
71
79
  DataClassFutureZonedDateTimePeriod,
72
80
  TrueOrFalseFutureLit,
73
81
  TrueOrFalseFutureTypeLit,
82
+ TypedDictFutureIntFloat,
74
83
  )
75
84
  from utilities.hypothesis import text_ascii
76
85
  from utilities.sentinel import Sentinel
@@ -87,20 +96,29 @@ from utilities.typing import (
87
96
  get_type_classes,
88
97
  get_type_hints,
89
98
  get_union_type_classes,
99
+ is_dataclass_class,
100
+ is_dataclass_instance,
90
101
  is_dict_type,
91
102
  is_frozenset_type,
92
103
  is_instance_gen,
104
+ is_iterable_of,
93
105
  is_list_type,
94
106
  is_literal_type,
95
107
  is_mapping_type,
96
108
  is_namedtuple_class,
97
109
  is_namedtuple_instance,
98
110
  is_optional_type,
111
+ is_sequence_of,
112
+ is_sequence_of_tuple_or_str_mapping,
99
113
  is_sequence_type,
100
114
  is_set_type,
115
+ is_string_mapping,
101
116
  is_subclass_gen,
117
+ is_tuple,
118
+ is_tuple_or_str_mapping,
102
119
  is_tuple_type,
103
120
  is_union_type,
121
+ make_isinstance,
104
122
  )
105
123
  from utilities.whenever import DatePeriod, TimePeriod, ZonedDateTimePeriod
106
124
 
@@ -149,16 +167,16 @@ type _TruthAndTrueAndFalse = _True | _TrueAndFalse
149
167
 
150
168
 
151
169
  class TestGetLiteralElements:
152
- @given(
153
- case=sampled_from([
154
- (_PlusOrMinusOneLit, [1, -1]),
155
- (_TruthLit, ["true", "false"]),
156
- (_TrueAndFalse, ["true", "false"]),
157
- (_TruthAndTrueAndFalse, ["true", "false"]),
158
- ])
170
+ @mark.parametrize(
171
+ ("obj", "expected"),
172
+ [
173
+ param(_PlusOrMinusOneLit, [1, -1]),
174
+ param(_TruthLit, ["true", "false"]),
175
+ param(_TrueAndFalse, ["true", "false"]),
176
+ param(_TruthAndTrueAndFalse, ["true", "false"]),
177
+ ],
159
178
  )
160
- def test_main(self, *, case: tuple[Any, list[Any]]) -> None:
161
- obj, expected = case
179
+ def test_main(self, *, obj: Any, expected: list[Any]) -> None:
162
180
  result = get_literal_elements(obj)
163
181
  assert result == expected
164
182
 
@@ -477,6 +495,15 @@ class TestGetTypeHints:
477
495
  expected = {"truth": TrueOrFalseFutureTypeLit}
478
496
  assert hints == expected
479
497
 
498
+ def test_typed_dict(self) -> None:
499
+ class Example(TypedDict):
500
+ int_: int
501
+ float_: float
502
+
503
+ hints = get_type_hints(Example)
504
+ expected = {"int_": int, "float_": float}
505
+ assert hints == expected
506
+
480
507
  @given(data=data())
481
508
  def test_uuid(self, *, data: DataObject) -> None:
482
509
  @dataclass(kw_only=True, slots=True)
@@ -647,6 +674,34 @@ class TestIsAnnotationOfType:
647
674
  assert func(obj) is expected
648
675
 
649
676
 
677
+ class TestIsDataClassClass:
678
+ def test_main(self) -> None:
679
+ @dataclass(kw_only=True, slots=True)
680
+ class Example:
681
+ x: None = None
682
+
683
+ assert is_dataclass_class(Example)
684
+ assert not is_dataclass_class(Example())
685
+
686
+ @mark.parametrize("obj", [param(None), param(type(None))])
687
+ def test_others(self, *, obj: Any) -> None:
688
+ assert not is_dataclass_class(obj)
689
+
690
+
691
+ class TestIsDataClassInstance:
692
+ def test_main(self) -> None:
693
+ @dataclass(kw_only=True, slots=True)
694
+ class Example:
695
+ x: None = None
696
+
697
+ assert not is_dataclass_instance(Example)
698
+ assert is_dataclass_instance(Example())
699
+
700
+ @mark.parametrize("obj", [param(None), param(type(None))])
701
+ def test_others(self, *, obj: Any) -> None:
702
+ assert not is_dataclass_instance(obj)
703
+
704
+
650
705
  class TestIsInstanceGen:
651
706
  @given(data=data())
652
707
  @mark.parametrize(
@@ -739,6 +794,8 @@ class TestIsInstanceGen:
739
794
  sets(strategy, min_size=10 if min_size is None else min_size)
740
795
  )
741
796
  assert not all(is_instance_gen(v, type_) for v in values)
797
+ case never:
798
+ assert_never(never)
742
799
 
743
800
  @given(bool_=booleans())
744
801
  def test_bool_value_vs_custom_int(self, *, bool_: bool) -> None:
@@ -753,6 +810,24 @@ class TestIsInstanceGen:
753
810
  assert not is_instance_gen(int_, MyInt)
754
811
  assert is_instance_gen(MyInt(int_), MyInt)
755
812
 
813
+ @mark.parametrize(
814
+ ("obj", "expected"),
815
+ [
816
+ param(None, False),
817
+ param({}, False),
818
+ param({None: False}, False),
819
+ param({"int_": None}, False),
820
+ param({"int_": None, "float_": None}, False),
821
+ param({"int_": 0, "float_": None}, False),
822
+ param({"int_": None, "float_": 0.0}, False),
823
+ param({"int_": 0, "float_": 0.0}, True),
824
+ param({"int_": 0, "float_": 0.0, "extra": None}, True),
825
+ ],
826
+ )
827
+ def test_typed_dict(self, *, obj: Any, expected: bool) -> None:
828
+ result = is_instance_gen(obj, TypedDictFutureIntFloat)
829
+ assert result is expected
830
+
756
831
  def test_error(self) -> None:
757
832
  with raises(
758
833
  IsInstanceGenError,
@@ -761,6 +836,37 @@ class TestIsInstanceGen:
761
836
  _ = is_instance_gen(None, Final)
762
837
 
763
838
 
839
+ class TestIsIterableOf:
840
+ @mark.parametrize(
841
+ ("obj", "expected"),
842
+ [
843
+ param([0], True),
844
+ param(["0"], False),
845
+ param({0}, True),
846
+ param({0: 0}, True),
847
+ param(None, False),
848
+ param([None], False),
849
+ ],
850
+ )
851
+ def test_single(self, *, obj: Any, expected: bool) -> None:
852
+ result = is_iterable_of(obj, int)
853
+ assert result is expected
854
+
855
+ @mark.parametrize(
856
+ ("obj", "expected"),
857
+ [
858
+ param([0], True),
859
+ param(["0"], True),
860
+ param([0, "0"], True),
861
+ param(None, False),
862
+ param([None], False),
863
+ ],
864
+ )
865
+ def test_multiple(self, *, obj: Any, expected: bool) -> None:
866
+ result = is_iterable_of(obj, (int, str))
867
+ assert result is expected
868
+
869
+
764
870
  class TestIsNamedTuple:
765
871
  def test_main(self) -> None:
766
872
  class Example(NamedTuple):
@@ -778,6 +884,66 @@ class TestIsNamedTuple:
778
884
  assert not is_namedtuple_instance(Example(x=0))
779
885
 
780
886
 
887
+ class TestIsSequenceOf:
888
+ @mark.parametrize(
889
+ ("obj", "expected"),
890
+ [
891
+ param([0], True),
892
+ param(["0"], False),
893
+ param({0}, False),
894
+ param({0: 0}, False),
895
+ param(None, False),
896
+ param([None], False),
897
+ ],
898
+ )
899
+ def test_single(self, *, obj: Any, expected: bool) -> None:
900
+ result = is_sequence_of(obj, int)
901
+ assert result is expected
902
+
903
+ @mark.parametrize(
904
+ ("obj", "expected"),
905
+ [
906
+ param([0], True),
907
+ param(["0"], True),
908
+ param([0, "0"], True),
909
+ param(None, False),
910
+ param([None], False),
911
+ ],
912
+ )
913
+ def test_multiple(self, *, obj: Any, expected: bool) -> None:
914
+ result = is_sequence_of(obj, (int, str))
915
+ assert result is expected
916
+
917
+
918
+ class TestIsSequenceOfTupleOrStrMapping:
919
+ @mark.parametrize(
920
+ ("obj", "expected"),
921
+ [
922
+ param(None, False),
923
+ param([(1, 2, 3)], True),
924
+ param([{"a": 1, "b": 2, "c": 3}], True),
925
+ param([(1, 2, 3), {"a": 1, "b": 2, "c": 3}], True),
926
+ ],
927
+ )
928
+ def test_main(self, *, obj: Any, expected: bool) -> None:
929
+ result = is_sequence_of_tuple_or_str_mapping(obj)
930
+ assert result is expected
931
+
932
+
933
+ class TestIsStringMapping:
934
+ @mark.parametrize(
935
+ ("obj", "expected"),
936
+ [
937
+ param(None, False),
938
+ param({"a": 1, "b": 2, "c": 3}, True),
939
+ param({1: "a", 2: "b", 3: "c"}, False),
940
+ ],
941
+ )
942
+ def test_main(self, *, obj: Any, expected: bool) -> None:
943
+ result = is_string_mapping(obj)
944
+ assert result is expected
945
+
946
+
781
947
  class TestIsSubclassGen:
782
948
  @mark.parametrize(
783
949
  ("child", "parent", "expected"),
@@ -867,3 +1033,55 @@ class TestIsSubclassGen:
867
1033
  match="Argument must be a class; got None of type <class 'NoneType'>",
868
1034
  ):
869
1035
  _ = is_subclass_gen(None, NoneType)
1036
+
1037
+
1038
+ class TestIsTuple:
1039
+ @mark.parametrize(
1040
+ ("obj", "expected"),
1041
+ [param(None, False), param((1, 2, 3), True), param([1, 2, 3], False)],
1042
+ )
1043
+ def test_main(self, *, obj: Any, expected: bool) -> None:
1044
+ result = is_tuple(obj)
1045
+ assert result is expected
1046
+
1047
+
1048
+ class TestIsTupleOrStringMapping:
1049
+ @mark.parametrize(
1050
+ ("obj", "expected"),
1051
+ [
1052
+ param(None, False),
1053
+ param((1, 2, 3), True),
1054
+ param({"a": 1, "b": 2, "c": 3}, True),
1055
+ param({1: "a", 2: "b", 3: "c"}, False),
1056
+ ],
1057
+ )
1058
+ def test_main(self, *, obj: Any, expected: bool) -> None:
1059
+ result = is_tuple_or_str_mapping(obj)
1060
+ assert result is expected
1061
+
1062
+
1063
+ class TestMakeIsInstance:
1064
+ @mark.parametrize(
1065
+ ("obj", "expected"), [param(True, True), param(False, True), param(None, False)]
1066
+ )
1067
+ def test_single(self, *, obj: bool | None, expected: bool) -> None:
1068
+ func = make_isinstance(bool)
1069
+ result = func(obj)
1070
+ assert result is expected
1071
+
1072
+ @mark.parametrize(
1073
+ ("obj", "expected"), [param(0, True), param("0", True), param(None, False)]
1074
+ )
1075
+ def test_multiple(self, *, obj: bool | None, expected: bool) -> None:
1076
+ func = make_isinstance((int, str))
1077
+ result = func(obj)
1078
+ assert result is expected
1079
+
1080
+ @mark.parametrize(
1081
+ ("obj", "expected"),
1082
+ [param(None, False), param({"int_": 0, "float_": 0.0}, True)],
1083
+ )
1084
+ def test_typed_dict(self, *, obj: Any, expected: float) -> None:
1085
+ func = make_isinstance(TypedDictFutureIntFloat)
1086
+ result = func(obj)
1087
+ assert result is expected