dataframely 2.12.0__tar.gz → 2.13.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. {dataframely-2.12.0 → dataframely-2.13.1}/PKG-INFO +1 -1
  2. dataframely-2.13.1/dataframely/_deprecation.py +58 -0
  3. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/collection/collection.py +100 -6
  4. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/filter_result.py +11 -0
  5. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/schema.py +57 -0
  6. {dataframely-2.12.0 → dataframely-2.13.1}/docs/guides/features/serialization.md +22 -0
  7. {dataframely-2.12.0 → dataframely-2.13.1}/docs/guides/migration/index.md +5 -6
  8. {dataframely-2.12.0 → dataframely-2.13.1}/pyproject.toml +6 -3
  9. dataframely-2.13.1/tests/collection/test_skip_member_validation.py +108 -0
  10. dataframely-2.13.1/tests/test_deprecation.py +149 -0
  11. dataframely-2.12.0/dataframely/_deprecation.py +0 -27
  12. dataframely-2.12.0/tests/test_deprecation.py +0 -24
  13. {dataframely-2.12.0 → dataframely-2.13.1}/.claude/CLAUDE.md +0 -0
  14. {dataframely-2.12.0 → dataframely-2.13.1}/.copier-answers.yml +0 -0
  15. {dataframely-2.12.0 → dataframely-2.13.1}/.envrc +0 -0
  16. {dataframely-2.12.0 → dataframely-2.13.1}/.gitattributes +0 -0
  17. {dataframely-2.12.0 → dataframely-2.13.1}/.github/CODEOWNERS +0 -0
  18. {dataframely-2.12.0 → dataframely-2.13.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  19. {dataframely-2.12.0 → dataframely-2.13.1}/.github/copilot-instructions.md +0 -0
  20. {dataframely-2.12.0 → dataframely-2.13.1}/.github/dependabot.yml +0 -0
  21. {dataframely-2.12.0 → dataframely-2.13.1}/.github/instructions/tests.instructions.md +0 -0
  22. {dataframely-2.12.0 → dataframely-2.13.1}/.github/release-drafter.yml +0 -0
  23. {dataframely-2.12.0 → dataframely-2.13.1}/.github/workflows/build.yml +0 -0
  24. {dataframely-2.12.0 → dataframely-2.13.1}/.github/workflows/chore.yml +0 -0
  25. {dataframely-2.12.0 → dataframely-2.13.1}/.github/workflows/ci.yml +0 -0
  26. {dataframely-2.12.0 → dataframely-2.13.1}/.github/workflows/copilot-setup-steps.yml +0 -0
  27. {dataframely-2.12.0 → dataframely-2.13.1}/.github/workflows/nightly.yml +0 -0
  28. {dataframely-2.12.0 → dataframely-2.13.1}/.github/workflows/release-drafter.yml +0 -0
  29. {dataframely-2.12.0 → dataframely-2.13.1}/.github/workflows/scorecard.yml +0 -0
  30. {dataframely-2.12.0 → dataframely-2.13.1}/.gitignore +0 -0
  31. {dataframely-2.12.0 → dataframely-2.13.1}/.lefthook.yaml +0 -0
  32. {dataframely-2.12.0 → dataframely-2.13.1}/.prettierignore +0 -0
  33. {dataframely-2.12.0 → dataframely-2.13.1}/.prettierrc +0 -0
  34. {dataframely-2.12.0 → dataframely-2.13.1}/.readthedocs.yml +0 -0
  35. {dataframely-2.12.0 → dataframely-2.13.1}/AGENTS.md +0 -0
  36. {dataframely-2.12.0 → dataframely-2.13.1}/Cargo.lock +0 -0
  37. {dataframely-2.12.0 → dataframely-2.13.1}/Cargo.toml +0 -0
  38. {dataframely-2.12.0 → dataframely-2.13.1}/LICENSE +0 -0
  39. {dataframely-2.12.0 → dataframely-2.13.1}/README.md +0 -0
  40. {dataframely-2.12.0 → dataframely-2.13.1}/SECURITY.md +0 -0
  41. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/__init__.py +0 -0
  42. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_base_schema.py +0 -0
  43. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_compat.py +0 -0
  44. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_filter.py +0 -0
  45. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_match_to_schema.py +0 -0
  46. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_native.pyi +0 -0
  47. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_plugin.py +0 -0
  48. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_polars.py +0 -0
  49. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_pydantic.py +0 -0
  50. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_rule.py +0 -0
  51. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_serialization.py +0 -0
  52. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_storage/__init__.py +0 -0
  53. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_storage/_base.py +0 -0
  54. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_storage/_exc.py +0 -0
  55. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_storage/_fsspec.py +0 -0
  56. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_storage/constants.py +0 -0
  57. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_storage/delta.py +0 -0
  58. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_storage/parquet.py +0 -0
  59. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/_typing.py +0 -0
  60. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/collection/__init__.py +0 -0
  61. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/collection/_base.py +0 -0
  62. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/collection/filter_result.py +0 -0
  63. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/__init__.py +0 -0
  64. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/_base.py +0 -0
  65. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/_mixins.py +0 -0
  66. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/_registry.py +0 -0
  67. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/_utils.py +0 -0
  68. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/any.py +0 -0
  69. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/array.py +0 -0
  70. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/binary.py +0 -0
  71. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/bool.py +0 -0
  72. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/categorical.py +0 -0
  73. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/datetime.py +0 -0
  74. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/decimal.py +0 -0
  75. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/enum.py +0 -0
  76. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/float.py +0 -0
  77. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/integer.py +0 -0
  78. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/list.py +0 -0
  79. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/object.py +0 -0
  80. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/string.py +0 -0
  81. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/columns/struct.py +0 -0
  82. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/config.py +0 -0
  83. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/exc.py +0 -0
  84. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/experimental/__init__.py +0 -0
  85. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/experimental/infer_schema.py +0 -0
  86. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/functional.py +0 -0
  87. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/py.typed +0 -0
  88. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/random.py +0 -0
  89. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/testing/__init__.py +0 -0
  90. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/testing/const.py +0 -0
  91. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/testing/factory.py +0 -0
  92. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/testing/mask.py +0 -0
  93. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/testing/rules.py +0 -0
  94. {dataframely-2.12.0 → dataframely-2.13.1}/dataframely/testing/storage.py +0 -0
  95. {dataframely-2.12.0 → dataframely-2.13.1}/docker-compose.yml +0 -0
  96. {dataframely-2.12.0 → dataframely-2.13.1}/docs/_static/custom.css +0 -0
  97. {dataframely-2.12.0 → dataframely-2.13.1}/docs/_static/favicon.ico +0 -0
  98. {dataframely-2.12.0 → dataframely-2.13.1}/docs/_templates/autosummary/class.rst +0 -0
  99. {dataframely-2.12.0 → dataframely-2.13.1}/docs/_templates/autosummary/method.rst +0 -0
  100. {dataframely-2.12.0 → dataframely-2.13.1}/docs/_templates/classes/column.rst +0 -0
  101. {dataframely-2.12.0 → dataframely-2.13.1}/docs/_templates/classes/error.rst +0 -0
  102. {dataframely-2.12.0 → dataframely-2.13.1}/docs/_templates/classes/filter_result.rst +0 -0
  103. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/collection/generation.rst +0 -0
  104. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/collection/index.rst +0 -0
  105. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/collection/io.rst +0 -0
  106. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/collection/metadata.rst +0 -0
  107. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/collection/operations.rst +0 -0
  108. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/collection/validation.rst +0 -0
  109. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/columns/index.rst +0 -0
  110. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/errors/index.rst +0 -0
  111. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/experimental/index.rst +0 -0
  112. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/filter_result/failure_info.rst +0 -0
  113. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/filter_result/index.rst +0 -0
  114. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/index.rst +0 -0
  115. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/misc/index.rst +0 -0
  116. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/schema/conversion.rst +0 -0
  117. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/schema/generation.rst +0 -0
  118. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/schema/index.rst +0 -0
  119. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/schema/io.rst +0 -0
  120. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/schema/metadata.rst +0 -0
  121. {dataframely-2.12.0 → dataframely-2.13.1}/docs/api/schema/validation.rst +0 -0
  122. {dataframely-2.12.0 → dataframely-2.13.1}/docs/conf.py +0 -0
  123. {dataframely-2.12.0 → dataframely-2.13.1}/docs/css/custom.css +0 -0
  124. {dataframely-2.12.0 → dataframely-2.13.1}/docs/guides/coding-agents.md +0 -0
  125. {dataframely-2.12.0 → dataframely-2.13.1}/docs/guides/development.md +0 -0
  126. {dataframely-2.12.0 → dataframely-2.13.1}/docs/guides/examples/index.md +0 -0
  127. {dataframely-2.12.0 → dataframely-2.13.1}/docs/guides/examples/real-world.ipynb +0 -0
  128. {dataframely-2.12.0 → dataframely-2.13.1}/docs/guides/faq.md +0 -0
  129. {dataframely-2.12.0 → dataframely-2.13.1}/docs/guides/features/column-metadata.md +0 -0
  130. {dataframely-2.12.0 → dataframely-2.13.1}/docs/guides/features/data-generation.md +0 -0
  131. {dataframely-2.12.0 → dataframely-2.13.1}/docs/guides/features/index.md +0 -0
  132. {dataframely-2.12.0 → dataframely-2.13.1}/docs/guides/features/lazy-validation.md +0 -0
  133. {dataframely-2.12.0 → dataframely-2.13.1}/docs/guides/features/primary-keys.md +0 -0
  134. {dataframely-2.12.0 → dataframely-2.13.1}/docs/guides/features/sql-generation.md +0 -0
  135. {dataframely-2.12.0 → dataframely-2.13.1}/docs/guides/index.md +0 -0
  136. {dataframely-2.12.0 → dataframely-2.13.1}/docs/guides/migration/v1-v2.md +0 -0
  137. {dataframely-2.12.0 → dataframely-2.13.1}/docs/guides/quickstart.md +0 -0
  138. {dataframely-2.12.0 → dataframely-2.13.1}/docs/index.md +0 -0
  139. {dataframely-2.12.0 → dataframely-2.13.1}/pixi.lock +0 -0
  140. {dataframely-2.12.0 → dataframely-2.13.1}/pixi.toml +0 -0
  141. {dataframely-2.12.0 → dataframely-2.13.1}/rust-toolchain.toml +0 -0
  142. {dataframely-2.12.0 → dataframely-2.13.1}/skills/SKILL.md +0 -0
  143. {dataframely-2.12.0 → dataframely-2.13.1}/src/lib.rs +0 -0
  144. {dataframely-2.12.0 → dataframely-2.13.1}/src/polars_plugin/mod.rs +0 -0
  145. {dataframely-2.12.0 → dataframely-2.13.1}/src/polars_plugin/rule_failure.rs +0 -0
  146. {dataframely-2.12.0 → dataframely-2.13.1}/src/polars_plugin/utils.rs +0 -0
  147. {dataframely-2.12.0 → dataframely-2.13.1}/src/polars_plugin/validation_error.rs +0 -0
  148. {dataframely-2.12.0 → dataframely-2.13.1}/src/regex/errdefs.rs +0 -0
  149. {dataframely-2.12.0 → dataframely-2.13.1}/src/regex/mod.rs +0 -0
  150. {dataframely-2.12.0 → dataframely-2.13.1}/src/regex/repr.rs +0 -0
  151. {dataframely-2.12.0 → dataframely-2.13.1}/tests/benches/conftest.py +0 -0
  152. {dataframely-2.12.0 → dataframely-2.13.1}/tests/benches/test_collection.py +0 -0
  153. {dataframely-2.12.0 → dataframely-2.13.1}/tests/benches/test_failure.py +0 -0
  154. {dataframely-2.12.0 → dataframely-2.13.1}/tests/benches/test_schema.py +0 -0
  155. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_base.py +0 -0
  156. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_cast.py +0 -0
  157. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_collection_future_annotations.py +0 -0
  158. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_create_empty.py +0 -0
  159. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_dataframe_members.py +0 -0
  160. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_filter_one_to_n.py +0 -0
  161. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_filter_validate.py +0 -0
  162. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_ignore_in_filter.py +0 -0
  163. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_implementation.py +0 -0
  164. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_join.py +0 -0
  165. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_matches.py +0 -0
  166. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_optional_members.py +0 -0
  167. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_pipe.py +0 -0
  168. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_propagate_row_failures.py +0 -0
  169. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_repr.py +0 -0
  170. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_sample.py +0 -0
  171. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_serialization.py +0 -0
  172. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_storage.py +0 -0
  173. {dataframely-2.12.0 → dataframely-2.13.1}/tests/collection/test_validate_input.py +0 -0
  174. {dataframely-2.12.0 → dataframely-2.13.1}/tests/column_types/__init__.py +0 -0
  175. {dataframely-2.12.0 → dataframely-2.13.1}/tests/column_types/test_any.py +0 -0
  176. {dataframely-2.12.0 → dataframely-2.13.1}/tests/column_types/test_array.py +0 -0
  177. {dataframely-2.12.0 → dataframely-2.13.1}/tests/column_types/test_binary.py +0 -0
  178. {dataframely-2.12.0 → dataframely-2.13.1}/tests/column_types/test_datetime.py +0 -0
  179. {dataframely-2.12.0 → dataframely-2.13.1}/tests/column_types/test_decimal.py +0 -0
  180. {dataframely-2.12.0 → dataframely-2.13.1}/tests/column_types/test_enum.py +0 -0
  181. {dataframely-2.12.0 → dataframely-2.13.1}/tests/column_types/test_float.py +0 -0
  182. {dataframely-2.12.0 → dataframely-2.13.1}/tests/column_types/test_integer.py +0 -0
  183. {dataframely-2.12.0 → dataframely-2.13.1}/tests/column_types/test_list.py +0 -0
  184. {dataframely-2.12.0 → dataframely-2.13.1}/tests/column_types/test_object.py +0 -0
  185. {dataframely-2.12.0 → dataframely-2.13.1}/tests/column_types/test_string.py +0 -0
  186. {dataframely-2.12.0 → dataframely-2.13.1}/tests/column_types/test_struct.py +0 -0
  187. {dataframely-2.12.0 → dataframely-2.13.1}/tests/columns/__init__.py +0 -0
  188. {dataframely-2.12.0 → dataframely-2.13.1}/tests/columns/test_alias.py +0 -0
  189. {dataframely-2.12.0 → dataframely-2.13.1}/tests/columns/test_base.py +0 -0
  190. {dataframely-2.12.0 → dataframely-2.13.1}/tests/columns/test_check.py +0 -0
  191. {dataframely-2.12.0 → dataframely-2.13.1}/tests/columns/test_default_dtypes.py +0 -0
  192. {dataframely-2.12.0 → dataframely-2.13.1}/tests/columns/test_description.py +0 -0
  193. {dataframely-2.12.0 → dataframely-2.13.1}/tests/columns/test_matches.py +0 -0
  194. {dataframely-2.12.0 → dataframely-2.13.1}/tests/columns/test_metadata.py +0 -0
  195. {dataframely-2.12.0 → dataframely-2.13.1}/tests/columns/test_polars_schema.py +0 -0
  196. {dataframely-2.12.0 → dataframely-2.13.1}/tests/columns/test_pyarrow.py +0 -0
  197. {dataframely-2.12.0 → dataframely-2.13.1}/tests/columns/test_pydantic.py +0 -0
  198. {dataframely-2.12.0 → dataframely-2.13.1}/tests/columns/test_rules.py +0 -0
  199. {dataframely-2.12.0 → dataframely-2.13.1}/tests/columns/test_sample.py +0 -0
  200. {dataframely-2.12.0 → dataframely-2.13.1}/tests/columns/test_sqlalchemy_columns.py +0 -0
  201. {dataframely-2.12.0 → dataframely-2.13.1}/tests/columns/test_str.py +0 -0
  202. {dataframely-2.12.0 → dataframely-2.13.1}/tests/columns/test_utils.py +0 -0
  203. {dataframely-2.12.0 → dataframely-2.13.1}/tests/conftest.py +0 -0
  204. {dataframely-2.12.0 → dataframely-2.13.1}/tests/core_validation/__init__.py +0 -0
  205. {dataframely-2.12.0 → dataframely-2.13.1}/tests/core_validation/test_match_to_schema.py +0 -0
  206. {dataframely-2.12.0 → dataframely-2.13.1}/tests/core_validation/test_rule_evaluation.py +0 -0
  207. {dataframely-2.12.0 → dataframely-2.13.1}/tests/experimental/test_infer_schema.py +0 -0
  208. {dataframely-2.12.0 → dataframely-2.13.1}/tests/failure_info/test_storage.py +0 -0
  209. {dataframely-2.12.0 → dataframely-2.13.1}/tests/functional/test_concat.py +0 -0
  210. {dataframely-2.12.0 → dataframely-2.13.1}/tests/functional/test_relationships.py +0 -0
  211. {dataframely-2.12.0 → dataframely-2.13.1}/tests/schema/test_base.py +0 -0
  212. {dataframely-2.12.0 → dataframely-2.13.1}/tests/schema/test_cast.py +0 -0
  213. {dataframely-2.12.0 → dataframely-2.13.1}/tests/schema/test_create_empty.py +0 -0
  214. {dataframely-2.12.0 → dataframely-2.13.1}/tests/schema/test_create_empty_if_none.py +0 -0
  215. {dataframely-2.12.0 → dataframely-2.13.1}/tests/schema/test_filter.py +0 -0
  216. {dataframely-2.12.0 → dataframely-2.13.1}/tests/schema/test_inheritance.py +0 -0
  217. {dataframely-2.12.0 → dataframely-2.13.1}/tests/schema/test_matches.py +0 -0
  218. {dataframely-2.12.0 → dataframely-2.13.1}/tests/schema/test_pydantic_model.py +0 -0
  219. {dataframely-2.12.0 → dataframely-2.13.1}/tests/schema/test_read_write_parquet.py +0 -0
  220. {dataframely-2.12.0 → dataframely-2.13.1}/tests/schema/test_repr.py +0 -0
  221. {dataframely-2.12.0 → dataframely-2.13.1}/tests/schema/test_rule_implementation.py +0 -0
  222. {dataframely-2.12.0 → dataframely-2.13.1}/tests/schema/test_sample.py +0 -0
  223. {dataframely-2.12.0 → dataframely-2.13.1}/tests/schema/test_serialization.py +0 -0
  224. {dataframely-2.12.0 → dataframely-2.13.1}/tests/schema/test_storage.py +0 -0
  225. {dataframely-2.12.0 → dataframely-2.13.1}/tests/schema/test_validate.py +0 -0
  226. {dataframely-2.12.0 → dataframely-2.13.1}/tests/storage/test_delta.py +0 -0
  227. {dataframely-2.12.0 → dataframely-2.13.1}/tests/storage/test_fsspec.py +0 -0
  228. {dataframely-2.12.0 → dataframely-2.13.1}/tests/test_compat.py +0 -0
  229. {dataframely-2.12.0 → dataframely-2.13.1}/tests/test_config.py +0 -0
  230. {dataframely-2.12.0 → dataframely-2.13.1}/tests/test_factory.py +0 -0
  231. {dataframely-2.12.0 → dataframely-2.13.1}/tests/test_native_regex.py +0 -0
  232. {dataframely-2.12.0 → dataframely-2.13.1}/tests/test_pydantic.py +0 -0
  233. {dataframely-2.12.0 → dataframely-2.13.1}/tests/test_random.py +0 -0
  234. {dataframely-2.12.0 → dataframely-2.13.1}/tests/test_serialization.py +0 -0
  235. {dataframely-2.12.0 → dataframely-2.13.1}/tests/test_typing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataframely
3
- Version: 2.12.0
3
+ Version: 2.13.1
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3.10
6
6
  Classifier: Programming Language :: Python :: 3.11
@@ -0,0 +1,58 @@
1
+ # Copyright (c) QuantCo 2025-2026
2
+ # SPDX-License-Identifier: BSD-3-Clause
3
+
4
+ from __future__ import annotations
5
+
6
+ import sys
7
+ import warnings
8
+ from functools import wraps
9
+ from typing import TYPE_CHECKING, TypeVar
10
+
11
+ if TYPE_CHECKING:
12
+ from collections.abc import Callable
13
+ from typing import ParamSpec
14
+
15
+ P = ParamSpec("P")
16
+ T = TypeVar("T")
17
+
18
+
19
+ def issue_deprecation_warning(message: str, *, version: str = "") -> None:
20
+ """Issue a deprecation warning pointing at the caller of the deprecated method.
21
+
22
+ This must be called directly from the body of the deprecated (public) method so
23
+ that the warning points at the user's code rather than at dataframely internals.
24
+
25
+ Args:
26
+ message: The message associated with the warning.
27
+ version: The dataframely version in which the deprecation occurred (if not
28
+ already part of ``message``).
29
+ """
30
+ if version:
31
+ message = f"{message.strip()}\n(Deprecated in dataframely {version})"
32
+ # `stacklevel=2` blames the caller of the deprecated method (one frame up from this
33
+ # function). All call sites invoke this directly from the deprecated method body.
34
+ warnings.warn(message, DeprecationWarning, stacklevel=2)
35
+
36
+
37
+ if sys.version_info >= (3, 13):
38
+ from warnings import deprecated
39
+ else:
40
+ try:
41
+ from typing_extensions import deprecated
42
+ except ImportError: # pragma: no cover
43
+
44
+ def deprecated( # type: ignore[no-redef]
45
+ message: str,
46
+ ) -> Callable[[Callable[P, T]], Callable[P, T]]:
47
+ """Fallback for :func:`warnings.deprecated` without :pep:`702` support."""
48
+
49
+ def decorate(function: Callable[P, T]) -> Callable[P, T]:
50
+ @wraps(function)
51
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
52
+ issue_deprecation_warning(message)
53
+ return function(*args, **kwargs)
54
+
55
+ wrapper.__deprecated__ = message # type: ignore[attr-defined]
56
+ return wrapper
57
+
58
+ return decorate
@@ -28,6 +28,7 @@ import polars as pl
28
28
  import polars.exceptions as plexc
29
29
 
30
30
  from dataframely._compat import deltalake
31
+ from dataframely._deprecation import deprecated, issue_deprecation_warning
31
32
  from dataframely._filter import Filter
32
33
  from dataframely._native import format_rule_failures
33
34
  from dataframely._plugin import all_rules_required
@@ -63,6 +64,15 @@ else:
63
64
 
64
65
  _FILTER_COLUMN_PREFIX = "__DATAFRAMELY_FILTER_COLUMN__"
65
66
 
67
+ #: Deprecation message emitted when reading a collection with implicit validation, i.e.
68
+ #: with any ``validation`` other than ``"skip"`` (see #367).
69
+ _IMPLICIT_VALIDATION_DEPRECATION = (
70
+ "Reading a collection with `validation != 'skip'` is deprecated. Starting with "
71
+ "dataframely v3, data is read without inspecting schema metadata and without "
72
+ "running validation. Pass `validation='skip'` to opt into the future behavior, or "
73
+ "call `validate` explicitly if you require validation."
74
+ )
75
+
66
76
  P = ParamSpec("P")
67
77
  T = TypeVar("T")
68
78
 
@@ -386,6 +396,7 @@ class Collection(BaseCollection, ABC):
386
396
  *,
387
397
  cast: bool = False,
388
398
  eager: bool = True,
399
+ skip_member_validation: bool = False,
389
400
  **kwargs: Any,
390
401
  ) -> Self:
