dataframely 1.3.1__tar.gz → 1.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. {dataframely-1.3.1 → dataframely-1.4.0}/PKG-INFO +2 -2
  2. dataframely-1.4.0/dataframely/_deprecation.py +39 -0
  3. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/columns/_base.py +77 -5
  4. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/columns/any.py +17 -3
  5. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/columns/array.py +17 -3
  6. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/columns/datetime.py +100 -20
  7. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/columns/decimal.py +21 -4
  8. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/columns/enum.py +21 -4
  9. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/columns/float.py +21 -4
  10. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/columns/integer.py +21 -4
  11. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/columns/list.py +21 -4
  12. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/columns/object.py +17 -3
  13. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/columns/string.py +21 -4
  14. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/columns/struct.py +21 -4
  15. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/random.py +5 -1
  16. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.columns.rst +16 -0
  17. {dataframely-1.3.1 → dataframely-1.4.0}/docs/index.rst +1 -1
  18. {dataframely-1.3.1 → dataframely-1.4.0}/docs/sites/development.rst +1 -0
  19. dataframely-1.4.0/docs/sites/versioning.rst +20 -0
  20. {dataframely-1.3.1 → dataframely-1.4.0}/pyproject.toml +4 -3
  21. {dataframely-1.3.1 → dataframely-1.4.0}/tests/column_types/test_datetime.py +35 -2
  22. dataframely-1.4.0/tests/columns/test_check.py +68 -0
  23. {dataframely-1.3.1 → dataframely-1.4.0}/tests/columns/test_sql_schema.py +2 -0
  24. dataframely-1.4.0/tests/test_deprecation.py +28 -0
  25. dataframely-1.3.1/tests/columns/test_check.py +0 -19
  26. {dataframely-1.3.1 → dataframely-1.4.0}/.copier-answers.yml +0 -0
  27. {dataframely-1.3.1 → dataframely-1.4.0}/.envrc +0 -0
  28. {dataframely-1.3.1 → dataframely-1.4.0}/.gitattributes +0 -0
  29. {dataframely-1.3.1 → dataframely-1.4.0}/.github/CODEOWNERS +0 -0
  30. {dataframely-1.3.1 → dataframely-1.4.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  31. {dataframely-1.3.1 → dataframely-1.4.0}/.github/dependabot.yml +0 -0
  32. {dataframely-1.3.1 → dataframely-1.4.0}/.github/release-drafter.yml +0 -0
  33. {dataframely-1.3.1 → dataframely-1.4.0}/.github/workflows/build.yml +0 -0
  34. {dataframely-1.3.1 → dataframely-1.4.0}/.github/workflows/chore.yml +0 -0
  35. {dataframely-1.3.1 → dataframely-1.4.0}/.github/workflows/ci.yml +0 -0
  36. {dataframely-1.3.1 → dataframely-1.4.0}/.gitignore +0 -0
  37. {dataframely-1.3.1 → dataframely-1.4.0}/.pre-commit-config.yaml +0 -0
  38. {dataframely-1.3.1 → dataframely-1.4.0}/.prettierignore +0 -0
  39. {dataframely-1.3.1 → dataframely-1.4.0}/.prettierrc +0 -0
  40. {dataframely-1.3.1 → dataframely-1.4.0}/.readthedocs.yml +0 -0
  41. {dataframely-1.3.1 → dataframely-1.4.0}/Cargo.lock +0 -0
  42. {dataframely-1.3.1 → dataframely-1.4.0}/Cargo.toml +0 -0
  43. {dataframely-1.3.1 → dataframely-1.4.0}/LICENSE +0 -0
  44. {dataframely-1.3.1 → dataframely-1.4.0}/README.md +0 -0
  45. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/__init__.py +0 -0
  46. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/_base_collection.py +0 -0
  47. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/_base_schema.py +0 -0
  48. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/_compat.py +0 -0
  49. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/_extre.pyi +0 -0
  50. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/_filter.py +0 -0
  51. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/_polars.py +0 -0
  52. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/_rule.py +0 -0
  53. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/_typing.py +0 -0
  54. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/_validation.py +0 -0
  55. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/collection.py +0 -0
  56. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/columns/__init__.py +0 -0
  57. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/columns/_mixins.py +0 -0
  58. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/columns/_utils.py +0 -0
  59. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/columns/bool.py +0 -0
  60. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/config.py +0 -0
  61. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/exc.py +0 -0
  62. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/failure.py +0 -0
  63. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/functional.py +0 -0
  64. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/mypy.py +0 -0
  65. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/py.typed +0 -0
  66. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/schema.py +0 -0
  67. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/testing/__init__.py +0 -0
  68. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/testing/const.py +0 -0
  69. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/testing/factory.py +0 -0
  70. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/testing/mask.py +0 -0
  71. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/testing/rules.py +0 -0
  72. {dataframely-1.3.1 → dataframely-1.4.0}/dataframely/testing/typing.py +0 -0
  73. {dataframely-1.3.1 → dataframely-1.4.0}/docker-compose.yml +0 -0
  74. {dataframely-1.3.1 → dataframely-1.4.0}/docs/Makefile +0 -0
  75. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.collection.rst +0 -0
  76. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.columns.any.rst +0 -0
  77. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.columns.bool.rst +0 -0
  78. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.columns.datetime.rst +0 -0
  79. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.columns.decimal.rst +0 -0
  80. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.columns.enum.rst +0 -0
  81. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.columns.float.rst +0 -0
  82. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.columns.integer.rst +0 -0
  83. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.columns.list.rst +0 -0
  84. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.columns.string.rst +0 -0
  85. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.columns.struct.rst +0 -0
  86. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.config.rst +0 -0
  87. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.exc.rst +0 -0
  88. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.failure.rst +0 -0
  89. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.functional.rst +0 -0
  90. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.mypy.rst +0 -0
  91. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.random.rst +0 -0
  92. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.rst +0 -0
  93. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.schema.rst +0 -0
  94. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.testing.const.rst +0 -0
  95. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.testing.factory.rst +0 -0
  96. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.testing.mask.rst +0 -0
  97. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.testing.rst +0 -0
  98. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.testing.rules.rst +0 -0
  99. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/dataframely.testing.typing.rst +0 -0
  100. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_api/modules.rst +0 -0
  101. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_static/custom.css +0 -0
  102. {dataframely-1.3.1 → dataframely-1.4.0}/docs/_static/favicon.ico +0 -0
  103. {dataframely-1.3.1 → dataframely-1.4.0}/docs/conf.py +0 -0
  104. {dataframely-1.3.1 → dataframely-1.4.0}/docs/make.bat +0 -0
  105. {dataframely-1.3.1 → dataframely-1.4.0}/docs/sites/examples/real-world.ipynb +0 -0
  106. {dataframely-1.3.1 → dataframely-1.4.0}/docs/sites/faq.rst +0 -0
  107. {dataframely-1.3.1 → dataframely-1.4.0}/docs/sites/installation.rst +0 -0
  108. {dataframely-1.3.1 → dataframely-1.4.0}/docs/sites/quickstart.rst +0 -0
  109. {dataframely-1.3.1 → dataframely-1.4.0}/pixi.lock +0 -0
  110. {dataframely-1.3.1 → dataframely-1.4.0}/pixi.toml +0 -0
  111. {dataframely-1.3.1 → dataframely-1.4.0}/src/errdefs.rs +0 -0
  112. {dataframely-1.3.1 → dataframely-1.4.0}/src/lib.rs +0 -0
  113. {dataframely-1.3.1 → dataframely-1.4.0}/src/regex_repr.rs +0 -0
  114. {dataframely-1.3.1 → dataframely-1.4.0}/tests/collection/test_base.py +0 -0
  115. {dataframely-1.3.1 → dataframely-1.4.0}/tests/collection/test_cast.py +0 -0
  116. {dataframely-1.3.1 → dataframely-1.4.0}/tests/collection/test_create_empty.py +0 -0
  117. {dataframely-1.3.1 → dataframely-1.4.0}/tests/collection/test_filter_one_to_n.py +0 -0
  118. {dataframely-1.3.1 → dataframely-1.4.0}/tests/collection/test_filter_validate.py +0 -0
  119. {dataframely-1.3.1 → dataframely-1.4.0}/tests/collection/test_ignore_in_filter.py +0 -0
  120. {dataframely-1.3.1 → dataframely-1.4.0}/tests/collection/test_implementation.py +0 -0
  121. {dataframely-1.3.1 → dataframely-1.4.0}/tests/collection/test_optional_members.py +0 -0
  122. {dataframely-1.3.1 → dataframely-1.4.0}/tests/collection/test_sample.py +0 -0
  123. {dataframely-1.3.1 → dataframely-1.4.0}/tests/collection/test_validate_input.py +0 -0
  124. {dataframely-1.3.1 → dataframely-1.4.0}/tests/column_types/__init__.py +0 -0
  125. {dataframely-1.3.1 → dataframely-1.4.0}/tests/column_types/test_any.py +0 -0
  126. {dataframely-1.3.1 → dataframely-1.4.0}/tests/column_types/test_array.py +0 -0
  127. {dataframely-1.3.1 → dataframely-1.4.0}/tests/column_types/test_decimal.py +0 -0
  128. {dataframely-1.3.1 → dataframely-1.4.0}/tests/column_types/test_enum.py +0 -0
  129. {dataframely-1.3.1 → dataframely-1.4.0}/tests/column_types/test_float.py +0 -0
  130. {dataframely-1.3.1 → dataframely-1.4.0}/tests/column_types/test_integer.py +0 -0
  131. {dataframely-1.3.1 → dataframely-1.4.0}/tests/column_types/test_list.py +0 -0
  132. {dataframely-1.3.1 → dataframely-1.4.0}/tests/column_types/test_object.py +0 -0
  133. {dataframely-1.3.1 → dataframely-1.4.0}/tests/column_types/test_string.py +0 -0
  134. {dataframely-1.3.1 → dataframely-1.4.0}/tests/column_types/test_struct.py +0 -0
  135. {dataframely-1.3.1 → dataframely-1.4.0}/tests/columns/__init__.py +0 -0
  136. {dataframely-1.3.1 → dataframely-1.4.0}/tests/columns/test_alias.py +0 -0
  137. {dataframely-1.3.1 → dataframely-1.4.0}/tests/columns/test_default_dtypes.py +0 -0
  138. {dataframely-1.3.1 → dataframely-1.4.0}/tests/columns/test_metadata.py +0 -0
  139. {dataframely-1.3.1 → dataframely-1.4.0}/tests/columns/test_polars_schema.py +0 -0
  140. {dataframely-1.3.1 → dataframely-1.4.0}/tests/columns/test_pyarrow.py +0 -0
  141. {dataframely-1.3.1 → dataframely-1.4.0}/tests/columns/test_rules.py +0 -0
  142. {dataframely-1.3.1 → dataframely-1.4.0}/tests/columns/test_sample.py +0 -0
  143. {dataframely-1.3.1 → dataframely-1.4.0}/tests/columns/test_str.py +0 -0
  144. {dataframely-1.3.1 → dataframely-1.4.0}/tests/columns/test_utils.py +0 -0
  145. {dataframely-1.3.1 → dataframely-1.4.0}/tests/core_validation/__init__.py +0 -0
  146. {dataframely-1.3.1 → dataframely-1.4.0}/tests/core_validation/test_column_validation.py +0 -0
  147. {dataframely-1.3.1 → dataframely-1.4.0}/tests/core_validation/test_dtype_validation.py +0 -0
  148. {dataframely-1.3.1 → dataframely-1.4.0}/tests/core_validation/test_rule_evaluation.py +0 -0
  149. {dataframely-1.3.1 → dataframely-1.4.0}/tests/functional/test_concat.py +0 -0
  150. {dataframely-1.3.1 → dataframely-1.4.0}/tests/functional/test_relationships.py +0 -0
  151. {dataframely-1.3.1 → dataframely-1.4.0}/tests/schema/test_base.py +0 -0
  152. {dataframely-1.3.1 → dataframely-1.4.0}/tests/schema/test_cast.py +0 -0
  153. {dataframely-1.3.1 → dataframely-1.4.0}/tests/schema/test_create_empty.py +0 -0
  154. {dataframely-1.3.1 → dataframely-1.4.0}/tests/schema/test_create_empty_if_none.py +0 -0
  155. {dataframely-1.3.1 → dataframely-1.4.0}/tests/schema/test_filter.py +0 -0
  156. {dataframely-1.3.1 → dataframely-1.4.0}/tests/schema/test_inheritance.py +0 -0
  157. {dataframely-1.3.1 → dataframely-1.4.0}/tests/schema/test_rule_implementation.py +0 -0
  158. {dataframely-1.3.1 → dataframely-1.4.0}/tests/schema/test_sample.py +0 -0
  159. {dataframely-1.3.1 → dataframely-1.4.0}/tests/schema/test_validate.py +0 -0
  160. {dataframely-1.3.1 → dataframely-1.4.0}/tests/test_compat.py +0 -0
  161. {dataframely-1.3.1 → dataframely-1.4.0}/tests/test_config.py +0 -0
  162. {dataframely-1.3.1 → dataframely-1.4.0}/tests/test_exc.py +0 -0
  163. {dataframely-1.3.1 → dataframely-1.4.0}/tests/test_extre.py +0 -0
  164. {dataframely-1.3.1 → dataframely-1.4.0}/tests/test_failure_info.py +0 -0
  165. {dataframely-1.3.1 → dataframely-1.4.0}/tests/test_random.py +0 -0
  166. {dataframely-1.3.1 → dataframely-1.4.0}/tests/test_typing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataframely
3
- Version: 1.3.1
3
+ Version: 1.4.0
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3.11
6
6
  Classifier: Programming Language :: Python :: 3.12
@@ -12,8 +12,8 @@ Summary: A declarative, polars-native data frame validation library
12
12
  Author-email: Andreas Albert <andreas.albert@quantco.com>, Daniel Elsner <daniel.elsner@quantco.com>, Oliver Borchert <oliver.borchert@quantco.com>
13
13
  Requires-Python: >=3.11
14
14
  Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
15
- Project-URL: Repository, https://github.com/quantco/dataframely
16
15
  Project-URL: Documentation, https://dataframely.readthedocs.io/
16
+ Project-URL: Repository, https://github.com/quantco/dataframely
17
17
 
18
18
  <!-- LOGO -->
19
19
  <br />
@@ -0,0 +1,39 @@
1
+ # Copyright (c) QuantCo 2025-2025
2
+ # SPDX-License-Identifier: BSD-3-Clause
3
+
4
+ import os
5
+ import warnings
6
+ from collections.abc import Callable
7
+ from functools import wraps
8
+
9
+ TRUTHY_VALUES = ["1", "true"]
10
+
11
+
12
+ def skip_if(env: str) -> Callable:
13
+ """Decorator to skip warnings based on environment variable.
14
+
15
+ If the environment variable is equivalent to any of TRUTHY_VALUES, the wrapped
16
+ function is skipped.
17
+ """
18
+
19
+ def decorator(fun: Callable) -> Callable:
20
+ @wraps(fun)
21
+ def wrapper() -> None:
22
+ if os.getenv(env, "").lower() in TRUTHY_VALUES:
23
+ return
24
+ fun()
25
+
26
+ return wrapper
27
+
28
+ return decorator
29
+
30
+
31
+ @skip_if(env="DATAFRAMELY_NO_FUTURE_WARNINGS")
32
+ def warn_nullable_default_change() -> None:
33
+ warnings.warn(
34
+ "The 'nullable' argument was not explicitly set. In a future release, "
35
+ "'nullable=False' will be the default if 'nullable' is not specified. "
36
+ "Explicitly set 'nullable=True' if you want your column to be nullable.",
37
+ FutureWarning,
38
+ stacklevel=4,
39
+ )
@@ -4,12 +4,14 @@
4
4
  from __future__ import annotations
5
5
 
6
6
  from abc import ABC, abstractmethod
7
+ from collections import Counter
7
8
  from collections.abc import Callable
8
9
  from typing import Any
9
10
 
10
11
  import polars as pl
11
12
 
12
13
  from dataframely._compat import pa, sa, sa_TypeEngine
14
+ from dataframely._deprecation import warn_nullable_default_change
13
15
  from dataframely._polars import PolarsDataType
14
16
  from dataframely.random import Generator
15
17
 
@@ -28,19 +30,36 @@ class Column(ABC):
28
30
  def __init__(
29
31
  self,
30
32
  *,
31
- nullable: bool = True,
33
+ nullable: bool | None = None,
32
34
  primary_key: bool = False,
33
- check: Callable[[pl.Expr], pl.Expr] | None = None,
35
+ check: (
36
+ Callable[[pl.Expr], pl.Expr]
37
+ | list[Callable[[pl.Expr], pl.Expr]]
38
+ | dict[str, Callable[[pl.Expr], pl.Expr]]
39
+ | None
40
+ ) = None,
34
41
  alias: str | None = None,
35
42
  metadata: dict[str, Any] | None = None,
36
43
  ):
37
44
  """
38
45
  Args:
39
46
  nullable: Whether this column may contain null values.
47
+ Explicitly set `nullable=True` if you want your column to be nullable.
48
+ In a future release, `nullable=False` will be the default if `nullable`
49
+ is not specified.
40
50
  primary_key: Whether this column is part of the primary key of the schema.
41
51
  If ``True``, ``nullable`` is automatically set to ``False``.
42
- check: A custom check to run for this column. Must return a non-aggregated
43
- boolean expression.
52
+ check: A custom rule or multiple rules to run for this column. This can be:
53
+ - A single callable that returns a non-aggregated boolean expression.
54
+ The name of the rule is derived from the callable name, or defaults to
55
+ "check" for lambdas.
56
+ - A list of callables, where each callable returns a non-aggregated
57
+ boolean expression. The name of the rule is derived from the callable
58
+ name, or defaults to "check" for lambdas. Where multiple rules result
59
+ in the same name, the suffix __i is appended to the name.
60
+ - A dictionary mapping rule names to callables, where each callable
61
+ returns a non-aggregated boolean expression.
62
+ All rule names provided here are given the prefix "check_".
44
63
  alias: An overwrite for this column's name which allows for using a column
45
64
  name that is not a valid Python identifier. Especially note that setting
46
65
  this option does _not_ allow to refer to the column with two different
@@ -48,6 +67,10 @@ class Column(ABC):
48
67
  internally sets the alias to the column's name in the parent schema.
49
68
  metadata: A dictionary of metadata to attach to the column.
50
69
  """
70
+ if nullable is None:
71
+ warn_nullable_default_change()
72
+ nullable = True
73
+
51
74
  self.nullable = nullable and not primary_key
52
75
  self.primary_key = primary_key
53
76
  self.check = check
@@ -96,10 +119,59 @@ class Column(ABC):
96
119
  result = {}
97
120
  if not self.nullable:
98
121
  result["nullability"] = expr.is_not_null()
122
+
99
123
  if self.check is not None:
100
- result["check"] = self.check(expr)
124
+ if isinstance(self.check, dict):
125
+ for rule_name, rule_callable in self.check.items():
126
+ result[f"check__{rule_name}"] = rule_callable(expr)
127
+ else:
128
+ list_of_rules = (
129
+ self.check if isinstance(self.check, list) else [self.check]
130
+ )
131
+ # Get unique names for rules from callables
132
+ rule_names = self._derive_check_rule_names(list_of_rules)
133
+ for rule_name, rule_callable in zip(rule_names, list_of_rules):
134
+ result[rule_name] = rule_callable(expr)
135
+
101
136
  return result
102
137
 
138
+ def _derive_check_rule_names(
139
+ self, rules: list[Callable[[pl.Expr], pl.Expr]]
140
+ ) -> list[str]:
141
+ """Generate unique names for rule callables.
142
+
143
+ For callables with the same name, appends a suffix __i where i is the index
144
+ of occurrence (starting from 0), but only if there are duplicates.
145
+
146
+ Args:
147
+ rules: List of rule callables.
148
+
149
+ Returns:
150
+ List of unique names corresponding to the rule callables.
151
+ """
152
+ base_names = [
153
+ f"check__{rule.__name__}" if rule.__name__ != "<lambda>" else "check"
154
+ for rule in rules
155
+ ]
156
+
157
+ # Count occurrences using Counter
158
+ name_counts = Counter(base_names)
159
+
160
+ # Append suffixes to names that are duplicated
161
+ final_names = []
162
+ duplicate_counter: dict[str, int] = {
163
+ name: 0 for name in name_counts if name_counts[name] > 1
164
+ }
165
+ for name in base_names:
166
+ if name_counts[name] > 1:
167
+ postfix = duplicate_counter[name]
168
+ final_names.append(f"{name}__{postfix}")
169
+ duplicate_counter[name] += 1
170
+ else:
171
+ final_names.append(name)
172
+
173
+ return final_names
174
+
103
175
  # -------------------------------------- SQL ------------------------------------- #
104
176
 
105
177
  def sqlalchemy_column(self, name: str, dialect: sa.Dialect) -> sa.Column:
@@ -25,14 +25,28 @@ class Any(Column):
25
25
  def __init__(
26
26
  self,
27
27
  *,
28
- check: Callable[[pl.Expr], pl.Expr] | None = None,
28
+ check: (
29
+ Callable[[pl.Expr], pl.Expr]
30
+ | list[Callable[[pl.Expr], pl.Expr]]
31
+ | dict[str, Callable[[pl.Expr], pl.Expr]]
32
+ | None
33
+ ) = None,
29
34
  alias: str | None = None,
30
35
  metadata: dict[str, Any] | None = None,
31
36
  ):
32
37
  """
33
38
  Args:
34
- check: A custom check to run for this column. Must return a non-aggregated
35
- boolean expression.
39
+ check: A custom rule or multiple rules to run for this column. This can be:
40
+ - A single callable that returns a non-aggregated boolean expression.
41
+ The name of the rule is derived from the callable name, or defaults to
42
+ "check" for lambdas.
43
+ - A list of callables, where each callable returns a non-aggregated
44
+ boolean expression. The name of the rule is derived from the callable
45
+ name, or defaults to "check" for lambdas. Where multiple rules result
46
+ in the same name, the suffix __i is appended to the name.
47
+ - A dictionary mapping rule names to callables, where each callable
48
+ returns a non-aggregated boolean expression.
49
+ All rule names provided here are given the prefix "check_".
36
50
  alias: An overwrite for this column's name which allows for using a column
37
51
  name that is not a valid Python identifier. Especially note that setting
38
52
  this option does _not_ allow to refer to the column with two different
@@ -28,7 +28,12 @@ class Array(Column):
28
28
  # polars doesn't yet support grouping by arrays,
29
29
  # see https://github.com/pola-rs/polars/issues/22574
30
30
  primary_key: Literal[False] = False,
31
- check: Callable[[pl.Expr], pl.Expr] | None = None,
31
+ check: (
32
+ Callable[[pl.Expr], pl.Expr]
33
+ | list[Callable[[pl.Expr], pl.Expr]]
34
+ | dict[str, Callable[[pl.Expr], pl.Expr]]
35
+ | None
36
+ ) = None,
32
37
  alias: str | None = None,
33
38
  metadata: dict[str, Any] | None = None,
34
39
  ):
@@ -39,8 +44,17 @@ class Array(Column):
39
44
  nullable: Whether this column may contain null values.
40
45
  primary_key: Whether this column is part of the primary key of the schema.
41
46
  Not yet supported for the Array type.
42
- check: A custom check to run for this column. Must return a non-aggregated
43
- boolean expression.
47
+ check: A custom rule or multiple rules to run for this column. This can be:
48
+ - A single callable that returns a non-aggregated boolean expression.
49
+ The name of the rule is derived from the callable name, or defaults to
50
+ "check" for lambdas.
51
+ - A list of callables, where each callable returns a non-aggregated
52
+ boolean expression. The name of the rule is derived from the callable
53
+ name, or defaults to "check" for lambdas. Where multiple rules result
54
+ in the same name, the suffix __i is appended to the name.
55
+ - A dictionary mapping rule names to callables, where each callable
56
+ returns a non-aggregated boolean expression.
57
+ All rule names provided here are given the prefix "check_".
44
58
  alias: An overwrite for this column's name which allows for using a column
45
59
  name that is not a valid Python identifier. Especially note that setting
46
60
  this option does _not_ allow to refer to the column with two different
@@ -32,20 +32,28 @@ class Date(OrdinalMixin[dt.date], Column):
32
32
  def __init__(
33
33
  self,
34
34
  *,
35
- nullable: bool = True,
35
+ nullable: bool | None = None,
36
36
  primary_key: bool = False,
37
37
  min: dt.date | None = None,
38
38
  min_exclusive: dt.date | None = None,
39
39
  max: dt.date | None = None,
40
40
  max_exclusive: dt.date | None = None,
41
41
  resolution: str | None = None,
42
- check: Callable[[pl.Expr], pl.Expr] | None = None,
42
+ check: (
43
+ Callable[[pl.Expr], pl.Expr]
44
+ | list[Callable[[pl.Expr], pl.Expr]]
45
+ | dict[str, Callable[[pl.Expr], pl.Expr]]
46
+ | None
47
+ ) = None,
43
48
  alias: str | None = None,
44
49
  metadata: dict[str, Any] | None = None,
45
50
  ):
46
51
  """
47
52
  Args:
48
53
  nullable: Whether this column may contain null values.
54
+ Explicitly set `nullable=True` if you want your column to be nullable.
55
+ In a future release, `nullable=False` will be the default if `nullable`
56
+ is not specified.
49
57
  primary_key: Whether this column is part of the primary key of the schema.
50
58
  If ``True``, ``nullable`` is automatically set to ``False``.
51
59
  min: The minimum date for dates in this column (inclusive).
@@ -58,8 +66,17 @@ class Date(OrdinalMixin[dt.date], Column):
58
66
  formatting language used by :mod:`polars` datetime ``round`` method.
59
67
  For example, a value ``1mo`` expects all dates to be on the first of the
60
68
  month. Note that this setting does *not* affect the storage resolution.
61
- check: A custom check to run for this column. Must return a non-aggregated
62
- boolean expression.
69
+ check: A custom rule or multiple rules to run for this column. This can be:
70
+ - A single callable that returns a non-aggregated boolean expression.
71
+ The name of the rule is derived from the callable name, or defaults to
72
+ "check" for lambdas.
73
+ - A list of callables, where each callable returns a non-aggregated
74
+ boolean expression. The name of the rule is derived from the callable
75
+ name, or defaults to "check" for lambdas. Where multiple rules result
76
+ in the same name, the suffix __i is appended to the name.
77
+ - A dictionary mapping rule names to callables, where each callable
78
+ returns a non-aggregated boolean expression.
79
+ All rule names provided here are given the prefix "check_".
63
80
  alias: An overwrite for this column's name which allows for using a column
64
81
  name that is not a valid Python identifier. Especially note that setting
65
82
  this option does _not_ allow to refer to the column with two different
@@ -142,20 +159,28 @@ class Time(OrdinalMixin[dt.time], Column):
142
159
  def __init__(
143
160
  self,
144
161
  *,
145
- nullable: bool = True,
162
+ nullable: bool | None = None,
146
163
  primary_key: bool = False,
147
164
  min: dt.time | None = None,
148
165
  min_exclusive: dt.time | None = None,
149
166
  max: dt.time | None = None,
150
167
  max_exclusive: dt.time | None = None,
151
168
  resolution: str | None = None,
152
- check: Callable[[pl.Expr], pl.Expr] | None = None,
169
+ check: (
170
+ Callable[[pl.Expr], pl.Expr]
171
+ | list[Callable[[pl.Expr], pl.Expr]]
172
+ | dict[str, Callable[[pl.Expr], pl.Expr]]
173
+ | None
174
+ ) = None,
153
175
  alias: str | None = None,
154
176
  metadata: dict[str, Any] | None = None,
155
177
  ):
156
178
  """
157
179
  Args:
158
180
  nullable: Whether this column may contain null values.
181
+ Explicitly set `nullable=True` if you want your column to be nullable.
182
+ In a future release, `nullable=False` will be the default if `nullable`
183
+ is not specified.
159
184
  primary_key: Whether this column is part of the primary key of the schema.
160
185
  If ``True``, ``nullable`` is automatically set to ``False``.
161
186
  min: The minimum time for times in this column (inclusive).
@@ -168,8 +193,17 @@ class Time(OrdinalMixin[dt.time], Column):
168
193
  formatting language used by :mod:`polars` datetime ``round`` method.
169
194
  For example, a value ``1h`` expects all times to be full hours. Note
170
195
  that this setting does *not* affect the storage resolution.
171
- check: A custom check to run for this column. Must return a non-aggregated
172
- boolean expression.
196
+ check: A custom rule or multiple rules to run for this column. This can be:
197
+ - A single callable that returns a non-aggregated boolean expression.
198
+ The name of the rule is derived from the callable name, or defaults to
199
+ "check" for lambdas.
200
+ - A list of callables, where each callable returns a non-aggregated
201
+ boolean expression. The name of the rule is derived from the callable
202
+ name, or defaults to "check" for lambdas. Where multiple rules result
203
+ in the same name, the suffix __i is appended to the name.
204
+ - A dictionary mapping rule names to callables, where each callable
205
+ returns a non-aggregated boolean expression.
206
+ All rule names provided here are given the prefix "check_".
173
207
  alias: An overwrite for this column's name which allows for using a column
174
208
  name that is not a valid Python identifier. Especially note that setting
175
209
  this option does _not_ allow to refer to the column with two different
@@ -258,20 +292,29 @@ class Datetime(OrdinalMixin[dt.datetime], Column):
258
292
  def __init__(
259
293
  self,
260
294
  *,
261
- nullable: bool = True,
295
+ nullable: bool | None = None,
262
296
  primary_key: bool = False,
263
297
  min: dt.datetime | None = None,
264
298
  min_exclusive: dt.datetime | None = None,
265
299
  max: dt.datetime | None = None,
266
300
  max_exclusive: dt.datetime | None = None,
267
301
  resolution: str | None = None,
268
- check: Callable[[pl.Expr], pl.Expr] | None = None,
302
+ time_zone: str | dt.tzinfo | None = None,
303
+ check: (
304
+ Callable[[pl.Expr], pl.Expr]
305
+ | list[Callable[[pl.Expr], pl.Expr]]
306
+ | dict[str, Callable[[pl.Expr], pl.Expr]]
307
+ | None
308
+ ) = None,
269
309
  alias: str | None = None,
270
310
  metadata: dict[str, Any] | None = None,
271
311
  ):
272
312
  """
273
313
  Args:
274
314
  nullable: Whether this column may contain null values.
315
+ Explicitly set `nullable=True` if you want your column to be nullable.
316
+ In a future release, `nullable=False` will be the default if `nullable`
317
+ is not specified.
275
318
  primary_key: Whether this column is part of the primary key of the schema.
276
319
  If ``True``, ``nullable`` is automatically set to ``False``.
277
320
  min: The minimum datetime for datetimes in this column (inclusive).
@@ -284,8 +327,20 @@ class Datetime(OrdinalMixin[dt.datetime], Column):
284
327
  the formatting language used by :mod:`polars` datetime ``round`` method.
285
328
  For example, a value ``1h`` expects all datetimes to be full hours. Note
286
329
  that this setting does *not* affect the storage resolution.
287
- check: A custom check to run for this column. Must return a non-aggregated
288
- boolean expression.
330
+ time_zone: The time zone that datetimes in the column must have. The time
331
+ zone must use a valid IANA time zone name identifier e.x. ``Etc/UTC`` or
332
+ ``America/New_York``.
333
+ check: A custom rule or multiple rules to run for this column. This can be:
334
+ - A single callable that returns a non-aggregated boolean expression.
335
+ The name of the rule is derived from the callable name, or defaults to
336
+ "check" for lambdas.
337
+ - A list of callables, where each callable returns a non-aggregated
338
+ boolean expression. The name of the rule is derived from the callable
339
+ name, or defaults to "check" for lambdas. Where multiple rules result
340
+ in the same name, the suffix __i is appended to the name.
341
+ - A dictionary mapping rule names to callables, where each callable
342
+ returns a non-aggregated boolean expression.
343
+ All rule names provided here are given the prefix "check_".
289
344
  alias: An overwrite for this column's name which allows for using a column
290
345
  name that is not a valid Python identifier. Especially note that setting
291
346
  this option does _not_ allow to refer to the column with two different
@@ -317,10 +372,11 @@ class Datetime(OrdinalMixin[dt.datetime], Column):
317
372
  metadata=metadata,
318
373
  )
