dycw-utilities 0.110.1__tar.gz → 0.110.2__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 (228) hide show
  1. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/PKG-INFO +1 -1
  2. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/pyproject.toml +2 -2
  3. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_text.py +54 -5
  4. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/__init__.py +1 -1
  5. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/text.py +132 -11
  6. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/.gitignore +0 -0
  7. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/LICENSE +0 -0
  8. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/README.md +0 -0
  9. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/__init__.py +0 -0
  10. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/conftest.py +0 -0
  11. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/modules/__init__.py +0 -0
  12. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/modules/package_missing/__init__.py +0 -0
  13. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/modules/package_missing/module.py +0 -0
  14. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/modules/package_with/__init__.py +0 -0
  15. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/modules/package_with/outer_1.py +0 -0
  16. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/modules/package_with/outer_2.py +0 -0
  17. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  18. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  19. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  20. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  21. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/modules/package_without/__init__.py +0 -0
  22. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/modules/package_without/module_1.py +0 -0
  23. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/modules/package_without/module_2.py +0 -0
  24. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/modules/standalone.py +0 -0
  25. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/modules/with_imports.py +0 -0
  26. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  27. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  28. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  29. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  30. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  31. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  32. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  33. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  34. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/scripts/__init__.py +0 -0
  35. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/scripts/test_async_service/__init__.py +0 -0
  36. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/scripts/test_async_service/__main__.py +0 -0
  37. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/scripts/test_async_service/run.sh +0 -0
  38. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/scripts/test_queue_processor/__init__.py +0 -0
  39. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/scripts/test_queue_processor/__main__.py +0 -0
  40. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/scripts/test_queue_processor/run.sh +0 -0
  41. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_altair.py +0 -0
  42. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_astor.py +0 -0
  43. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_asyncio.py +0 -0
  44. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_atomicwrites.py +0 -0
  45. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_atools.py +0 -0
  46. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_cachetools.py +0 -0
  47. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_click.py +0 -0
  48. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_concurrent.py +0 -0
  49. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_contextlib.py +0 -0
  50. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_contextvars.py +0 -0
  51. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_cryptography.py +0 -0
  52. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_cvxpy.py +0 -0
  53. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_dataclasses.py +0 -0
  54. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_datetime.py +0 -0
  55. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_enum.py +0 -0
  56. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_errors.py +0 -0
  57. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_eventkit.py +0 -0
  58. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_fastapi.py +0 -0
  59. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_fpdf2.py +0 -0
  60. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_functions.py +0 -0
  61. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_functools.py +0 -0
  62. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_getpass.py +0 -0
  63. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_git.py +0 -0
  64. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_hashlib.py +0 -0
  65. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_http.py +0 -0
  66. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_hypothesis.py +0 -0
  67. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_ipython.py +0 -0
  68. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_iterables.py +0 -0
  69. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_jupyter.py +0 -0
  70. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_lightweight_charts.py +0 -0
  71. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_logging.py +0 -0
  72. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_loguru.py +0 -0
  73. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_luigi.py +0 -0
  74. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_math.py +0 -0
  75. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_memory_profiler.py +0 -0
  76. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_modules.py +0 -0
  77. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_more_itertools.py +0 -0
  78. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_numpy.py +0 -0
  79. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_operator.py +0 -0
  80. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_optuna.py +0 -0
  81. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_orjson.py +0 -0
  82. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_os.py +0 -0
  83. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_parse.py +0 -0
  84. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_pathlib.py +0 -0
  85. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_period.py +0 -0
  86. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_pickle.py +0 -0
  87. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_platform.py +0 -0
  88. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_polars.py +0 -0
  89. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_polars_ols.py +0 -0
  90. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_pqdm.py +0 -0
  91. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_pydantic.py +0 -0
  92. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_pyinstrument.py +0 -0
  93. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_pyrsistent.py +0 -0
  94. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_pytest.py +0 -0
  95. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_pytest_regressions.py +0 -0
  96. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_python_dotenv.py +0 -0
  97. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_random.py +0 -0
  98. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_re.py +0 -0
  99. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_redis.py +0 -0
  100. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_reprlib.py +0 -0
  101. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_rich.py +0 -0
  102. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_scipy.py +0 -0
  103. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_sentinel.py +0 -0
  104. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_shelve.py +0 -0
  105. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_slack_sdk.py +0 -0
  106. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_socket.py +0 -0
  107. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_sqlalchemy.py +0 -0
  108. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_sqlalchemy_polars.py +0 -0
  109. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_statsmodel.py +0 -0
  110. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_streamlit.py +0 -0
  111. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_sys.py +0 -0
  112. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_tempfile.py +0 -0
  113. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_tenacity.py +0 -0
  114. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_threading.py +0 -0
  115. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_timer.py +0 -0
  116. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_traceback.py +0 -0
  117. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_traceback_funcs/__init__.py +0 -0
  118. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_traceback_funcs/chain.py +0 -0
  119. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
  120. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
  121. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_traceback_funcs/error_bind.py +0 -0
  122. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_traceback_funcs/many.py +0 -0
  123. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_traceback_funcs/one.py +0 -0
  124. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_traceback_funcs/recursive.py +0 -0
  125. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
  126. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
  127. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_traceback_funcs/two.py +0 -0
  128. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_traceback_funcs/untraced.py +0 -0
  129. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_types.py +0 -0
  130. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_typing.py +0 -0
  131. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_typing_funcs/__init__.py +0 -0
  132. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_typing_funcs/no_future.py +0 -0
  133. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_typing_funcs/with_future.py +0 -0
  134. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_tzdata.py +0 -0
  135. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_tzlocal.py +0 -0
  136. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_uuid.py +0 -0
  137. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_version.py +0 -0
  138. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_warnings.py +0 -0
  139. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_whenever.py +0 -0
  140. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_zipfile.py +0 -0
  141. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/tests/test_zoneinfo.py +0 -0
  142. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/altair.py +0 -0
  143. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/astor.py +0 -0
  144. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/asyncio.py +0 -0
  145. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/atomicwrites.py +0 -0
  146. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/atools.py +0 -0
  147. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/cachetools.py +0 -0
  148. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/click.py +0 -0
  149. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/concurrent.py +0 -0
  150. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/contextlib.py +0 -0
  151. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/contextvars.py +0 -0
  152. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/cryptography.py +0 -0
  153. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/cvxpy.py +0 -0
  154. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/dataclasses.py +0 -0
  155. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/datetime.py +0 -0
  156. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/enum.py +0 -0
  157. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/errors.py +0 -0
  158. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/eventkit.py +0 -0
  159. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/fastapi.py +0 -0
  160. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/fpdf2.py +0 -0
  161. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/functions.py +0 -0
  162. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/functools.py +0 -0
  163. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/getpass.py +0 -0
  164. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/git.py +0 -0
  165. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/hashlib.py +0 -0
  166. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/http.py +0 -0
  167. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/hypothesis.py +0 -0
  168. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/ipython.py +0 -0
  169. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/iterables.py +0 -0
  170. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/jupyter.py +0 -0
  171. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/lightweight_charts.py +0 -0
  172. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/logging.py +0 -0
  173. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/loguru.py +0 -0
  174. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/luigi.py +0 -0
  175. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/math.py +0 -0
  176. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/memory_profiler.py +0 -0
  177. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/modules.py +0 -0
  178. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/more_itertools.py +0 -0
  179. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/numpy.py +0 -0
  180. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/operator.py +0 -0
  181. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/optuna.py +0 -0
  182. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/orjson.py +0 -0
  183. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/os.py +0 -0
  184. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/parse.py +0 -0
  185. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/pathlib.py +0 -0
  186. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/period.py +0 -0
  187. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/pickle.py +0 -0
  188. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/platform.py +0 -0
  189. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/polars.py +0 -0
  190. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/polars_ols.py +0 -0
  191. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/pqdm.py +0 -0
  192. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/py.typed +0 -0
  193. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/pydantic.py +0 -0
  194. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/pyinstrument.py +0 -0
  195. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/pyrsistent.py +0 -0
  196. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/pytest.py +0 -0
  197. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/pytest_regressions.py +0 -0
  198. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/python_dotenv.py +0 -0
  199. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/random.py +0 -0
  200. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/re.py +0 -0
  201. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/redis.py +0 -0
  202. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/reprlib.py +0 -0
  203. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/rich.py +0 -0
  204. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/scipy.py +0 -0
  205. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/sentinel.py +0 -0
  206. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/shelve.py +0 -0
  207. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/slack_sdk.py +0 -0
  208. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/socket.py +0 -0
  209. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/sqlalchemy.py +0 -0
  210. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/sqlalchemy_polars.py +0 -0
  211. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/statsmodels.py +0 -0
  212. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/streamlit.py +0 -0
  213. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/sys.py +0 -0
  214. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/tempfile.py +0 -0
  215. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/tenacity.py +0 -0
  216. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/threading.py +0 -0
  217. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/timer.py +0 -0
  218. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/traceback.py +0 -0
  219. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/types.py +0 -0
  220. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/typing.py +0 -0
  221. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/tzdata.py +0 -0
  222. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/tzlocal.py +0 -0
  223. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/uuid.py +0 -0
  224. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/version.py +0 -0
  225. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/warnings.py +0 -0
  226. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/whenever.py +0 -0
  227. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/zipfile.py +0 -0
  228. {dycw_utilities-0.110.1 → dycw_utilities-0.110.2}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.110.1