391
402
  """Validate that a set of data frames satisfy the collection's invariants.
@@ -406,6 +417,11 @@ class Collection(BaseCollection, ABC):
406
417
  :meth:`~polars.LazyFrame.collect` on the individual member or
407
418
  :meth:`collect_all` on the collection. Note that, in the latter case,
408
419
  information from error messages is limited.
420
+ skip_member_validation: Whether to skip validating individual members and only
421
+ apply the collection filters. **Use this option with caution** as it
422
+ requires the caller to ensure that the individual members have been
423
+ validated. This option is particularly useful in performance-critical
424
+ scenarios where the members are known to be valid.
409
425
  kwargs: Keyword arguments passed directly to :meth:`polars.collect_all` and
410
426
  :meth:`polars.LazyFrame.collect` when `eager=True`.
411
427
 
@@ -429,7 +445,13 @@ class Collection(BaseCollection, ABC):
429
445
  if eager:
430
446
  # If we perform the validation eagerly, we call filter and check the failure
431
447
  # information to properly construct a useful error message.
432
- filtered, failures = cls.filter(data, cast=cast, eager=True, **kwargs)
448
+ filtered, failures = cls.filter(
449
+ data,
450
+ cast=cast,
451
+ eager=True,
452
+ skip_member_validation=skip_member_validation,
453
+ **kwargs,
454
+ )
433
455
  if any(len(failure) > 0 for failure in failures.values()):
434
456
  errors: dict[str, str] = {}
435
457
  for member, failure in failures.items():
@@ -460,7 +482,17 @@ class Collection(BaseCollection, ABC):
460
482
  # efficiently as we cannot easily propagate error messages from different
461
483
  # members anyways.
462
484
  members: dict[str, pl.LazyFrame] = {
463
- name: member.schema.validate(data[name].lazy(), cast=cast, eager=False)
485
+ name: (
486
+ (
487
+ member.schema.cast(data[name].lazy())
488
+ if cast
489
+ else data[name].lazy()
490
+ )
491
+ if skip_member_validation
492
+ else member.schema.validate(
493
+ data[name].lazy(), cast=cast, eager=False
494
+ )
495
+ )
464
496
  for name, member in cls.members().items()
465
497
  if name in data
466
498
  }
@@ -556,6 +588,7 @@ class Collection(BaseCollection, ABC):
556
588
  *,
557
589
  cast: bool = False,
558
590
  eager: bool = True,
591
+ skip_member_validation: bool = False,
559
592
  **kwargs: Any,
560
593
  ) -> CollectionFilterResult[Self]:
561
594
  """Filter the members data frame by their schemas and the collection's filters.