319
374
  self.resolution = resolution
375
+ self.time_zone = time_zone
320
376
 
321
377
  @property
322
378
  def dtype(self) -> pl.DataType:
323
- return pl.Datetime()
379
+ return pl.Datetime(time_zone=self.time_zone)
324
380
 
325
381
  def validation_rules(self, expr: pl.Expr) -> dict[str, pl.Expr]:
326
382
  result = super().validation_rules(expr)
@@ -329,16 +385,22 @@ class Datetime(OrdinalMixin[dt.datetime], Column):
329
385
  return result
330
386
 
331
387
  def sqlalchemy_dtype(self, dialect: sa.Dialect) -> sa_TypeEngine:
388
+ timezone_enabled = self.time_zone is not None
332
389
  match dialect.name:
333
390
  case "mssql":
334
391
  # sa.DateTime wrongly maps to DATETIME
335
- return sa_mssql.DATETIME2(6)
392
+ return sa_mssql.DATETIME2(6, timezone=timezone_enabled)
336
393
  case _:
337
- return sa.DateTime()
394
+ return sa.DateTime(timezone=timezone_enabled)
338
395
 
339
396
  @property
340
397
  def pyarrow_dtype(self) -> pa.DataType:
341
- return pa.timestamp("us")
398
+ time_zone = (
399
+ self.time_zone.tzname(None)
400
+ if isinstance(self.time_zone, dt.tzinfo)
401
+ else self.time_zone
402
+ )
403
+ return pa.timestamp("us", time_zone)
342
404
 
