dycw-utilities 0.153.6__tar.gz → 0.153.8__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 (212) hide show
  1. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/PKG-INFO +1 -1
  2. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/pyproject.toml +2 -2
  3. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/conftest.py +46 -27
  4. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_functions.py +45 -17
  5. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_sqlalchemy.py +34 -0
  6. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/__init__.py +1 -1
  7. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/functions.py +16 -0
  8. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/sqlalchemy.py +25 -3
  9. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/.gitignore +0 -0
  10. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/LICENSE +0 -0
  11. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/README.md +0 -0
  12. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/__init__.py +0 -0
  13. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/modules/__init__.py +0 -0
  14. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/modules/package_missing/__init__.py +0 -0
  15. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/modules/package_missing/module.py +0 -0
  16. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/modules/package_with/__init__.py +0 -0
  17. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/modules/package_with/outer_1.py +0 -0
  18. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/modules/package_with/outer_2.py +0 -0
  19. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  20. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  21. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  22. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  23. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/modules/package_without/__init__.py +0 -0
  24. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/modules/package_without/module_1.py +0 -0
  25. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/modules/package_without/module_2.py +0 -0
  26. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/modules/standalone.py +0 -0
  27. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/modules/with_imports.py +0 -0
  28. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  29. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  30. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  31. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  32. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  33. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  34. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  35. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  36. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_altair.py +0 -0
  37. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_asyncio.py +0 -0
  38. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_atomicwrites.py +0 -0
  39. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_atools.py +0 -0
  40. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_cachetools.py +0 -0
  41. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_click.py +0 -0
  42. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_concurrent.py +0 -0
  43. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_contextlib.py +0 -0
  44. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_contextvars.py +0 -0
  45. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_cryptography.py +0 -0
  46. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_cvxpy.py +0 -0
  47. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_dataclasses.py +0 -0
  48. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_enum.py +0 -0
  49. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_errors.py +0 -0
  50. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_eventkit.py +0 -0
  51. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_fastapi.py +0 -0
  52. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_fpdf2.py +0 -0
  53. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_functools.py +0 -0
  54. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_getpass.py +0 -0
  55. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_gzip.py +0 -0
  56. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_hashlib.py +0 -0
  57. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_http.py +0 -0
  58. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_hypothesis.py +0 -0
  59. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_importlib.py +0 -0
  60. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_inflect.py +0 -0
  61. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_ipython.py +0 -0
  62. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_iterables.py +0 -0
  63. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_json.py +0 -0
  64. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_jupyter.py +0 -0
  65. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_libcst.py +0 -0
  66. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_lightweight_charts.py +0 -0
  67. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_logging.py +0 -0
  68. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_math.py +0 -0
  69. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_memory_profiler.py +0 -0
  70. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_modules.py +0 -0
  71. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_more_itertools.py +0 -0
  72. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_numpy.py +0 -0
  73. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_objects/__init__.py +0 -0
  74. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_objects/objects.py +0 -0
  75. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_operator.py +0 -0
  76. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_optuna.py +0 -0
  77. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_orjson.py +0 -0
  78. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_os.py +0 -0
  79. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_parse.py +0 -0
  80. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_pathlib.py +0 -0
  81. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_pickle.py +0 -0
  82. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_platform.py +0 -0
  83. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_polars.py +0 -0
  84. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_polars_ols.py +0 -0
  85. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_postgres.py +0 -0
  86. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_pottery.py +0 -0
  87. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_pqdm.py +0 -0
  88. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_psutil.py +0 -0
  89. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_pyinstrument.py +0 -0
  90. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_pytest.py +0 -0
  91. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_pytest_randomly.py +0 -0
  92. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_pytest_regressions.py +0 -0
  93. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_random.py +0 -0
  94. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_re.py +0 -0
  95. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_redis.py +0 -0
  96. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_reprlib.py +0 -0
  97. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_scipy.py +0 -0
  98. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_sentinel.py +0 -0
  99. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_shelve.py +0 -0
  100. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_slack_sdk.py +0 -0
  101. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_socket.py +0 -0
  102. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_sqlalchemy_polars.py +0 -0
  103. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_statsmodels.py +0 -0
  104. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_string.py +0 -0
  105. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_tempfile.py +0 -0
  106. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_text.py +0 -0
  107. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_threading.py +0 -0
  108. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_timer.py +0 -0
  109. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_traceback.py +0 -0
  110. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_typed_settings.py +0 -0
  111. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_types.py +0 -0
  112. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_typing.py +0 -0
  113. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_typing_funcs/__init__.py +0 -0
  114. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_typing_funcs/no_future.py +0 -0
  115. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_typing_funcs/with_future.py +0 -0
  116. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_tzdata.py +0 -0
  117. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_tzlocal.py +0 -0
  118. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_uuid.py +0 -0
  119. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_version.py +0 -0
  120. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_warnings.py +0 -0
  121. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_whenever.py +0 -0
  122. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_yield_access/__init__.py +0 -0
  123. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_yield_access/script.py +0 -0
  124. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_yield_access/script.sh +0 -0
  125. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_zipfile.py +0 -0
  126. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/tests/test_zoneinfo.py +0 -0
  127. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/altair.py +0 -0
  128. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/asyncio.py +0 -0
  129. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/atomicwrites.py +0 -0
  130. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/atools.py +0 -0
  131. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/cachetools.py +0 -0
  132. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/click.py +0 -0
  133. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/concurrent.py +0 -0
  134. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/contextlib.py +0 -0
  135. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/contextvars.py +0 -0
  136. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/cryptography.py +0 -0
  137. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/cvxpy.py +0 -0
  138. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/dataclasses.py +0 -0
  139. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/enum.py +0 -0
  140. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/errors.py +0 -0
  141. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/eventkit.py +0 -0
  142. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/fastapi.py +0 -0
  143. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/fpdf2.py +0 -0
  144. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/functools.py +0 -0
  145. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/getpass.py +0 -0
  146. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/gzip.py +0 -0
  147. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/hashlib.py +0 -0
  148. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/http.py +0 -0
  149. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/hypothesis.py +0 -0
  150. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/importlib.py +0 -0
  151. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/inflect.py +0 -0
  152. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/ipython.py +0 -0
  153. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/iterables.py +0 -0
  154. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/json.py +0 -0
  155. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/jupyter.py +0 -0
  156. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/libcst.py +0 -0
  157. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/lightweight_charts.py +0 -0
  158. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/logging.py +0 -0
  159. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/math.py +0 -0
  160. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/memory_profiler.py +0 -0
  161. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/modules.py +0 -0
  162. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/more_itertools.py +0 -0
  163. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/numpy.py +0 -0
  164. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/operator.py +0 -0
  165. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/optuna.py +0 -0
  166. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/orjson.py +0 -0
  167. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/os.py +0 -0
  168. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/parse.py +0 -0
  169. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/pathlib.py +0 -0
  170. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/pickle.py +0 -0
  171. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/platform.py +0 -0
  172. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/polars.py +0 -0
  173. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/polars_ols.py +0 -0
  174. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/postgres.py +0 -0
  175. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/pottery.py +0 -0
  176. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/pqdm.py +0 -0
  177. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/psutil.py +0 -0
  178. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/py.typed +0 -0
  179. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/pyinstrument.py +0 -0
  180. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/pytest.py +0 -0
  181. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/pytest_plugins/__init__.py +0 -0
  182. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/pytest_plugins/pytest_randomly.py +0 -0
  183. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/pytest_plugins/pytest_regressions.py +0 -0
  184. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/pytest_regressions.py +0 -0
  185. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/random.py +0 -0
  186. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/re.py +0 -0
  187. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/redis.py +0 -0
  188. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/reprlib.py +0 -0
  189. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/scipy.py +0 -0
  190. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/sentinel.py +0 -0
  191. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/shelve.py +0 -0
  192. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/slack_sdk.py +0 -0
  193. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/socket.py +0 -0
  194. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/sqlalchemy_polars.py +0 -0
  195. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/statsmodels.py +0 -0
  196. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/string.py +0 -0
  197. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/tempfile.py +0 -0
  198. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/text.py +0 -0
  199. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/threading.py +0 -0
  200. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/timer.py +0 -0
  201. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/traceback.py +0 -0
  202. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/typed_settings.py +0 -0
  203. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/types.py +0 -0
  204. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/typing.py +0 -0
  205. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/tzdata.py +0 -0
  206. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/tzlocal.py +0 -0
  207. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/uuid.py +0 -0
  208. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/version.py +0 -0
  209. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/warnings.py +0 -0
  210. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/whenever.py +0 -0
  211. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/zipfile.py +0 -0
  212. {dycw_utilities-0.153.6 → dycw_utilities-0.153.8}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.153.6