@@ -572,6 +605,11 @@ class Collection(BaseCollection, ABC):
572
605
  eager: Whether the filter operation should be performed eagerly.
573
606
  Note that until https://github.com/pola-rs/polars/pull/24129 is
574
607
  released, eagerly filtering can provide significant speedups.
608
+ skip_member_validation: Whether to skip filtering individual members and only
609
+ apply the collection filters. **Use this option with caution** as it
610
+ requires the caller to ensure that the individual members have been
611
+ validated. This option is particularly useful in performance-critical
612
+ scenarios where the members are known to already be valid.
575
613
  kwargs: Keyword arguments passed directly to :meth:`polars.collect_all` and
576
614
  :meth:`polars.LazyFrame.collect` when `eager=True`.
577
615
 
@@ -615,10 +653,20 @@ class Collection(BaseCollection, ABC):
615
653
  if member.is_optional and member_name not in data:
616
654
  continue
617
655
 
618
- member_result, failures[member_name] = member.schema.filter(
619
- data[member_name].lazy(), cast=cast, eager=eager, **kwargs
620
- )
621
- results[member_name] = member_result.lazy()
656
+ if skip_member_validation:
657
+ results[member_name] = (
658
+ member.schema.cast(data[member_name].lazy())
659
+ if cast
660
+ else data[member_name].lazy()
661
+ )
662
+ failures[member_name] = FailureInfo._create_empty(
663
+ member.schema, with_casting_rules=cast
664
+ )
665
+ else:
666
+ member_result, failures[member_name] = member.schema.filter(
667
+ data[member_name].lazy(), cast=cast, eager=eager, **kwargs
668
+ )
669
+ results[member_name] = member_result.lazy()
622
670
 
623
671
  # Once we've done that, we can apply the filters on this collection. To this end,
624
672
  # we iterate over all filters and store the filter results.
@@ -1023,7 +1071,16 @@ class Collection(BaseCollection, ABC):
1023
1071
  Attention:
1024
1072
  Be aware that this method suffers from the same limitations as
1025
1073
  :meth:`serialize`.
1074
+
1075
+ .. deprecated:: 3.0.0
1076
+ Reading with `validation != "skip"` is deprecated. Starting with
1077
+ dataframely v3, this method reads the data without inspecting any schema
1078
+ metadata and without running validation. Pass `validation="skip"` to opt
1079
+ into this behavior, or call :meth:`validate` explicitly if you require
1080
+ validation.
1026
1081
  """
1082
+ if validation != "skip":
1083
+ issue_deprecation_warning(_IMPLICIT_VALIDATION_DEPRECATION)
1027
1084
  return cls._read(
1028
1085
  backend=ParquetStorageBackend(),
1029
1086
  validation=validation,
@@ -1080,7 +1137,16 @@ class Collection(BaseCollection, ABC):
1080
1137
  Attention:
1081
1138
  Be aware that this method suffers from the same limitations as
1082
1139
  :meth:`serialize`.
1140
+
1141
+ .. deprecated:: 3.0.0
1142
+ Reading with `validation != "skip"` is deprecated. Starting with
1143
+ dataframely v3, this method reads the data without inspecting any schema
1144
+ metadata and without running validation. Pass `validation="skip"` to opt
1145
+ into this behavior, or call :meth:`validate` explicitly if you require
1146
+ validation.
1083
1147
  """