343
405
  def _sample_unchecked(self, generator: Generator, n: int) -> pl.Series:
344
406
  return generator.sample_datetime(
@@ -354,6 +416,7 @@ class Datetime(OrdinalMixin[dt.datetime], Column):
354
416
  allow_null_response=True,
355
417
  ),
356
418
  resolution=self.resolution,
419
+ time_zone=self.time_zone,
357
420
  null_probability=self._null_probability,
358
421
  )
359
422
 
@@ -364,20 +427,28 @@ class Duration(OrdinalMixin[dt.timedelta], Column):
364
427
  def __init__(
365
428
  self,
366
429
  *,
367
- nullable: bool = True,
430
+ nullable: bool | None = None,
368
431
  primary_key: bool = False,
369
432
  min: dt.timedelta | None = None,
370
433
  min_exclusive: dt.timedelta | None = None,
371
434
  max: dt.timedelta | None = None,
372
435
  max_exclusive: dt.timedelta | None = None,
373
436
  resolution: str | None = None,
374
- check: Callable[[pl.Expr], pl.Expr] | None = None,
437
+ check: (
438
+ Callable[[pl.Expr], pl.Expr]
439
+ | list[Callable[[pl.Expr], pl.Expr]]
440
+ | dict[str, Callable[[pl.Expr], pl.Expr]]
441
+ | None
442
+ ) = None,
375
443
  alias: str | None = None,
376
444
  metadata: dict[str, Any] | None = None,
377
445
  ):