3
+ Version: 0.153.8
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -229,7 +229,7 @@ dependencies = [
229
229
  name = "dycw-utilities"
230
230
  readme = "README.md"
231
231
  requires-python = ">= 3.12"
232
- version = "0.153.6"
232
+ version = "0.153.8"
233
233
 
234
234
  [project.entry-points.pytest11]
235
235
  pytest-randomly = "utilities.pytest_plugins.pytest_randomly"
@@ -262,7 +262,7 @@ test = [
262
262
  # bump-my-version
263
263
  [tool.bumpversion]
264
264
  allow_dirty = true
265
- current_version = "0.153.6"
265
+ current_version = "0.153.8"
266
266
 
267
267
  [[tool.bumpversion.files]]
268
268
  filename = "src/utilities/__init__.py"
@@ -114,42 +114,61 @@ def test_engine(*, request: SubRequest, tmp_path: Path) -> Engine:
114
114
 
115
115
 
116
116
  @fixture(params=[param("sqlite"), param("postgresql", marks=SKIPIF_CI)])
117
- async def test_async_engine(*, request: SubRequest, tmp_path: Path) -> AsyncEngine:
118
- from utilities.sqlalchemy import create_engine
119
-
117
+ async def test_async_engine(
118
+ *,
119
+ request: SubRequest,
120
+ test_async_sqlite_engine: AsyncEngine,
121
+ test_async_postgres_engine: AsyncEngine,
122
+ ) -> AsyncEngine:
120
123
  dialect = request.param
121
124
  match dialect:
122
125
  case "sqlite":
123
- db_path = tmp_path / "db.sqlite"
124
- return create_engine("sqlite+aiosqlite", database=str(db_path), async_=True)
126
+ return test_async_sqlite_engine
125
127
  case "postgresql":
126
- from asyncpg.exceptions import InvalidCatalogNameError
127
-
128
- engine = create_engine(
129
- "postgresql+asyncpg",
130
- host="localhost",
131
- port=5432,
132
- database="testing",
133
- async_=True,
134
- )
135
- try:
136
- async with engine.begin() as conn:
137
- tables: Sequence[str] = (
138
- (await conn.execute(_select_tables())).scalars().all()
139
- )
140
- except InvalidCatalogNameError:
141
- ...
142
- else:
143
- for table in filter(_is_to_drop, tables):
144
- async with engine.begin() as conn:
145
- with suppress(Exception):
146
- _ = await conn.execute(_drop_table(table))
147
- return engine
128
+ return test_async_postgres_engine
148
129
  case _:
149
130
  msg = f"Unsupported dialect: {dialect}"
150
131
  raise NotImplementedError(msg)
151
132
 
152
133
 
134
+ @fixture
135
+ async def test_async_sqlite_engine(*, tmp_path: Path) -> AsyncEngine:
136
+ from utilities.sqlalchemy import create_engine
137
+
138
+ db_path = tmp_path / "db.sqlite"
139
+ return create_engine("sqlite+aiosqlite", database=str(db_path), async_=True)
140
+
141
+
142
+ @fixture
143
+ async def test_async_postgres_engine() -> AsyncEngine:
144
+ from asyncpg.exceptions import InvalidCatalogNameError
145
+
146
+ from utilities.sqlalchemy import create_engine
147
+
148
+ if IS_CI:
149
+ skip(reason="Skipped for CI")
150
+ engine = create_engine(
151
+ "postgresql+asyncpg",
152
+ host="localhost",
153
+ port=5432,
154
+ database="testing",
155
+ async_=True,
156
+ )
157
+ try:
158
+ async with engine.begin() as conn:
159
+ tables: Sequence[str] = (
160
+ (await conn.execute(_select_tables())).scalars().all()
161
+ )
162
+ except InvalidCatalogNameError:
163
+ ...
164
+ else:
165
+ for table in filter(_is_to_drop, tables):
166
+ async with engine.begin() as conn:
167
+ with suppress(Exception):
168
+ _ = await conn.execute(_drop_table(table))
169
+ return engine
170
+
171
+
153
172
  def _is_to_drop(table: str, /) -> bool:
154
173
  try:
155
174
  datetime_str = extract_group(r"^(\d{8}T\d{6})_", table)
@@ -6,6 +6,8 @@ from functools import cache, cached_property, lru_cache, partial, wraps
6
6
  from itertools import chain
7
7
  from operator import neg
8
8
  from pathlib import Path
9
+ from subprocess import check_output
10
+ from sys import executable
9
11
  from types import NoneType
10
12
  from typing import TYPE_CHECKING, Any, ClassVar, cast
11
13
 
@@ -22,7 +24,7 @@ from hypothesis.strategies import (
22
24
  permutations,
23
25
  sampled_from,
24
26
  )
25
- from pytest import raises
27
+ from pytest import mark, param, raises
26
28
 
27
29
  from utilities.errors import ImpossibleCaseError
28
30
  from utilities.functions import (
@@ -95,6 +97,7 @@ from utilities.functions import (
95
97
  yield_object_properties,
96
98
  )
97
99
  from utilities.sentinel import sentinel
100
+ from utilities.text import parse_bool, strip_and_dedent
98
101
  from utilities.whenever import NOW_UTC, ZERO_TIME, get_now, get_today
99
102
 
100
103
  if TYPE_CHECKING:
@@ -131,40 +134,40 @@ class TestApplyDecorators:
131
134
  assert counter == 1
132
135
 
133
136
 
134
- class TestEnsureBytes:
135
- @given(case=sampled_from([(b"", False), (b"", True), (None, True)]))
136
- def test_main(self, *, case: tuple[bytes | None, bool]) -> None:
137
+ class TestEnsureBool:
138
+ @given(case=sampled_from([(True, False), (True, True), (None, True)]))
139
+ def test_main(self, *, case: tuple[bool | None, bool]) -> None:
137
140
  obj, nullable = case
138
- _ = ensure_bytes(obj, nullable=nullable)
141
+ _ = ensure_bool(obj, nullable=nullable)
139
142
 
140
143
  @given(
141
144
  case=sampled_from([
142
- (False, "Object '.*' of type '.*' must be a byte string"),
143
- (True, "Object '.*' of type '.*' must be a byte string or None"),
145
+ (False, "Object '.*' of type '.*' must be a boolean"),
146
+ (True, "Object '.*' of type '.*' must be a boolean or None"),
144
147
  ])
145
148
  )
146
149
  def test_error(self, *, case: tuple[bool, str]) -> None:
147
150
  nullable, match = case
148
- with raises(EnsureBytesError, match=match):
149
- _ = ensure_bytes(sentinel, nullable=nullable)
151
+ with raises(EnsureBoolError, match=match):
152
+ _ = ensure_bool(sentinel, nullable=nullable)
150
153
 
151
154
 
152
- class TestEnsureBool:
153
- @given(case=sampled_from([(True, False), (True, True), (None, True)]))
154
- def test_main(self, *, case: tuple[bool | None, bool]) -> None:
155
+ class TestEnsureBytes:
156
+ @given(case=sampled_from([(b"", False), (b"", True), (None, True)]))
157
+ def test_main(self, *, case: tuple[bytes | None, bool]) -> None:
155
158
  obj, nullable = case
156
- _ = ensure_bool(obj, nullable=nullable)
159
+ _ = ensure_bytes(obj, nullable=nullable)
157
160
 
158
161
  @given(
159
162
  case=sampled_from([
160
- (False, "Object '.*' of type '.*' must be a boolean"),
161
- (True, "Object '.*' of type '.*' must be a boolean or None"),
163
+ (False, "Object '.*' of type '.*' must be a byte string"),
164
+ (True, "Object '.*' of type '.*' must be a byte string or None"),
162
165
  ])
163
166
  )
164
167
  def test_error(self, *, case: tuple[bool, str]) -> None:
165
168
  nullable, match = case
166
- with raises(EnsureBoolError, match=match):
167
- _ = ensure_bool(sentinel, nullable=nullable)
169
+ with raises(EnsureBytesError, match=match):
170
+ _ = ensure_bytes(sentinel, nullable=nullable)
168
171
 
169
172
 
170
173
  class TestEnsureClass:
@@ -915,6 +918,31 @@ class TestSecond:
915
918
  assert second(pair) == y
916
919
 
917
920
 
921
+ class TestSkipIfOptimize:
922
+ @mark.parametrize("optimize", [param(True), param(False)])
923
+ def test_main(self, *, optimize: bool) -> None:
924
+ code = strip_and_dedent("""
925
+ from utilities.functions import skip_if_optimize
926
+
927
+ is_run = False
928
+
929
+ @skip_if_optimize
930
+ def func() -> None:
931
+ global is_run
932
+ is_run = True
933
+
934
+ func()
935
+ print(is_run)
936
+ """)
937
+
938
+ args = [executable]
939
+ if optimize:
940
+ args.append("-O")
941
+ args.extend(["-c", code])
942
+ is_run = parse_bool(check_output(args, text=True))
943
+ assert is_run is not optimize
944
+
945
+
918
946
  class TestYieldObjectAttributes:
919
947
  @given(n=integers())
920
948
  def test_main(self, *, n: int) -> None:
@@ -1,6 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from asyncio import sleep
3
4
  from enum import Enum, StrEnum, auto
5
+ from getpass import getuser
4
6
  from itertools import chain
5
7
  from typing import TYPE_CHECKING, Any, Literal, cast, overload, override
6
8
  from uuid import uuid4
@@ -29,6 +31,7 @@ from sqlalchemy.orm import (
29
31
  relationship,
30
32
  )
31
33
 
34
+ from tests.conftest import SKIPIF_CI
32
35
  from utilities.hypothesis import int32s, pairs, urls
33
36
  from utilities.iterables import one
34
37
  from utilities.modules import is_installed
@@ -72,6 +75,8 @@ from utilities.sqlalchemy import (
72
75
  columnwise_max,
73
76
  columnwise_min,
74
77
  create_engine,
78
+ ensure_database_created,
79
+ ensure_database_dropped,
75
80
  ensure_tables_created,
76
81
  ensure_tables_dropped,
77
82
  enum_name,
@@ -253,6 +258,35 @@ class TestCreateEngine:
253
258
  assert isinstance(engine, cls)
254
259
 
255
260
 
261
+ @SKIPIF_CI
262
+ class TestEnsureDatabaseCreatedAndDropped:
263
+ async def test_main(self) -> None:
264
+ url = URL.create(
265
+ "postgresql+asyncpg",
266
+ username=getuser(),
267
+ password="password", # noqa: S106
268
+ host="localhost",
269
+ port=5432,
270
+ database="postgres",
271
+ )
272
+ database = f"testing_{_table_names()}"
273
+ for _ in range(2):
274
+ await ensure_database_created(url, database)
275
+ await sleep(0.1)
276
+ for _ in range(2):
277
+ await ensure_database_dropped(url, database)
278
+ await sleep(0.1)
279
+
280
+ async def _run_test(
281
+ self, engine: AsyncEngine, table_or_orm: TableOrORMInstOrClass, /
282
+ ) -> None:
283
+ for _ in range(2):
284
+ await ensure_tables_created(engine, table_or_orm)
285
+ sel = select(get_table(table_or_orm))
286
+ async with engine.begin() as conn:
287
+ _ = (await conn.execute(sel)).all()
288
+
289
+
256
290
  class TestEnsureTablesCreated:
257
291
  async def test_table(self, *, test_async_engine: AsyncEngine) -> None:
258
292
  table = Table(
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.153.6"
3
+ __version__ = "0.153.8"
@@ -935,6 +935,21 @@ def second[U](pair: tuple[Any, U], /) -> U:
935
935
  ##
936
936
 
937
937
 
938
+ def skip_if_optimize[**P](func: Callable[P, None], /) -> Callable[P, None]:
939
+ """Skip a function if we are in the optimized mode."""
940
+ if __debug__:
941
+ return func
942
+
943
+ @wraps(func)
944
+ def wrapped(*args: P.args, **kwargs: P.kwargs) -> None:
945
+ _ = (args, kwargs)
946
+
947
+ return wrapped
948
+
949
+
950
+ ##
951
+
952
+
938
953
  def yield_object_attributes(
939
954
  obj: Any,
940
955
  /,
@@ -1043,6 +1058,7 @@ __all__ = [
1043
1058
  "min_nullable",
1044
1059
  "not_func",
1045
1060
  "second",
1061
+ "skip_if_optimize",
1046
1062
  "yield_object_attributes",
1047
1063
  "yield_object_cached_properties",
1048
1064
  "yield_object_properties",
@@ -30,7 +30,6 @@ from typing import (
30
30
  )
31
31
 
32
32
  import sqlalchemy
33
- import sqlalchemy.ext.asyncio
34
33
  from sqlalchemy import (
35
34
  URL,
36
35
  Column,
@@ -63,7 +62,7 @@ from sqlalchemy.exc import (
63
62
  OperationalError,
64
63
  ProgrammingError,
65
64
  )
66
- from sqlalchemy.ext.asyncio import AsyncConnection, AsyncEngine
65
+ from sqlalchemy.ext.asyncio import AsyncConnection, AsyncEngine, create_async_engine
67
66
  from sqlalchemy.orm import (
68
67
  DeclarativeBase,
69
68
  InstrumentedAttribute,
@@ -311,7 +310,7 @@ def create_engine(
311
310
  case False:
312
311
  return sqlalchemy.create_engine(url, poolclass=poolclass)
313
312
  case True:
314
- return sqlalchemy.ext.asyncio.create_async_engine(url, poolclass=poolclass)
313
+ return create_async_engine(url, poolclass=poolclass)
315
314
  case never:
316
315
  assert_never(never)
317
316
 
@@ -319,6 +318,27 @@ def create_engine(
319
318
  ##
320
319
 
321
320
 
321
+ async def ensure_database_created(super_: URL, database: str, /) -> None:
322
+ """Ensure a database is created."""
323
+ engine = create_async_engine(super_, isolation_level="AUTOCOMMIT")
324
+ async with engine.begin() as conn:
325
+ try:
326
+ _ = await conn.execute(text(f"CREATE DATABASE {database}"))
327
+ except (OperationalError, ProgrammingError) as error:
328
+ if not search('database ".*" already exists', ensure_str(one(error.args))):
329
+ raise
330
+
331
+
332
+ async def ensure_database_dropped(super_: URL, database: str, /) -> None:
333
+ """Ensure a database is dropped."""
334
+ engine = create_async_engine(super_, isolation_level="AUTOCOMMIT")
335
+ async with engine.begin() as conn:
336
+ _ = await conn.execute(text(f"DROP DATABASE IF EXISTS {database}"))
337
+
338
+
339
+ ##
340
+
341
+
322
342
  async def ensure_tables_created(
323
343
  engine: AsyncEngine,
324
344
  /,
@@ -1284,6 +1304,8 @@ __all__ = [
1284
1304
  "columnwise_max",
1285
1305
  "columnwise_min",
1286
1306
  "create_engine",
1307
+ "ensure_database_created",
1308
+ "ensure_database_dropped",
1287
1309
  "ensure_tables_created",
1288
1310
  "ensure_tables_dropped",
1289
1311
  "enum_name",