1148
+ if validation != "skip":
1149
+ issue_deprecation_warning(_IMPLICIT_VALIDATION_DEPRECATION)
1084
1150
  return cls._read(
1085
1151
  backend=ParquetStorageBackend(),
1086
1152
  validation=validation,
@@ -1089,6 +1155,10 @@ class Collection(BaseCollection, ABC):
1089
1155
  **kwargs,
1090
1156
  )
1091
1157
 
1158
+ @deprecated(
1159
+ "`Collection.write_delta` is deprecated and will be removed in dataframely v3. "
1160
+ "Write the individual members with `polars.DataFrame.write_delta` instead."
1161
+ )
1092
1162
  def write_delta(
1093
1163
  self, target: str | Path | deltalake.DeltaTable, **kwargs: Any
1094
1164
  ) -> None:
@@ -1115,6 +1185,10 @@ class Collection(BaseCollection, ABC):
1115
1185
  break your schema.
1116
1186
 
1117
1187
  This method suffers from the same limitations as :meth:`~dataframely.Schema.serialize`.
1188
+
1189
+ .. deprecated:: 3.0.0
1190
+ This method is deprecated and will be removed in dataframely v3. Write the
1191
+ individual members with :meth:`polars.DataFrame.write_delta` instead.
1118
1192
  """
1119
1193
  self._write(
1120
1194
  backend=DeltaStorageBackend(),
@@ -1123,6 +1197,11 @@ class Collection(BaseCollection, ABC):
1123
1197
  )
1124
1198
 
1125
1199
  @classmethod
1200
+ @deprecated(
1201
+ "`Collection.scan_delta` is deprecated and will be removed in dataframely v3. "
1202
+ "Read the individual members with `polars.scan_delta` and call `validate` "
1203
+ "explicitly instead."
1204
+ )
1126
1205
  def scan_delta(
1127
1206
  cls,
1128
1207
  source: str | Path | deltalake.DeltaTable,
@@ -1176,6 +1255,11 @@ class Collection(BaseCollection, ABC):
1176
1255
  break your schema.
1177
1256
 
1178
1257
  Be aware that this method suffers from the same limitations as :meth:`serialize`.
1258
+
1259
+ .. deprecated:: 3.0.0
1260
+ This method is deprecated and will be removed in dataframely v3. Read the
1261
+ individual members with :meth:`polars.scan_delta` and call :meth:`validate`
1262
+ explicitly instead.
1179
1263
  """