378
446
  """
379
447
  Args:
380
448
  nullable: Whether this column may contain null values.
449
+ Explicitly set `nullable=True` if you want your column to be nullable.
450
+ In a future release, `nullable=False` will be the default if `nullable`
451
+ is not specified.
381
452
  primary_key: Whether this column is part of the primary key of the schema.
382
453
  If ``True``, ``nullable`` is automatically set to ``False``.
383
454
  min: The minimum duration for durations in this column (inclusive).
@@ -390,8 +461,17 @@ class Duration(OrdinalMixin[dt.timedelta], Column):
390
461
  the formatting language used by :mod:`polars` datetime ``round`` method.
391
462
  For example, a value ``1h`` expects all durations to be full hours. Note
392
463
  that this setting does *not* affect the storage resolution.
393
- check: A custom check to run for this column. Must return a non-aggregated
394
- boolean expression.
464
+ check: A custom rule or multiple rules to run for this column. This can be:
465
+ - A single callable that returns a non-aggregated boolean expression.
466
+ The name of the rule is derived from the callable name, or defaults to
467
+ "check" for lambdas.
468
+ - A list of callables, where each callable returns a non-aggregated
469
+ boolean expression. The name of the rule is derived from the callable
470
+ name, or defaults to "check" for lambdas. Where multiple rules result
471
+ in the same name, the suffix __i is appended to the name.
472
+ - A dictionary mapping rule names to callables, where each callable
473
+ returns a non-aggregated boolean expression.
474
+ All rule names provided here are given the prefix "check_".
395
475
  alias: An overwrite for this column's name which allows for using a column
396
476
  name that is not a valid Python identifier. Especially note that setting
397
477
  this option does _not_ allow to refer to the column with two different
@@ -27,13 +27,18 @@ class Decimal(OrdinalMixin[decimal.Decimal], Column):
27
27
  precision: int | None = None,
28
28
  scale: int = 0,
29
29
  *,
30
- nullable: bool = True,
30
+ nullable: bool | None = None,
31
31
  primary_key: bool = False,
32
32
  min: decimal.Decimal | None = None,
33
33
  min_exclusive: decimal.Decimal | None = None,
34
34
  max: decimal.Decimal | None = None,
35
35
  max_exclusive: decimal.Decimal | None = None,
36
- check: Callable[[pl.Expr], pl.Expr] | None = None,
36
+ check: (
37
+ Callable[[pl.Expr], pl.Expr]
38
+ | list[Callable[[pl.Expr], pl.Expr]]
39
+ | dict[str, Callable[[pl.Expr], pl.Expr]]
40
+ | None
41
+ ) = None,
37
42
  alias: str | None = None,
38
43
  metadata: dict[str, Any] | None = None,
39
44
  ):
@@ -42,6 +47,9 @@ class Decimal(OrdinalMixin[decimal.Decimal], Column):
42
47
  precision: Maximum number of digits in each number.
43
48
  scale: Number of digits to the right of the decimal point in each number.
44
49
  nullable: Whether this column may contain null values.
50
+ Explicitly set `nullable=True` if you want your column to be nullable.
51
+ In a future release, `nullable=False` will be the default if `nullable`
52
+ is not specified.
45
53
  primary_key: Whether this column is part of the primary key of the schema.
46
54
  If ``True``, ``nullable`` is automatically set to ``False``.
47
55
  min: The minimum value for decimals in this column (inclusive).
@@ -50,8 +58,17 @@ class Decimal(OrdinalMixin[decimal.Decimal], Column):
50
58
  max: The maximum value for decimals in this column (inclusive).
51
59
  max_exclusive: Like ``max`` but exclusive. May not be specified if ``max``
52
60
  is specified and vice versa.
53
- check: A custom check to run for this column. Must return a non-aggregated
54
- boolean expression.
61
+ check: A custom rule or multiple rules to run for this column. This can be:
62
+ - A single callable that returns a non-aggregated boolean expression.
63
+ The name of the rule is derived from the callable name, or defaults to
64
+ "check" for lambdas.
65
+ - A list of callables, where each callable returns a non-aggregated
66
+ boolean expression. The name of the rule is derived from the callable
67
+ name, or defaults to "check" for lambdas. Where multiple rules result
68
+ in the same name, the suffix __i is appended to the name.
69
+ - A dictionary mapping rule names to callables, where each callable
70
+ returns a non-aggregated boolean expression.
71
+ All rule names provided here are given the prefix "check_".
55
72
  alias: An overwrite for this column's name which allows for using a column
56
73
  name that is not a valid Python identifier. Especially note that setting
57
74
  this option does _not_ allow to refer to the column with two different
@@ -22,9 +22,14 @@ class Enum(Column):
22
22
  self,
23
23
  categories: Sequence[str],
24
24
  *,
25
- nullable: bool = True,
25
+ nullable: bool | None = None,
26
26
  primary_key: bool = False,
27
- check: Callable[[pl.Expr], pl.Expr] | None = None,
27
+ check: (
28
+ Callable[[pl.Expr], pl.Expr]
29
+ | list[Callable[[pl.Expr], pl.Expr]]
30
+ | dict[str, Callable[[pl.Expr], pl.Expr]]
31
+ | None
32
+ ) = None,
28
33
  alias: str | None = None,
29
34
  metadata: dict[str, Any] | None = None,
30
35
  ):
@@ -32,10 +37,22 @@ class Enum(Column):
32
37
  Args:
33
38
  categories: The list of valid categories for the enum.
34
39
  nullable: Whether this column may contain null values.
40
+ Explicitly set `nullable=True` if you want your column to be nullable.
41
+ In a future release, `nullable=False` will be the default if `nullable`
42
+ is not specified.
35
43
  primary_key: Whether this column is part of the primary key of the schema.
36
44
  If ``True``, ``nullable`` is automatically set to ``False``.
37
- check: A custom check to run for this column. Must return a non-aggregated
38
- boolean expression.
45
+ check: A custom rule or multiple rules to run for this column. This can be:
46
+ - A single callable that returns a non-aggregated boolean expression.
47
+ The name of the rule is derived from the callable name, or defaults to
48
+ "check" for lambdas.
49
+ - A list of callables, where each callable returns a non-aggregated
50
+ boolean expression. The name of the rule is derived from the callable
51
+ name, or defaults to "check" for lambdas. Where multiple rules result
52
+ in the same name, the suffix __i is appended to the name.
53
+ - A dictionary mapping rule names to callables, where each callable
54
+ returns a non-aggregated boolean expression.
55
+ All rule names provided here are given the prefix "check_".
39
56
  alias: An overwrite for this column's name which allows for using a column
40
57
  name that is not a valid Python identifier. Especially note that setting
41
58
  this option does _not_ allow to refer to the column with two different
@@ -26,20 +26,28 @@ class _BaseFloat(OrdinalMixin[float], Column):
26
26
  def __init__(
27
27
  self,
28
28
  *,
29
- nullable: bool = True,
29
+ nullable: bool | None = None,
30
30
  primary_key: bool = False,
31
31
  allow_inf_nan: bool = False,
32
32
  min: float | None = None,
33
33
  min_exclusive: float | None = None,
34
34
  max: float | None = None,
35
35
  max_exclusive: float | None = None,
36
- check: Callable[[pl.Expr], pl.Expr] | None = None,
36
+ check: (
37
+ Callable[[pl.Expr], pl.Expr]
38
+ | list[Callable[[pl.Expr], pl.Expr]]
39
+ | dict[str, Callable[[pl.Expr], pl.Expr]]
40
+ | None
41
+ ) = None,
37
42
  alias: str | None = None,
38
43
  metadata: dict[str, Any] | None = None,
39
44
  ):
40
45
  """