3
+ Version: 0.110.2
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -94,7 +94,7 @@ dependencies = [
94
94
  name = "dycw-utilities"
95
95
  readme = "README.md"
96
96
  requires-python = ">= 3.12"
97
- version = "0.110.1"
97
+ version = "0.110.2"
98
98
 
99
99
  [project.optional-dependencies]
100
100
  test = [
@@ -337,7 +337,7 @@ zzz-test-zoneinfo = [
337
337
  # bump-my-version
338
338
  [tool.bumpversion]
339
339
  allow_dirty = true
340
- current_version = "0.110.1"
340
+ current_version = "0.110.2"
341
341
 
342
342
  [[tool.bumpversion.files]]
343
343
  filename = "src/utilities/__init__.py"
@@ -20,9 +20,12 @@ from utilities.hypothesis import text_ascii
20
20
  from utilities.text import (
21
21
  ParseBoolError,
22
22
  ParseNoneError,
23
- SplitStrError,
24
23
  _SplitKeyValuePairsDuplicateKeysError,
25
24
  _SplitKeyValuePairsSplitError,
25
+ _SplitStrClosingBracketMismatchedError,
26
+ _SplitStrClosingBracketUnmatchedError,
27
+ _SplitStrCountError,
28
+ _SplitStrOpeningBracketUnmatchedError,
26
29
  join_strs,
27
30
  parse_bool,
28
31
  parse_none,
@@ -114,7 +117,7 @@ class TestSplitKeyValuePairs:
114
117
  _ = split_key_value_pairs("a=1,a=22,a=333", mapping=True)
115
118
 
116
119
 
117
- class TestSplitStrAndJoinStr:
120
+ class TestSplitAndJoinStr:
118
121
  @given(
119
122
  data=data(),
120
123
  case=sampled_from([
@@ -126,9 +129,10 @@ class TestSplitStrAndJoinStr:
126
129
  ("1,22", 2, ["1", "22"]),
127
130
  ("1,22,333", 3, ["1", "22", "333"]),
128
131
  ("1,,333", 3, ["1", "", "333"]),
132
+ ("1,(22,22,22),333", 5, ["1", "(22", "22", "22)", "333"]),
129
133
  ]),
130
134
  )
131
- def test_main(self, *, case: tuple[str, int, list[str]], data: DataObject) -> None:
135
+ def test_main(self, *, data: DataObject, case: tuple[str, int, list[str]]) -> None:
132
136
  text, n, expected = case
133
137
  n_use = data.draw(just(n) | none())
134
138
  result = split_str(text, n=n_use)
@@ -138,6 +142,29 @@ class TestSplitStrAndJoinStr:
138
142
  assert result == tuple(expected)
139
143
  assert join_strs(result) == text
140
144
 
145
+ @given(
146
+ data=data(),
147
+ case=sampled_from([
148
+ ("1", 1, ["1"]),
149
+ ("1,22", 2, ["1", "22"]),
150
+ ("1,22,333", 3, ["1", "22", "333"]),
151
+ ("1,(22),333", 3, ["1", "(22)", "333"]),
152
+ ("1,(22,22),333", 3, ["1", "(22,22)", "333"]),
153
+ ("1,(22,22,22),333", 3, ["1", "(22,22,22)", "333"]),
154
+ ]),
155
+ )
156
+ def test_brackets(
157
+ self, *, data: DataObject, case: tuple[str, int, list[str]]
158
+ ) -> None:
159
+ text, n, expected = case
160
+ n_use = data.draw(just(n) | none())
161
+ result = split_str(text, brackets=[("(", ")")], n=n_use)
162
+ if n_use is None:
163
+ assert result == expected
164
+ else:
165
+ assert result == tuple(expected)
166
+ assert join_strs(result) == text
167
+
141
168
  @given(texts=lists(text_ascii()))
142
169
  def test_generic(self, *, texts: list[str]) -> None:
143
170
  assert split_str(join_strs(texts)) == texts
@@ -146,12 +173,34 @@ class TestSplitStrAndJoinStr:
146
173
  def test_sort(self, *, texts: set[str]) -> None:
147
174
  assert split_str(join_strs(texts, sort=True)) == sorted(texts)
148
175
 
149
- def test_error(self) -> None:
176
+ def test_error_closing_bracket_mismatched(self) -> None:
177
+ with raises(
178
+ _SplitStrClosingBracketMismatchedError,
179
+ match=r"Unable to split '1,\(22\},333'; got mismatched '\(' at position 2 and '}' at position 5",
180
+ ):
181
+ _ = split_str("1,(22},333", brackets=[("(", ")"), ("{", "}")])
182
+
183
+ def test_error_closing_bracket_unmatched(self) -> None:
150
184
  with raises(
151
- SplitStrError, match=r"Unable to split '1,22,333' into 4 part\(s\); got 3"
185
+ _SplitStrClosingBracketUnmatchedError,
186
+ match=r"Unable to split '1,22\),333'; got unmatched '\)' at position 4",
187
+ ):
188
+ _ = split_str("1,22),333", brackets=[("(", ")")])
189
+
190
+ def test_error_count(self) -> None:
191
+ with raises(
192
+ _SplitStrCountError,
193
+ match=r"Unable to split '1,22,333' into 4 part\(s\); got 3",
152
194
  ):
153
195
  _ = split_str("1,22,333", n=4)
154
196
 
197
+ def test_error_opening_bracket(self) -> None:
198
+ with raises(
199
+ _SplitStrOpeningBracketUnmatchedError,
200
+ match=r"Unable to split '1,\(22,333'; got unmatched '\(' at position 2",
201
+ ):
202
+ _ = split_str("1,(22,333", brackets=[("(", ")")])
203
+
155
204
 
156
205
  class TestSnakeCase:
157
206
  @given(
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.110.1"
3
+ __version__ = "0.110.2"
@@ -1,12 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import re
4
+ from collections import deque
4
5
  from dataclasses import dataclass
5
- from re import IGNORECASE, Match, search
6
+ from itertools import chain
7
+ from re import IGNORECASE, Match, escape, search
6
8
  from textwrap import dedent
7
9
  from typing import TYPE_CHECKING, Any, Literal, overload, override
8
10
 
9
- from utilities.iterables import CheckDuplicatesError, check_duplicates
11
+ from utilities.iterables import CheckDuplicatesError, check_duplicates, transpose
10
12
  from utilities.reprlib import get_repr
11
13
 
12
14
  if TYPE_CHECKING:
@@ -167,47 +169,134 @@ class _SplitKeyValuePairsDuplicateKeysError(SplitKeyValuePairsError):
167
169
 
168
170
 
169
171
  @overload
170
- def split_str(text: str, /, *, separator: str = ",", n: Literal[1]) -> tuple[str]: ...
172
+ def split_str(
173
+ text: str,
174
+ /,
175
+ *,
176
+ separator: str = ",",
177
+ brackets: Iterable[tuple[str, str]] | None = None,
178
+ n: Literal[1],
179
+ ) -> tuple[str]: ...
171
180
  @overload
172
181
  def split_str(
173
- text: str, /, *, separator: str = ",", n: Literal[2]
182
+ text: str,
183
+ /,
184
+ *,
185
+ separator: str = ",",
186
+ brackets: Iterable[tuple[str, str]] | None = None,
187
+ n: Literal[2],
174
188
  ) -> tuple[str, str]: ...
175
189
  @overload
176
190
  def split_str(
177
- text: str, /, *, separator: str = ",", n: Literal[3]
191
+ text: str,
192
+ /,
193
+ *,
194
+ separator: str = ",",
195
+ brackets: Iterable[tuple[str, str]] | None = None,
196
+ n: Literal[3],
178
197
  ) -> tuple[str, str, str]: ...
179
198
  @overload
180
199
  def split_str(
181
- text: str, /, *, separator: str = ",", n: Literal[4]
200
+ text: str,
201
+ /,
202
+ *,
203
+ separator: str = ",",
204
+ brackets: Iterable[tuple[str, str]] | None = None,
205
+ n: Literal[4],
182
206
  ) -> tuple[str, str, str, str]: ...
183
207
  @overload
184
208
  def split_str(
185
- text: str, /, *, separator: str = ",", n: Literal[5]
209
+ text: str,
210
+ /,
211
+ *,
212
+ separator: str = ",",
213
+ brackets: Iterable[tuple[str, str]] | None = None,
214
+ n: Literal[5],
186
215
  ) -> tuple[str, str, str, str, str]: ...
187
216
  @overload
188
217
  def split_str(
189
- text: str, /, *, separator: str = ",", n: int | None = None
218
+ text: str,
219
+ /,
220
+ *,
221
+ separator: str = ",",
222
+ brackets: Iterable[tuple[str, str]] | None = None,
223
+ n: int | None = None,
190
224
  ) -> Sequence[str]: ...
191
225
  def split_str(
192
- text: str, /, *, separator: str = ",", n: int | None = None
226
+ text: str,
227
+ /,
228
+ *,
229
+ separator: str = ",",
230
+ brackets: Iterable[tuple[str, str]] | None = None,
231
+ n: int | None = None,
193
232
  ) -> Sequence[str]:
194
233
  """Split a string, with a special provision for the empty string."""
195
234
  if text == "":
196
235
  texts = []
197
236
  elif text == _escape_separator(separator=separator):
198
237
  texts = [""]
199
- else:
238
+ elif brackets is None:
200
239
  texts = text.split(separator)
240
+ else:
241
+ texts = _split_str_brackets(text, brackets, separator=separator)
201
242
  if n is None:
202
243
  return texts
203
244
  if len(texts) != n:
204
- raise SplitStrError(text=text, n=n, texts=texts)
245
+ raise _SplitStrCountError(text=text, n=n, texts=texts)
205
246
  return tuple(texts)
206
247
 
207
248
 
249
+ def _split_str_brackets(
250
+ text: str, brackets: Iterable[tuple[str, str]], /, *, separator: str = ","
251
+ ) -> Sequence[str]:
252
+ brackets = list(brackets)
253
+ opens, closes = transpose(brackets)
254
+ close_to_open = {close: open_ for open_, close in brackets}
255
+
256
+ escapes = map(escape, chain(chain.from_iterable(brackets), [separator]))
257
+ pattern = re.compile("|".join(escapes))
258
+
259
+ results: Sequence[str] = []
260
+ stack: deque[tuple[str, int]] = deque()
261
+ last = 0
262
+
263
+ for match in pattern.finditer(text):
264
+ token, position = match.group(), match.start()
265
+ if token in opens:
266
+ stack.append((token, position))
267
+ elif token in closes:
268
+ if len(stack) == 0:
269
+ raise _SplitStrClosingBracketUnmatchedError(
270
+ text=text, token=token, position=position
271
+ )
272
+ open_token, open_position = stack.pop()
273
+ if open_token != close_to_open[token]:
274
+ raise _SplitStrClosingBracketMismatchedError(
275
+ text=text,
276
+ opening_token=open_token,
277
+ opening_position=open_position,
278
+ closing_token=token,
279
+ closing_position=position,
280
+ )
281
+ elif (token == separator) and (len(stack) == 0):
282
+ results.append(text[last:position].strip())
283
+ last = position + 1
284
+ results.append(text[last:].strip())
285
+ if len(stack) >= 1:
286
+ token, position = stack.pop()
287
+ raise _SplitStrOpeningBracketUnmatchedError(
288
+ text=text, token=token, position=position
289
+ )
290
+ return results
291
+
292
+
208
293
  @dataclass(kw_only=True, slots=True)
209
294
  class SplitStrError(Exception):
210
295
  text: str
296
+
297
+
298
+ @dataclass(kw_only=True, slots=True)
299
+ class _SplitStrCountError(SplitStrError):
211
300
  n: int
212
301
  texts: Sequence[str]
213
302
 
@@ -216,6 +305,38 @@ class SplitStrError(Exception):
216
305
  return f"Unable to split {self.text!r} into {self.n} part(s); got {len(self.texts)}"
217
306
 
218
307
 
308
+ @dataclass(kw_only=True, slots=True)
309
+ class _SplitStrClosingBracketMismatchedError(SplitStrError):
310
+ opening_token: str
311
+ opening_position: int
312
+ closing_token: str
313
+ closing_position: int
314
+
315
+ @override
316
+ def __str__(self) -> str:
317
+ return f"Unable to split {self.text!r}; got mismatched {self.opening_token!r} at position {self.opening_position} and {self.closing_token!r} at position {self.closing_position}"
318
+
319
+
320
+ @dataclass(kw_only=True, slots=True)
321
+ class _SplitStrClosingBracketUnmatchedError(SplitStrError):
322
+ token: str
323
+ position: int
324
+
325
+ @override
326
+ def __str__(self) -> str:
327
+ return f"Unable to split {self.text!r}; got unmatched {self.token!r} at position {self.position}"
328
+
329
+
330
+ @dataclass(kw_only=True, slots=True)
331
+ class _SplitStrOpeningBracketUnmatchedError(SplitStrError):
332
+ token: str
333
+ position: int
334
+
335
+ @override
336
+ def __str__(self) -> str:
337
+ return f"Unable to split {self.text!r}; got unmatched {self.token!r} at position {self.position}"
338
+
339
+
219
340
  def join_strs(
220
341
  texts: Iterable[str], /, *, sort: bool = False, separator: str = ","
221
342
  ) -> str: