dycw-utilities 0.109.16__tar.gz → 0.109.18__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 (226) hide show
  1. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/PKG-INFO +1 -1
  2. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/pyproject.toml +2 -2
  3. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_hypothesis.py +2 -1
  4. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_numpy.py +103 -17
  5. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_orjson.py +2 -1
  6. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_polars.py +29 -0
  7. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/__init__.py +1 -1
  8. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/numpy.py +129 -23
  9. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/polars.py +38 -0
  10. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/.gitignore +0 -0
  11. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/LICENSE +0 -0
  12. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/README.md +0 -0
  13. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/__init__.py +0 -0
  14. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/conftest.py +0 -0
  15. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/modules/__init__.py +0 -0
  16. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/modules/package_missing/__init__.py +0 -0
  17. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/modules/package_missing/module.py +0 -0
  18. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/modules/package_with/__init__.py +0 -0
  19. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/modules/package_with/outer_1.py +0 -0
  20. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/modules/package_with/outer_2.py +0 -0
  21. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/modules/package_with/subpackage/__init__.py +0 -0
  22. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/modules/package_with/subpackage/inner_1.py +0 -0
  23. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/modules/package_with/subpackage/inner_2.py +0 -0
  24. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/modules/package_with/subpackage/inner_3.py +0 -0
  25. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/modules/package_without/__init__.py +0 -0
  26. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/modules/package_without/module_1.py +0 -0
  27. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/modules/package_without/module_2.py +0 -0
  28. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/modules/standalone.py +0 -0
  29. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/modules/with_imports.py +0 -0
  30. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__obj.json +0 -0
  31. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/regressions/test_pytest_regressions/TestMultipleRegressionFixtures__test_main__series.json +0 -0
  32. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_int.json +0 -0
  33. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__false.json +0 -0
  34. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_literal__true.json +0 -0
  35. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/regressions/test_pytest_regressions/TestOrjsonRegressionFixture__test_dataclass_nested.json +0 -0
  36. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_dataframe.json +0 -0
  37. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/regressions/test_pytest_regressions/TestPolarsRegressionFixture__test_series.json +0 -0
  38. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/scripts/__init__.py +0 -0
  39. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/scripts/test_async_service/__init__.py +0 -0
  40. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/scripts/test_async_service/__main__.py +0 -0
  41. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/scripts/test_async_service/run.sh +0 -0
  42. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/scripts/test_queue_processor/__init__.py +0 -0
  43. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/scripts/test_queue_processor/__main__.py +0 -0
  44. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/scripts/test_queue_processor/run.sh +0 -0
  45. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_altair.py +0 -0
  46. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_astor.py +0 -0
  47. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_asyncio.py +0 -0
  48. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_atomicwrites.py +0 -0
  49. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_atools.py +0 -0
  50. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_cachetools.py +0 -0
  51. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_click.py +0 -0
  52. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_concurrent.py +0 -0
  53. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_contextlib.py +0 -0
  54. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_contextvars.py +0 -0
  55. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_cryptography.py +0 -0
  56. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_cvxpy.py +0 -0
  57. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_dataclasses.py +0 -0
  58. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_datetime.py +0 -0
  59. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_enum.py +0 -0
  60. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_errors.py +0 -0
  61. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_eventkit.py +0 -0
  62. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_fastapi.py +0 -0
  63. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_fpdf2.py +0 -0
  64. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_functions.py +0 -0
  65. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_functools.py +0 -0
  66. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_getpass.py +0 -0
  67. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_git.py +0 -0
  68. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_hashlib.py +0 -0
  69. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_http.py +0 -0
  70. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_ipython.py +0 -0
  71. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_iterables.py +0 -0
  72. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_jupyter.py +0 -0
  73. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_lightweight_charts.py +0 -0
  74. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_logging.py +0 -0
  75. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_loguru.py +0 -0
  76. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_luigi.py +0 -0
  77. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_math.py +0 -0
  78. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_memory_profiler.py +0 -0
  79. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_modules.py +0 -0
  80. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_more_itertools.py +0 -0
  81. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_operator.py +0 -0
  82. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_optuna.py +0 -0
  83. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_os.py +0 -0
  84. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_parse.py +0 -0
  85. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_pathlib.py +0 -0
  86. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_period.py +0 -0
  87. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_pickle.py +0 -0
  88. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_platform.py +0 -0
  89. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_polars_ols.py +0 -0
  90. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_pqdm.py +0 -0
  91. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_pydantic.py +0 -0
  92. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_pyinstrument.py +0 -0
  93. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_pyrsistent.py +0 -0
  94. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_pytest.py +0 -0
  95. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_pytest_regressions.py +0 -0
  96. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_python_dotenv.py +0 -0
  97. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_random.py +0 -0
  98. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_re.py +0 -0
  99. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_redis.py +0 -0
  100. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_reprlib.py +0 -0
  101. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_rich.py +0 -0
  102. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_scipy.py +0 -0
  103. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_sentinel.py +0 -0
  104. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_shelve.py +0 -0
  105. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_slack_sdk.py +0 -0
  106. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_socket.py +0 -0
  107. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_sqlalchemy.py +0 -0
  108. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_sqlalchemy_polars.py +0 -0
  109. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_streamlit.py +0 -0
  110. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_sys.py +0 -0
  111. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_tempfile.py +0 -0
  112. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_tenacity.py +0 -0
  113. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_text.py +0 -0
  114. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_threading.py +0 -0
  115. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_timer.py +0 -0
  116. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_traceback.py +0 -0
  117. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_traceback_funcs/__init__.py +0 -0
  118. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_traceback_funcs/chain.py +0 -0
  119. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_traceback_funcs/decorated_async.py +0 -0
  120. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_traceback_funcs/decorated_sync.py +0 -0
  121. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_traceback_funcs/error_bind.py +0 -0
  122. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_traceback_funcs/many.py +0 -0
  123. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_traceback_funcs/one.py +0 -0
  124. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_traceback_funcs/recursive.py +0 -0
  125. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_traceback_funcs/task_group_one.py +0 -0
  126. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_traceback_funcs/task_group_two.py +0 -0
  127. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_traceback_funcs/two.py +0 -0
  128. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_traceback_funcs/untraced.py +0 -0
  129. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_types.py +0 -0
  130. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_typing.py +0 -0
  131. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_typing_funcs/__init__.py +0 -0
  132. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_typing_funcs/no_future.py +0 -0
  133. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_typing_funcs/with_future.py +0 -0
  134. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_tzdata.py +0 -0
  135. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_tzlocal.py +0 -0
  136. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_uuid.py +0 -0
  137. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_version.py +0 -0
  138. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_warnings.py +0 -0
  139. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_whenever.py +0 -0
  140. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_zipfile.py +0 -0
  141. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/tests/test_zoneinfo.py +0 -0
  142. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/altair.py +0 -0
  143. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/astor.py +0 -0
  144. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/asyncio.py +0 -0
  145. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/atomicwrites.py +0 -0
  146. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/atools.py +0 -0
  147. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/cachetools.py +0 -0
  148. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/click.py +0 -0
  149. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/concurrent.py +0 -0
  150. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/contextlib.py +0 -0
  151. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/contextvars.py +0 -0
  152. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/cryptography.py +0 -0
  153. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/cvxpy.py +0 -0
  154. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/dataclasses.py +0 -0
  155. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/datetime.py +0 -0
  156. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/enum.py +0 -0
  157. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/errors.py +0 -0
  158. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/eventkit.py +0 -0
  159. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/fastapi.py +0 -0
  160. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/fpdf2.py +0 -0
  161. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/functions.py +0 -0
  162. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/functools.py +0 -0
  163. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/getpass.py +0 -0
  164. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/git.py +0 -0
  165. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/hashlib.py +0 -0
  166. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/http.py +0 -0
  167. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/hypothesis.py +0 -0
  168. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/ipython.py +0 -0
  169. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/iterables.py +0 -0
  170. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/jupyter.py +0 -0
  171. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/lightweight_charts.py +0 -0
  172. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/logging.py +0 -0
  173. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/loguru.py +0 -0
  174. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/luigi.py +0 -0
  175. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/math.py +0 -0
  176. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/memory_profiler.py +0 -0
  177. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/modules.py +0 -0
  178. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/more_itertools.py +0 -0
  179. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/operator.py +0 -0
  180. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/optuna.py +0 -0
  181. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/orjson.py +0 -0
  182. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/os.py +0 -0
  183. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/parse.py +0 -0
  184. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/pathlib.py +0 -0
  185. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/period.py +0 -0
  186. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/pickle.py +0 -0
  187. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/platform.py +0 -0
  188. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/polars_ols.py +0 -0
  189. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/pqdm.py +0 -0
  190. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/py.typed +0 -0
  191. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/pydantic.py +0 -0
  192. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/pyinstrument.py +0 -0
  193. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/pyrsistent.py +0 -0
  194. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/pytest.py +0 -0
  195. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/pytest_regressions.py +0 -0
  196. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/python_dotenv.py +0 -0
  197. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/random.py +0 -0
  198. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/re.py +0 -0
  199. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/redis.py +0 -0
  200. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/reprlib.py +0 -0
  201. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/rich.py +0 -0
  202. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/scipy.py +0 -0
  203. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/sentinel.py +0 -0
  204. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/shelve.py +0 -0
  205. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/slack_sdk.py +0 -0
  206. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/socket.py +0 -0
  207. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/sqlalchemy.py +0 -0
  208. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/sqlalchemy_polars.py +0 -0
  209. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/streamlit.py +0 -0
  210. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/sys.py +0 -0
  211. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/tempfile.py +0 -0
  212. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/tenacity.py +0 -0
  213. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/text.py +0 -0
  214. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/threading.py +0 -0
  215. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/timer.py +0 -0
  216. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/traceback.py +0 -0
  217. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/types.py +0 -0
  218. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/typing.py +0 -0
  219. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/tzdata.py +0 -0
  220. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/tzlocal.py +0 -0
  221. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/uuid.py +0 -0
  222. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/version.py +0 -0
  223. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/warnings.py +0 -0
  224. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/whenever.py +0 -0
  225. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/zipfile.py +0 -0
  226. {dycw_utilities-0.109.16 → dycw_utilities-0.109.18}/src/utilities/zoneinfo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.109.16