41
46
  Args:
42
47
  nullable: Whether this column may contain null values.
48
+ Explicitly set `nullable=True` if you want your column to be nullable.
49
+ In a future release, `nullable=False` will be the default if `nullable`
50
+ is not specified.
43
51
  primary_key: Whether this column is part of the primary key of the schema.
44
52
  If ``True``, ``nullable`` is automatically set to ``False``.
45
53
  allow_inf_nan: Whether this column may contain NaN and infinity values.
@@ -49,8 +57,17 @@ class _BaseFloat(OrdinalMixin[float], Column):
49
57
  max: The maximum value for floats in this column (inclusive).
50
58
  max_exclusive: Like ``max`` but exclusive. May not be specified if ``max``
51
59
  is specified and vice versa.
52
- check: A custom check to run for this column. Must return a non-aggregated
53
- boolean expression.
60
+ check: A custom rule or multiple rules to run for this column. This can be:
61
+ - A single callable that returns a non-aggregated boolean expression.
62
+ The name of the rule is derived from the callable name, or defaults to
63
+ "check" for lambdas.
64
+ - A list of callables, where each callable returns a non-aggregated
65
+ boolean expression. The name of the rule is derived from the callable
66
+ name, or defaults to "check" for lambdas. Where multiple rules result
67
+ in the same name, the suffix __i is appended to the name.
68
+ - A dictionary mapping rule names to callables, where each callable
69
+ returns a non-aggregated boolean expression.
70
+ All rule names provided here are given the prefix "check_".
54
71
  alias: An overwrite for this column's name which allows for using a column
55
72
  name that is not a valid Python identifier. Especially note that setting
56
73
  this option does _not_ allow to refer to the column with two different