1180
1264
  return cls._read(
1181
1265
  backend=DeltaStorageBackend(),
@@ -1185,6 +1269,11 @@ class Collection(BaseCollection, ABC):
1185
1269
  )
1186
1270
 
1187
1271
  @classmethod
1272
+ @deprecated(
1273
+ "`Collection.read_delta` is deprecated and will be removed in dataframely v3. "
1274
+ "Read the individual members with `polars.read_delta` and call `validate` "
1275
+ "explicitly instead."
1276
+ )
1188
1277
  def read_delta(
1189
1278
  cls,
1190
1279
  source: str | Path | deltalake.DeltaTable,
@@ -1237,6 +1326,11 @@ class Collection(BaseCollection, ABC):
1237
1326
  break your schema.
1238
1327
 
1239
1328
  Be aware that this method suffers from the same limitations as :meth:`serialize`.
1329
+
1330
+ .. deprecated:: 3.0.0
1331
+ This method is deprecated and will be removed in dataframely v3. Read the
1332
+ individual members with :meth:`polars.read_delta` and call :meth:`validate`
1333
+ explicitly instead.
1240
1334
  """
1241
1335
  return cls._read(
1242
1336
  backend=DeltaStorageBackend(),
@@ -106,6 +106,17 @@ class FailureInfo(Generic[S]):
106
106
  self._rule_columns = rule_columns
107
107
  self.schema = schema
108
108
 
109
+ @classmethod
110
+ def _create_empty(cls, schema: type[S], with_casting_rules: bool) -> FailureInfo[S]:
111
+ rules = schema._validation_rules(with_cast=with_casting_rules)
112
+ lf = pl.LazyFrame(
113
+ schema={
114
+ **schema.to_polars_schema(), # type: ignore
115
+ **{rule: pl.Boolean for rule in rules},
116
+ }
117
+ )
118
+ return cls(lf=lf, rule_columns=list(rules.keys()), schema=schema)
119
+
109
120
  @cached_property
110
121
  def _df(self) -> pl.DataFrame:
111
122
  return self._lf.collect()
@@ -18,6 +18,7 @@ from polars._typing import FileSource
18
18
 
19
19
  from ._base_schema import ORIGINAL_COLUMN_PREFIX, BaseSchema
20
20
  from ._compat import PartitionSchemeOrSinkDirectory, deltalake, pa, pydantic, sa
21
+ from ._deprecation import deprecated
21
22
  from ._match_to_schema import match_to_schema
22
23
  from ._native import format_rule_failures
23
24
  from ._plugin import all_rules, all_rules_horizontal, all_rules_required
@@ -897,6 +898,10 @@ class Schema(BaseSchema, ABC):
897
898
  # ------------------------------------ PARQUET ----------------------------------- #
898
899
 
899
900
  @classmethod
901
+ @deprecated(
902
+ "`Schema.write_parquet` is deprecated and will be removed in dataframely v3. "
903
+ "Use `polars.DataFrame.write_parquet` directly instead."
904
+ )
900
905
  def write_parquet(
901
906
  cls, df: DataFrame[Self], /, file: str | Path | IO[bytes], **kwargs: Any
902
907
  ) -> None:
@@ -919,10 +924,18 @@ class Schema(BaseSchema, ABC):
919
924
  Attention:
920
925
  Be aware that this method suffers from the same limitations as
921
926
  :meth:`serialize`.
927
+
928
+ .. deprecated:: 3.0.0
929
+ This method is deprecated and will be removed in dataframely v3. Use
930
+ :meth:`polars.DataFrame.write_parquet` directly instead.
922
931
  """
923
932
  cls._write(df=df, backend=ParquetStorageBackend(), file=file, **kwargs)
924
933
 
925
934
  @classmethod
935
+ @deprecated(
936
+ "`Schema.sink_parquet` is deprecated and will be removed in dataframely v3. "
937
+ "Use `polars.LazyFrame.sink_parquet` directly instead."
938
+ )
926
939
  def sink_parquet(
927
940
  cls,
928
941
  lf: LazyFrame[Self],
@@ -947,10 +960,18 @@ class Schema(BaseSchema, ABC):
947
960
  Attention:
948
961
  Be aware that this method suffers from the same limitations as
949
962
  :meth:`serialize`.
963
+
964
+ .. deprecated:: 3.0.0
965
+ This method is deprecated and will be removed in dataframely v3. Use
966
+ :meth:`polars.LazyFrame.sink_parquet` directly instead.
950
967
  """
951
968
  cls._sink(lf=lf, backend=ParquetStorageBackend(), file=file, **kwargs)
952
969
 
953
970
  @classmethod
971
+ @deprecated(
972
+ "`Schema.read_parquet` is deprecated and will be removed in dataframely v3. "
973
+ "Use `polars.read_parquet` and call `validate` explicitly instead."
974
+ )
954
975
  def read_parquet(
955
976
  cls,
956
977
  source: FileSource,
@@ -997,6 +1018,10 @@ class Schema(BaseSchema, ABC):
997
1018
  Attention:
998
1019
  Be aware that this method suffers from the same limitations as
999
1020
  :meth:`serialize`.
1021
+
1022
+ .. deprecated:: 3.0.0
1023
+ This method is deprecated and will be removed in dataframely v3. Use
1024
+ :meth:`polars.read_parquet` and call :meth:`validate` explicitly instead.
1000
1025
  """
1001
1026
  return cls._read(
1002
1027
  ParquetStorageBackend(),
@@ -1007,6 +1032,10 @@ class Schema(BaseSchema, ABC):
1007
1032
  )
1008
1033
 
1009
1034
  @classmethod
1035
+ @deprecated(
1036
+ "`Schema.scan_parquet` is deprecated and will be removed in dataframely v3. "
1037
+ "Use `polars.scan_parquet` and call `validate` explicitly instead."
1038
+ )
1010
1039
  def scan_parquet(
1011
1040
  cls,
1012
1041
  source: FileSource,
@@ -1053,6 +1082,10 @@ class Schema(BaseSchema, ABC):
1053
1082
  Attention:
1054
1083
  Be aware that this method suffers from the same limitations as
1055
1084
  :meth:`serialize`.
1085
+
1086
+ .. deprecated:: 3.0.0
1087
+ This method is deprecated and will be removed in dataframely v3. Use
1088
+ :meth:`polars.scan_parquet` and call :meth:`validate` explicitly instead.
1056
1089
  """
1057
1090
  return cls._read(
1058
1091
  ParquetStorageBackend(),
@@ -1099,6 +1132,10 @@ class Schema(BaseSchema, ABC):
1099
1132
 
1100
1133
  # --------------------------------- Delta -----------------------------------------#
1101
1134
  @classmethod
1135
+ @deprecated(
1136
+ "`Schema.write_delta` is deprecated and will be removed in dataframely v3. "
1137
+ "Use `polars.DataFrame.write_delta` directly instead."
1138
+ )
1102
1139
  def write_delta(
1103
1140
  cls,
1104
1141
  df: DataFrame[Self],
@@ -1127,6 +1164,10 @@ class Schema(BaseSchema, ABC):
1127
1164
  in violation of group constraints that dataframely cannot catch
1128
1165
  without re-validating. Only use appends if you are certain that they do not
1129
1166
  break your schema.
1167
+
1168
+ .. deprecated:: 3.0.0
1169
+ This method is deprecated and will be removed in dataframely v3. Use
1170
+ :meth:`polars.DataFrame.write_delta` directly instead.
1130
1171
  """
1131
1172
  DeltaStorageBackend().write_frame(
1132
1173
  df=df,
@@ -1135,6 +1176,10 @@ class Schema(BaseSchema, ABC):
1135
1176
  )
1136
1177
 
1137
1178
  @classmethod
1179
+ @deprecated(
1180
+ "`Schema.scan_delta` is deprecated and will be removed in dataframely v3. "
1181
+ "Use `polars.scan_delta` and call `validate` explicitly instead."
1182
+ )
1138
1183
  def scan_delta(
1139
1184
  cls,
1140
1185
  source: str | Path | deltalake.DeltaTable,
@@ -1182,6 +1227,10 @@ class Schema(BaseSchema, ABC):
1182
1227
  that are not through dataframely will result in losing the metadata.
1183
1228
 
1184
1229
  This method suffers from the same limitations as :meth:`serialize`.
1230
+
1231
+ .. deprecated:: 3.0.0
1232
+ This method is deprecated and will be removed in dataframely v3. Use
1233
+ :meth:`polars.scan_delta` and call :meth:`validate` explicitly instead.
1185
1234
  """
1186
1235
  return cls._read(
1187
1236
  DeltaStorageBackend(),
@@ -1192,6 +1241,10 @@ class Schema(BaseSchema, ABC):
1192
1241
  )
1193
1242
 
1194
1243
  @classmethod
1244
+ @deprecated(
1245
+ "`Schema.read_delta` is deprecated and will be removed in dataframely v3. "
1246
+ "Use `polars.read_delta` and call `validate` explicitly instead."
1247
+ )
1195
1248
  def read_delta(
1196
1249
  cls,
1197
1250
  source: str | Path | deltalake.DeltaTable,
@@ -1244,6 +1297,10 @@ class Schema(BaseSchema, ABC):
1244
1297
  break your schema.
1245
1298
 
1246
1299
  This method suffers from the same limitations as :meth:`serialize`.
1300
+
1301
+ .. deprecated:: 3.0.0
1302
+ This method is deprecated and will be removed in dataframely v3. Use
1303
+ :meth:`polars.read_delta` and call :meth:`validate` explicitly instead.
1247
1304
  """
1248
1305
  return cls._read(
1249
1306
  DeltaStorageBackend(),
@@ -1,5 +1,27 @@
1
1
  # Serialization
2
2
 
3
+ ```{warning}
4
+ Most of the I/O functionality described on this page is **deprecated** and will be
5
+ removed in dataframely v3 (see [#367](https://github.com/Quantco/dataframely/issues/367)).
6
+ Calling any of these methods now emits a {class}`DeprecationWarning`. Specifically:
7
+
8
+ - All I/O methods on {class}`~dataframely.Schema`
9
+ ({meth}`~dataframely.Schema.write_parquet`, {meth}`~dataframely.Schema.sink_parquet`,
10
+ {meth}`~dataframely.Schema.read_parquet`, {meth}`~dataframely.Schema.scan_parquet`,
11
+ {meth}`~dataframely.Schema.write_delta`, {meth}`~dataframely.Schema.read_delta`,
12
+ {meth}`~dataframely.Schema.scan_delta`) are deprecated. Use the corresponding
13
+ `polars` functions directly and call {meth}`~dataframely.Schema.validate` explicitly
14
+ where validation is required.
15
+ - The `deltalake` I/O methods on {class}`~dataframely.Collection`
16
+ ({meth}`~dataframely.Collection.write_delta`, {meth}`~dataframely.Collection.read_delta`,
17
+ {meth}`~dataframely.Collection.scan_delta`) are deprecated.
18
+ - {meth}`~dataframely.Collection.read_parquet` and
19
+ {meth}`~dataframely.Collection.scan_parquet` continue to exist, but reading with
20
+ `validation != "skip"` is deprecated: metadata will no longer be inspected and
21
+ validation will no longer run implicitly. Pass `validation="skip"` to opt into the
22
+ future behavior, or call {meth}`~dataframely.Collection.validate` explicitly.
23
+ ```
24
+
3
25
  `dataframely` provides support for easily storing and reading validated data.
4
26
  `polars` already provides native support for serializing data frames into different storage
5
27
  backends. For the storage of the data itself, `dataframely` usually dispatches to polars-native
@@ -26,17 +26,16 @@ As always, automated testing is useful here, but we also recommend checking the
26
26
  [published on GitHub](https://github.com/Quantco/dataframely/releases).
27
27
 
28
28
  In order to give users a heads-up before breaking changes are released, we introduce
29
- [FutureWarnings](https://docs.python.org/3/library/exceptions.html#FutureWarning).
29
+ [DeprecationWarnings](https://docs.python.org/3/library/exceptions.html#DeprecationWarning).
30
30
  Warnings are the most direct and effective tool at our disposal for reaching users directly.
31
31
  We therefore generally recommend that users do not silence such warnings explicitly, but instead migrate their code
32
32
  proactively, whenever possible.
33
33
  However, we also understand that the need for migration may catch users at an inconvenient time, and a temporary band
34
34
  aid solution might be required.
35
- Users can disable `FutureWarnings` either through
36
- [python builtins](https://docs.python.org/3/library/warnings.html#warnings.filterwarnings),
37
- builtins from tools
38
- like [pytest](https://docs.pytest.org/en/stable/how-to/capture-warnings.html#controlling-warnings),
39
- or by setting the `DATAFRAMELY_NO_FUTURE_WARNINGS` environment variable to `true` or `1`.
35
+ Users can disable `DeprecationWarnings` either through
36
+ [python builtins](https://docs.python.org/3/library/warnings.html#warnings.filterwarnings)
37
+ or through builtins from tools
38
+ like [pytest](https://docs.pytest.org/en/stable/how-to/capture-warnings.html#controlling-warnings).
40
39
 
41
40
  ## Experimental features
42
41
 
@@ -27,7 +27,7 @@ description = "A declarative, polars-native data frame validation library"
27
27
  name = "dataframely"
28
28
  readme = "README.md"
29
29
  requires-python = ">=3.10"
30
- version = "2.12.0"
30
+ version = "2.13.1"
31
31
 
32
32
  [project.optional-dependencies]
33
33
  deltalake = ["deltalake"]
@@ -107,10 +107,13 @@ addopts = "--import-mode=importlib --benchmark-skip -m 'not s3'"
107
107
  filterwarnings = [
108
108
  # By default, all warnings should yield errors
109
109
  "error",
110
- # Almost all tests are oblivious to the value of `nullable`. Let's ignore the warning as long as it exists.
111
- "ignore:The 'nullable' argument was not explicitly set:FutureWarning",
112
110
  # boto3 still uses .utcnow()
113
111
  "ignore::DeprecationWarning:botocore.*:",
112
+ # I/O deprecation warnings (see #367) are asserted in dedicated tests via
113
+ # `pytest.warns`; silence them elsewhere so existing tests keep exercising the
114
+ # still-present functionality.
115
+ "ignore:.*Reading a collection with .validation.*:DeprecationWarning",
116
+ "ignore:.*deprecated and will be removed in dataframely v3.*:DeprecationWarning",
114
117
  ]
115
118
  markers = [
116
119
  "s3: tests that run against and S3 backend",
@@ -0,0 +1,108 @@
1
+ # Copyright (c) QuantCo 2025-2026
2
+ # SPDX-License-Identifier: BSD-3-Clause
3
+
4
+ import polars as pl
5
+ import polars.exceptions as plexc
6
+ import pytest
7
+
8
+ import dataframely as dy
9
+
10
+
11
+ class FirstSchema(dy.Schema):
12
+ a = dy.Float64(min=5)
13
+
14
+
15
+ class SecondSchema(dy.Schema):
16
+ a = dy.String()
17
+
18
+
19
+ class Collection(dy.Collection):
20
+ first: dy.LazyFrame[FirstSchema]
21
+ second: dy.LazyFrame[SecondSchema]
22
+
23
+
24
+ @pytest.mark.parametrize("df_type", [pl.DataFrame, pl.LazyFrame])
25
+ def test_validate_skip_member_validation_eager(
26
+ df_type: type[pl.DataFrame] | type[pl.LazyFrame],
27
+ ) -> None:
28
+ first = df_type({"a": [3, 4, 5]}) # NOTE: first two rows are violations
29
+ second = df_type({"a": ["1", "2", "3"]})
30
+
31
+ with pytest.raises(dy.exc.ValidationError):
32
+ Collection.validate({"first": first, "second": second}, cast=True) # type: ignore
33
+
34
+ Collection.validate(
35
+ {"first": first, "second": second}, # type: ignore
36
+ cast=True,
37
+ skip_member_validation=True,
38
+ )
39
+
40
+
41
+ @pytest.mark.parametrize("df_type", [pl.DataFrame, pl.LazyFrame])
42
+ def test_validate_skip_member_validation_lazy(
43
+ df_type: type[pl.DataFrame] | type[pl.LazyFrame],
44
+ ) -> None:
45
+ first = df_type({"a": [3, 4, 5]}) # NOTE: first two rows are violations
46
+ second = df_type({"a": ["1", "2", "3"]})
47
+
48
+ with pytest.raises(plexc.ComputeError):
49
+ Collection.validate(
50
+ {"first": first, "second": second}, # type: ignore
51
+ cast=True,
52
+ eager=False,
53
+ ).collect_all()
54
+
55
+ Collection.validate(
56
+ {"first": first, "second": second}, # type: ignore
57
+ cast=True,
58
+ skip_member_validation=True,
59
+ eager=False,
60
+ ).collect_all()
61
+
62
+
63
+ @pytest.mark.parametrize("df_type", [pl.DataFrame, pl.LazyFrame])
64
+ def test_filter_skip_member_validation_eager(
65
+ df_type: type[pl.DataFrame] | type[pl.LazyFrame],
66
+ ) -> None:
67
+ first = df_type({"a": [3, 4, 5]}) # NOTE: first two rows are violations
68
+ second = df_type({"a": ["1", "2", "3"]})
69
+
70
+ _, failure_info = Collection.filter(
71
+ {"first": first, "second": second}, # type: ignore
72
+ cast=True,
73
+ )
74
+ assert failure_info["first"].counts() == {"a|min": 2}
75
+ assert failure_info["second"].counts() == {}
76
+
77
+ _, failure_info = Collection.filter(
78
+ {"first": first, "second": second}, # type: ignore
79
+ cast=True,
80
+ skip_member_validation=True,
81
+ )
82
+ assert failure_info["first"].counts() == {}
83
+ assert failure_info["second"].counts() == {}
84
+
85
+
86
+ @pytest.mark.parametrize("df_type", [pl.DataFrame, pl.LazyFrame])
87
+ def test_filter_skip_member_validation_lazy(
88
+ df_type: type[pl.DataFrame] | type[pl.LazyFrame],
89
+ ) -> None:
90
+ first = df_type({"a": [3, 4, 5]}) # NOTE: first two rows are violations
91
+ second = df_type({"a": ["1", "2", "3"]})
92
+
93
+ _, failure_info = Collection.filter(
94
+ {"first": first, "second": second}, # type: ignore
95
+ cast=True,
96
+ eager=False,
97
+ )
98
+ assert failure_info["first"].counts() == {"a|min": 2}
99
+ assert failure_info["second"].counts() == {}
100
+
101
+ _, failure_info = Collection.filter(
102
+ {"first": first, "second": second}, # type: ignore
103
+ cast=True,
104
+ skip_member_validation=True,
105
+ eager=False,
106
+ )
107
+ assert failure_info["first"].counts() == {}
108
+ assert failure_info["second"].counts() == {}