3
+ Version: 0.109.18
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -92,7 +92,7 @@ dependencies = [
92
92
  name = "dycw-utilities"
93
93
  readme = "README.md"
94
94
  requires-python = ">= 3.12"
95
- version = "0.109.16"
95
+ version = "0.109.18"
96
96
 
97
97
  [project.optional-dependencies]
98
98
  test = [
@@ -335,7 +335,7 @@ zzz-test-zoneinfo = [
335
335
  # bump-my-version
336
336
  [tool.bumpversion]
337
337
  allow_dirty = true
338
- current_version = "0.109.16"
338
+ current_version = "0.109.18"
339
339
 
340
340
  [[tool.bumpversion.files]]
341
341
  filename = "src/utilities/__init__.py"
@@ -29,7 +29,7 @@ from hypothesis.strategies import (
29
29
  from luigi import Task
30
30
  from numpy import inf, int64, isfinite, isinf, isnan, ravel, rint
31
31
  from pathvalidate import validate_filepath
32
- from pytest import raises
32
+ from pytest import mark, raises
33
33
  from sqlalchemy import Column, Integer, MetaData, Table, insert, select
34
34
  from sqlalchemy.ext.asyncio import AsyncEngine
35
35
 
@@ -1033,6 +1033,7 @@ class TestTempPaths:
1033
1033
  assert len(set(path.iterdir())) == 0
1034
1034
 
1035
1035
  @given(path=temp_paths(), contents=sets(text_ascii(min_size=1), max_size=10))
1036
+ @mark.flaky
1036
1037
  def test_writing_files(self, *, path: Path, contents: AbstractSet[str]) -> None:
1037
1038
  assert len(set(path.iterdir())) == 0
1038
1039
  as_set = set(maybe_yield_lower_case(contents))
@@ -19,6 +19,7 @@ from numpy import (
19
19
  ndarray,
20
20
  ones,
21
21
  pi,
22
+ where,
22
23
  zeros,
23
24
  zeros_like,
24
25
  )
@@ -27,7 +28,7 @@ from numpy.random import Generator
27
28
  from numpy.testing import assert_equal
28
29
  from pytest import mark, param, raises
29
30
 
30
- from utilities.hypothesis import float_arrays
31
+ from utilities.hypothesis import float_arrays, pairs
31
32
  from utilities.numpy import (
32
33
  DEFAULT_RNG,
33
34
  AsIntError,
@@ -36,11 +37,16 @@ from utilities.numpy import (
36
37
  NDArrayF,
37
38
  NDArrayI,
38
39
  ShiftError,
40
+ SigmoidError,
41
+ _BoxCarLocationsError,
42
+ _BoxCarLowerBoundSlopeError,
43
+ _BoxCarUpperBoundSlopeError,
44
+ adjust_frequencies,
39
45
  array_indexer,
40
46
  as_int,
47
+ boxcar,
41
48
  discretize,
42
49
  fillna,
43
- filter_frequencies,
44
50
  flatn0,
45
51
  get_frequency_spectrum,
46
52
  has_dtype,
@@ -94,12 +100,39 @@ from utilities.numpy import (
94
100
  minimum,
95
101
  shift,
96
102
  shift_bool,
103
+ sigmoid,
97
104
  )
98
105
 
99
106
  if TYPE_CHECKING:
100
107
  from collections.abc import Sequence
101
108
 
102
109
 
110
+ class TestAdjustFrequencies:
111
+ def test_filter(self) -> None:
112
+ n = 1000
113
+ x = linspace(0, 2 * pi, n)
114
+ noise = DEFAULT_RNG.normal(scale=0.25, size=n)
115
+ y = x + noise
116
+ result = adjust_frequencies(y, filters=lambda f: np.abs(f) <= 0.02)
117
+ assert result.shape == (n,)
118
+ amplitudes = fft(result)
119
+ freqs = fftfreq(n)
120
+ assert np.allclose(amplitudes[np.abs(freqs) > 0.02], 0.0)
121
+
122
+ def test_weight(self) -> None:
123
+ n = 1000
124
+ x = linspace(0, 2 * pi, n)
125
+ noise = DEFAULT_RNG.normal(scale=0.25, size=n)
126
+ y = x + noise
127
+ result = adjust_frequencies(
128
+ y, weights=lambda f: where(np.abs(f) <= 0.02, 1.0, 0.0)
129
+ )
130
+ assert result.shape == (n,)
131
+ amplitudes = fft(result)
132
+ freqs = fftfreq(n)
133
+ assert np.allclose(amplitudes[np.abs(freqs) > 0.02], 0.0)
134
+
135
+
103
136
  class TestArrayIndexer:
104
137
  @mark.parametrize(
105
138
  ("i", "ndim", "expected"),
@@ -252,6 +285,56 @@ class TestDiscretize:
252
285
  assert_equal(result, expected)
253
286
 
254
287
 
288
+ class TestBoxCar:
289
+ @given(
290
+ locs=pairs(floats(-10.0, 10.0), sorted=True),
291
+ slope_low=floats(0.1, 10.0),
292
+ slope_high=floats(0.1, 10.0),
293
+ )
294
+ def test_main(
295
+ self, *, locs: tuple[float, float], slope_low: float, slope_high: float
296
+ ) -> None:
297
+ loc_low, loc_high = locs
298
+ n = 1000
299
+ x = linspace(0, 2 * pi, n)
300
+ y = boxcar(
301
+ x,
302
+ loc_low=loc_low,
303
+ slope_low=slope_low,
304
+ loc_high=loc_high,
305
+ slope_high=slope_high,
306
+ )
307
+ assert y.shape == (n,)
308
+ assert is_between(y, 0.0, 1.0).all()
309
+
310
+ def test_error_locations(self) -> None:
311
+ n = 1000
312
+ x = linspace(0, 2 * pi, n)
313
+ with raises(
314
+ _BoxCarLocationsError,
315
+ match="Location parameters must be consistent; got 1.0 and -1.0",
316
+ ):
317
+ _ = boxcar(x, loc_low=1.0, loc_high=-1.0)
318
+
319
+ def test_error_lower_bound_slope(self) -> None:
320
+ n = 1000
321
+ x = linspace(0, 2 * pi, n)
322
+ with raises(
323
+ _BoxCarLowerBoundSlopeError,
324
+ match="Lower-bound slope parameter must be positive; got 0.0",
325
+ ):
326
+ _ = boxcar(x, slope_low=0.0)
327
+
328
+ def test_error_upper_bound_slope(self) -> None:
329
+ n = 1000
330
+ x = linspace(0, 2 * pi, n)
331
+ with raises(
332
+ _BoxCarUpperBoundSlopeError,
333
+ match="Upper-bound slope parameter must be positive; got 0.0",
334
+ ):
335
+ _ = boxcar(x, slope_high=0.0)
336
+
337
+
255
338
  class TestFillNa:
256
339
  @mark.parametrize(
257
340
  ("init", "value", "expected_v"),
@@ -274,19 +357,6 @@ class TestFillNa:
274
357
  assert_equal(result, expected)
275
358
 
276
359
 
277
- class TestFilterFrequencies:
278
- def test_main(self) -> None:
279
- n = 1000
280
- x = linspace(0, 2 * pi, n)
281
- noise = DEFAULT_RNG.normal(scale=0.25, size=n)
282
- y = x + noise
283
- result = filter_frequencies(y, lambda f: np.abs(f) <= 0.02)
284
- assert result.shape == (n,)
285
- fft_vals = fft(result)
286
- freqs = fftfreq(n)
287
- assert np.allclose(fft_vals[np.abs(freqs) > 0.02], 0.0)
288
-
289
-
290
360
  class TestFlatN0:
291
361
  @given(data=data(), n=integers(1, 10))
292
362
  def test_main(self, *, data: DataObject, n: int) -> None:
@@ -313,10 +383,10 @@ class TestGetFrequencySpectrum:
313
383
  x = linspace(0, 2 * pi, n)
314
384
  noise = DEFAULT_RNG.normal(scale=0.25, size=n)
315
385
  y = x + noise
316
- y2 = filter_frequencies(y, lambda f: np.abs(f) <= 0.02)
386
+ y2 = adjust_frequencies(y, filters=lambda f: np.abs(f) <= 0.02)
317
387
  result = get_frequency_spectrum(y2)
318
388
  assert result.shape == (n, 2)
319
- assert np.allclose(result[result[:, 0] > 0.02, 1], 0.0)
389
+ assert np.allclose(result[np.abs(result[:, 0]) > 0.02, 1], 0.0)
320
390
 
321
391
 
322
392
  class TestHasDtype:
@@ -1078,3 +1148,19 @@ class TestShiftBool:
1078
1148
  [fill_value if e is None else e for e in expected_v], dtype=bool
1079
1149
  )
1080
1150
  assert_equal(result, expected)
1151
+
1152
+
1153
+ class TestSigmoid:
1154
+ @given(loc=floats(-10.0, 10.0), slope=floats(-10.0, -0.1) | floats(0.1, 10.0))
1155
+ def test_main(self, *, loc: float, slope: float) -> None:
1156
+ n = 1000
1157
+ x = linspace(0, 2 * pi, n)
1158
+ y = sigmoid(x, loc=loc, slope=slope)
1159
+ assert y.shape == (n,)
1160
+ assert is_between(y, 0.0, 1.0).all()
1161
+
1162
+ def test_error(self) -> None:
1163
+ n = 1000
1164
+ x = linspace(0, 2 * pi, n)
1165
+ with raises(SigmoidError, match="Slope must be non-zero"):
1166
+ _ = sigmoid(x, slope=0.0)
@@ -23,7 +23,7 @@ from hypothesis.strategies import (
23
23
  )
24
24
  from orjson import JSONDecodeError
25
25
  from polars import Object, String, UInt64
26
- from pytest import approx, raises
26
+ from pytest import approx, mark, raises
27
27
 
28
28
  from tests.conftest import SKIPIF_CI_AND_WINDOWS
29
29
  from tests.test_operator import (
@@ -204,6 +204,7 @@ class TestGetLogRecords:
204
204
  min_log_file_line_num=integers() | none(),
205
205
  max_log_file_line_num=integers() | none(),
206
206
  )
207
+ @mark.flaky
207
208
  def test_filter(
208
209
  self,
209
210
  *,
@@ -12,6 +12,7 @@ from typing import TYPE_CHECKING, Any, ClassVar, Literal, cast
12
12
  from uuid import UUID, uuid4
13
13
 
14
14
  import hypothesis.strategies
15
+ import numpy as np
15
16
  import polars as pl
16
17
  from hypothesis import given
17
18
  from hypothesis.strategies import (
@@ -26,6 +27,7 @@ from hypothesis.strategies import (
26
27
  sampled_from,
27
28
  timezones,
28
29
  )
30
+ from numpy import allclose, linspace, pi
29
31
  from polars import (
30
32
  Boolean,
31
33
  DataFrame,
@@ -60,6 +62,7 @@ from utilities.hypothesis import (
60
62
  zoned_datetimes,
61
63
  )
62
64
  from utilities.math import number_of_decimals
65
+ from utilities.numpy import DEFAULT_RNG
63
66
  from utilities.pathlib import PWD
64
67
  from utilities.polars import (
65
68
  AppendDataClassError,
@@ -104,6 +107,7 @@ from utilities.polars import (
104
107
  _InsertBetweenMissingColumnsError,
105
108
  _InsertBetweenNonConsecutiveError,
106
109
  _yield_struct_series_element_remove_nulls,
110
+ adjust_frequencies,
107
111
  append_dataclass,
108
112
  are_frames_equal,
109
113
  ceil_datetime,
@@ -121,6 +125,7 @@ from utilities.polars import (
121
125
  finite_ewm_mean,
122
126
  floor_datetime,
123
127
  get_data_type_or_series_time_zone,
128
+ get_frequency_spectrum,
124
129
  get_series_number_of_decimals,
125
130
  insert_after,
126
131
  insert_before,
@@ -162,6 +167,16 @@ if TYPE_CHECKING:
162
167
  from utilities.types import MaybeType, StrMapping, WeekDay
163
168
 
164
169
 
170
+ class TestAdjustFrequencies:
171
+ def test_main(self) -> None:
172
+ n = 1000
173
+ x = linspace(0, 2 * pi, n)
174
+ noise = DEFAULT_RNG.normal(scale=0.25, size=n)
175
+ y = Series(values=x + noise)
176
+ result = adjust_frequencies(y, filters=lambda f: np.abs(f) <= 0.02)
177
+ assert isinstance(result, Series)
178
+
179
+
165
180
  class TestAppendDataClass:
166
181
  @given(
167
182
  data=fixed_dictionaries({
@@ -1213,6 +1228,20 @@ class TestGetDataTypeOrSeriesTimeZone:
1213
1228
  _ = get_data_type_or_series_time_zone(Datetime)
1214
1229
 
1215
1230
 
1231
+ class TestGetFrequencySpectrum:
1232
+ def test_main(self) -> None:
1233
+ n = 1000
1234
+ x = linspace(0, 2 * pi, n)
1235
+ noise = DEFAULT_RNG.normal(scale=0.25, size=n)
1236
+ y = Series(x + noise)
1237
+ y2 = adjust_frequencies(y, filters=lambda f: np.abs(f) <= 0.02)
1238
+ result = get_frequency_spectrum(y2)
1239
+ check_polars_dataframe(
1240
+ result, height=n, schema_list={"frequency": Float64, "amplitude": Float64}
1241
+ )
1242
+ assert allclose(result.filter(col("frequency").abs() > 0.02)["amplitude"], 0.0)
1243
+
1244
+
1216
1245
  class TestGetSeriesNumberOfDecimals:
1217
1246
  @given(data=data(), n=hypothesis.strategies.integers(1, 10), nullable=booleans())
1218
1247
  def test_main(self, *, data: DataObject, n: int, nullable: bool) -> None:
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.109.16"
3
+ __version__ = "0.109.18"
@@ -14,12 +14,12 @@ from numpy import (
14
14
  digitize,
15
15
  dtype,
16
16
  errstate,
17
+ exp,
17
18
  flatnonzero,
18
- float64,
19
19
  floating,
20
20
  full_like,
21
21
  inf,
22
- int64,
22
+ integer,
23
23
  isclose,
24
24
  isfinite,
25
25
  isinf,
@@ -38,11 +38,13 @@ from numpy.linalg import det, eig
38
38
  from numpy.random import default_rng
39
39
  from numpy.typing import NDArray
40
40
 
41
- from utilities.iterables import is_iterable_not_str
41
+ from utilities.iterables import always_iterable, is_iterable_not_str
42
42
 
43
43
  if TYPE_CHECKING:
44
44
  from collections.abc import Callable, Iterable
45
45
 
46
+ from utilities.types import MaybeIterable
47
+
46
48
 
47
49
  ##
48
50
 
@@ -88,8 +90,9 @@ timedelta64as = dtype("timedelta64[as]")
88
90
 
89
91
  NDArrayA = NDArray[Any]
90
92
  NDArrayB = NDArray[bool_]
91
- NDArrayF = NDArray[float64]
92
- NDArrayI = NDArray[int64]
93
+ NDArrayC128 = NDArray[complex128]
94
+ NDArrayF = NDArray[floating[Any]]
95
+ NDArrayI = NDArray[integer[Any]]
93
96
  NDArrayO = NDArray[object_]
94
97
 
95
98
 
@@ -133,6 +136,65 @@ class AsIntError(Exception): ...
133
136
  ##
134
137
 
135
138
 
139
+ def boxcar(
140
+ array: NDArrayF,
141
+ /,
142
+ *,
143
+ loc_low: float = -1.0,
144
+ slope_low: float = 1.0,
145
+ loc_high: float = 1.0,
146
+ slope_high: float = 1.0,
147
+ rtol: float | None = None,
148
+ atol: float | None = None,
149
+ ) -> NDArrayF:
150
+ """Construct a boxcar function."""
151
+ if not is_at_most(loc_low, loc_high, rtol=rtol, atol=atol):
152
+ raise _BoxCarLocationsError(low=loc_low, high=loc_high)
153
+ if not is_positive(slope_low, rtol=rtol, atol=atol):
154
+ raise _BoxCarLowerBoundSlopeError(slope=slope_low)
155
+ if not is_positive(slope_high, rtol=rtol, atol=atol):
156
+ raise _BoxCarUpperBoundSlopeError(slope=slope_high)
157
+ return (
158
+ sigmoid(array, loc=loc_low, slope=slope_low)
159
+ + sigmoid(array, loc=loc_high, slope=-slope_high)
160
+ ) / 2
161
+
162
+
163
+ @dataclass(kw_only=True, slots=True)
164
+ class BoxCarError(Exception): ...
165
+
166
+
167
+ @dataclass(kw_only=True, slots=True)
168
+ class _BoxCarLocationsError(BoxCarError):
169
+ low: float
170
+ high: float
171
+
172
+ @override
173
+ def __str__(self) -> str:
174
+ return f"Location parameters must be consistent; got {self.low} and {self.high}"
175
+
176
+
177
+ @dataclass(kw_only=True, slots=True)
178
+ class _BoxCarLowerBoundSlopeError(BoxCarError):
179
+ slope: float
180
+
181
+ @override
182
+ def __str__(self) -> str:
183
+ return f"Lower-bound slope parameter must be positive; got {self.slope}"
184
+
185
+
186
+ @dataclass(kw_only=True, slots=True)
187
+ class _BoxCarUpperBoundSlopeError(BoxCarError):
188
+ slope: float
189
+
190
+ @override
191
+ def __str__(self) -> str:
192
+ return f"Upper-bound slope parameter must be positive; got {self.slope}"
193
+
194
+
195
+ ##
196
+
197
+
136
198
  def discretize(x: NDArrayF, bins: int | Iterable[float], /) -> NDArrayF:
137
199
  """Discretize an array of floats.
138
200
 
@@ -164,28 +226,43 @@ def fillna(array: NDArrayF, /, *, value: float = 0.0) -> NDArrayF:
164
226
  ##
165
227
 
166
228
 
167
- def filter_frequencies(
229
+ def adjust_frequencies(
168
230
  array: NDArrayF,
169
231
  /,
170
- *filters: Callable[[NDArray[floating[Any]]], NDArrayB],
232
+ *,
233
+ filters: MaybeIterable[Callable[[NDArrayF], NDArrayB]] | None = None,
234
+ weights: MaybeIterable[Callable[[NDArrayF], NDArrayF]] | None = None,
171
235
  d: int = 1,
172
236
  ) -> NDArrayF:
173
- """Filter an array by the frequencies of its FFT."""
237
+ """Adjust an array via its FFT frequencies."""
174
238
  (n,) = array.shape
175
- fft_vals = fft(array)
239
+ amplitudes = fft(array)
176
240
  freqs = fftfreq(n, d=d)
177
- reduced = reduce(partial(_filter_frequencies_one, freqs=freqs), filters, fft_vals)
178
- return ifft(reduced).real
241
+ if filters is not None:
242
+ amplitudes = reduce(
243
+ partial(_adjust_frequencies_filter_one, freqs=freqs),
244
+ always_iterable(filters),
245
+ amplitudes,
246
+ )
247
+ if weights is not None:
248
+ amplitudes = reduce(
249
+ partial(_adjust_frequencies_weight_one, freqs=freqs),
250
+ always_iterable(weights),
251
+ amplitudes,
252
+ )
253
+ return ifft(amplitudes).real
254
+
255
+
256
+ def _adjust_frequencies_filter_one(
257
+ acc: NDArrayC128, el: Callable[[NDArrayF], NDArrayB], /, *, freqs: NDArrayF
258
+ ) -> NDArrayC128:
259
+ return where(el(freqs), acc, 0.0)
179
260
 
180
261
 
181
- def _filter_frequencies_one(
182
- acc: NDArray[complex128],
183
- el: Callable[[NDArray[floating[Any]]], NDArrayB],
184
- /,
185
- *,
186
- freqs: NDArray[floating[Any]],
187
- ) -> NDArray[complex128]:
188
- return where(el(freqs), acc, 0.0)
262
+ def _adjust_frequencies_weight_one(
263
+ acc: NDArrayC128, el: Callable[[NDArrayF], NDArrayF], /, *, freqs: NDArrayF
264
+ ) -> NDArrayC128:
265
+ return acc * el(freqs)
189
266
 
190
267
 
191
268
  ##
@@ -224,12 +301,12 @@ class FlatN0MultipleError(FlatN0Error):
224
301
  ##
225
302
 
226
303
 
227
- def get_frequency_spectrum(array: NDArrayF, /, *, d: int = 1) -> NDArray[floating[Any]]:
304
+ def get_frequency_spectrum(array: NDArrayF, /, *, d: int = 1) -> NDArrayF:
228
305
  """Get the frequency spectrum."""
229
306
  (n,) = array.shape
230
- fft_vals = fft(array)
307
+ amplitudes = fft(array)
231
308
  freqs = fftfreq(n, d=d)
232
- amplitudes = np.abs(fft_vals)
309
+ amplitudes = np.abs(amplitudes)
233
310
  data = np.hstack([freqs.reshape(-1, 1), amplitudes.reshape(-1, 1)])
234
311
  return data[argsort(data[:, 0])]
235
312
 
@@ -847,6 +924,31 @@ def shift_bool(
847
924
  ##
848
925
 
849
926
 
927
+ def sigmoid(
928
+ array: NDArrayF,
929
+ /,
930
+ *,
931
+ loc: float = 0.0,
932
+ slope: float = 1.0,
933
+ rtol: float | None = None,
934
+ atol: float | None = None,
935
+ ) -> NDArrayF:
936
+ """Construct a sigmoid function."""
937
+ if is_zero(slope, rtol=rtol, atol=atol):
938
+ raise SigmoidError
939
+ return 1 / (1 + exp(-slope * (array - loc)))
940
+
941
+
942
+ @dataclass(kw_only=True, slots=True)
943
+ class SigmoidError(Exception):
944
+ @override
945
+ def __str__(self) -> str:
946
+ return "Slope must be non-zero"
947
+
948
+
949
+ ##
950
+
951
+
850
952
  def _is_close(
851
953
  x: Any,
852
954
  y: Any,
@@ -869,6 +971,7 @@ def _is_close(
869
971
  __all__ = [
870
972
  "DEFAULT_RNG",
871
973
  "AsIntError",
974
+ "BoxCarError",
872
975
  "FlatN0EmptyError",
873
976
  "FlatN0Error",
874
977
  "FlatN0MultipleError",
@@ -878,8 +981,11 @@ __all__ = [
878
981
  "NDArrayI",
879
982
  "NDArrayO",
880
983
  "ShiftError",
984
+ "SigmoidError",
985
+ "adjust_frequencies",
881
986
  "array_indexer",
882
987
  "as_int",
988
+ "boxcar",
883
989
  "datetime64D",
884
990
  "datetime64M",
885
991
  "datetime64W",
@@ -895,7 +1001,6 @@ __all__ = [
895
1001
  "datetime64us",
896
1002
  "discretize",
897
1003
  "fillna",
898
- "filter_frequencies",
899
1004
  "flatn0",
900
1005
  "get_frequency_spectrum",
901
1006
  "has_dtype",
@@ -948,4 +1053,5 @@ __all__ = [
948
1053
  "maximum",
949
1054
  "minimum",
950
1055
  "shift_bool",
1056
+ "sigmoid",
951
1057
  ]
@@ -119,6 +119,7 @@ if TYPE_CHECKING:
119
119
  TimeUnit, # pyright: ignore[reportPrivateImportUsage]
120
120
  )
121
121
 
122
+ from utilities.numpy import NDArrayB, NDArrayF
122
123
  from utilities.types import (
123
124
  Dataclass,
124
125
  MaybeIterable,
@@ -141,6 +142,27 @@ _FINITE_EWM_MIN_WEIGHT = 0.9999
141
142
  ##
142
143
 
143
144
 
145
+ def adjust_frequencies(
146
+ series: Series,
147
+ /,
148
+ *,
149
+ filters: MaybeIterable[Callable[[NDArrayF], NDArrayB]] | None = None,
150
+ weights: MaybeIterable[Callable[[NDArrayF], NDArrayF]] | None = None,
151
+ d: int = 1,
152
+ ) -> Series:
153
+ """Adjust a Series via its FFT frequencies."""
154
+ import utilities.numpy
155
+
156
+ array = series.to_numpy()
157
+ adjusted = utilities.numpy.adjust_frequencies(
158
+ array, filters=filters, weights=weights, d=d
159
+ )
160
+ return Series(name=series.name, values=adjusted, dtype=Float64)
161
+
162
+
163
+ ##
164
+
165
+
144
166
  def append_dataclass(df: DataFrame, obj: Dataclass, /) -> DataFrame:
145
167
  """Append a dataclass object to a DataFrame."""
146
168
  non_null_fields = {k: v for k, v in asdict(obj).items() if v is not None}
@@ -1027,6 +1049,20 @@ class _GetDataTypeOrSeriesTimeZoneNotZonedError(GetDataTypeOrSeriesTimeZoneError
1027
1049
  ##
1028
1050
 
1029
1051
 
1052
+ def get_frequency_spectrum(series: Series, /, *, d: int = 1) -> DataFrame:
1053
+ """Get the frequency spectrum."""
1054
+ import utilities.numpy
1055
+
1056
+ array = series.to_numpy()
1057
+ spectrum = utilities.numpy.get_frequency_spectrum(array, d=d)
1058
+ return DataFrame(
1059
+ data=spectrum, schema={"frequency": Float64, "amplitude": Float64}, orient="row"
1060
+ )
1061
+
1062
+
1063
+ ##
1064
+
1065
+
1030
1066
  @overload
1031
1067
  def get_series_number_of_decimals(
1032
1068
  series: Series, /, *, nullable: Literal[True]
@@ -1736,6 +1772,7 @@ __all__ = [
1736
1772
  "SetFirstRowAsColumnsError",
1737
1773
  "StructFromDataClassError",
1738
1774
  "YieldStructSeriesElementsError",
1775
+ "adjust_frequencies",
1739
1776
  "append_dataclass",
1740
1777
  "are_frames_equal",
1741
1778
  "ceil_datetime",
@@ -1753,6 +1790,7 @@ __all__ = [
1753
1790
  "finite_ewm_mean",
1754
1791
  "floor_datetime",
1755
1792
  "get_data_type_or_series_time_zone",
1793
+ "get_frequency_spectrum",
1756
1794
  "get_series_number_of_decimals",
1757
1795
  "insert_after",
1758
1796
  "insert_before",