dataframely 1.3.1__tar.gz → 1.5.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.
- {dataframely-1.3.1 → dataframely-1.5.0}/.copier-answers.yml +1 -1
- dataframely-1.5.0/.gitattributes +1 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/.github/workflows/build.yml +2 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/.github/workflows/chore.yml +4 -4
- {dataframely-1.3.1 → dataframely-1.5.0}/.github/workflows/ci.yml +5 -2
- dataframely-1.5.0/.github/workflows/scorecard.yml +79 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/PKG-INFO +3 -3
- dataframely-1.5.0/SECURITY.md +7 -0
- dataframely-1.5.0/dataframely/_deprecation.py +39 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/collection.py +8 -15
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/columns/_base.py +77 -5
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/columns/any.py +17 -3
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/columns/array.py +17 -3
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/columns/datetime.py +105 -20
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/columns/decimal.py +21 -4
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/columns/enum.py +21 -4
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/columns/float.py +21 -4
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/columns/integer.py +21 -4
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/columns/list.py +21 -4
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/columns/object.py +17 -3
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/columns/string.py +21 -4
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/columns/struct.py +21 -4
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/failure.py +20 -12
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/random.py +10 -2
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.columns.rst +16 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/index.rst +1 -1
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/sites/development.rst +1 -0
- dataframely-1.5.0/docs/sites/versioning.rst +20 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/pixi.lock +3591 -3676
- {dataframely-1.3.1 → dataframely-1.5.0}/pixi.toml +1 -1
- {dataframely-1.3.1 → dataframely-1.5.0}/pyproject.toml +5 -4
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/column_types/test_datetime.py +42 -2
- dataframely-1.5.0/tests/columns/test_check.py +68 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/columns/test_pyarrow.py +7 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/columns/test_sql_schema.py +2 -0
- dataframely-1.5.0/tests/test_deprecation.py +28 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/test_failure_info.py +33 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/test_typing.py +1 -1
- dataframely-1.3.1/.gitattributes +0 -1
- dataframely-1.3.1/tests/columns/test_check.py +0 -19
- {dataframely-1.3.1 → dataframely-1.5.0}/.envrc +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/.github/CODEOWNERS +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/.github/dependabot.yml +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/.github/release-drafter.yml +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/.gitignore +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/.pre-commit-config.yaml +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/.prettierignore +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/.prettierrc +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/.readthedocs.yml +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/Cargo.lock +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/Cargo.toml +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/LICENSE +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/README.md +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/__init__.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/_base_collection.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/_base_schema.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/_compat.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/_extre.pyi +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/_filter.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/_polars.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/_rule.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/_typing.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/_validation.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/columns/__init__.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/columns/_mixins.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/columns/_utils.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/columns/bool.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/config.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/exc.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/functional.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/mypy.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/py.typed +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/schema.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/testing/__init__.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/testing/const.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/testing/factory.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/testing/mask.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/testing/rules.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/dataframely/testing/typing.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docker-compose.yml +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/Makefile +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.collection.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.columns.any.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.columns.bool.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.columns.datetime.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.columns.decimal.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.columns.enum.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.columns.float.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.columns.integer.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.columns.list.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.columns.string.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.columns.struct.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.config.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.exc.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.failure.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.functional.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.mypy.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.random.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.schema.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.testing.const.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.testing.factory.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.testing.mask.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.testing.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.testing.rules.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/dataframely.testing.typing.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_api/modules.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_static/custom.css +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/_static/favicon.ico +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/conf.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/make.bat +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/sites/examples/real-world.ipynb +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/sites/faq.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/sites/installation.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/docs/sites/quickstart.rst +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/src/errdefs.rs +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/src/lib.rs +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/src/regex_repr.rs +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/collection/test_base.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/collection/test_cast.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/collection/test_create_empty.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/collection/test_filter_one_to_n.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/collection/test_filter_validate.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/collection/test_ignore_in_filter.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/collection/test_implementation.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/collection/test_optional_members.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/collection/test_sample.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/collection/test_validate_input.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/column_types/__init__.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/column_types/test_any.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/column_types/test_array.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/column_types/test_decimal.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/column_types/test_enum.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/column_types/test_float.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/column_types/test_integer.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/column_types/test_list.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/column_types/test_object.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/column_types/test_string.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/column_types/test_struct.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/columns/__init__.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/columns/test_alias.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/columns/test_default_dtypes.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/columns/test_metadata.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/columns/test_polars_schema.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/columns/test_rules.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/columns/test_sample.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/columns/test_str.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/columns/test_utils.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/core_validation/__init__.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/core_validation/test_column_validation.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/core_validation/test_dtype_validation.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/core_validation/test_rule_evaluation.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/functional/test_concat.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/functional/test_relationships.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/schema/test_base.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/schema/test_cast.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/schema/test_create_empty.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/schema/test_create_empty_if_none.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/schema/test_filter.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/schema/test_inheritance.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/schema/test_rule_implementation.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/schema/test_sample.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/schema/test_validate.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/test_compat.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/test_config.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/test_exc.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/test_extre.py +0 -0
- {dataframely-1.3.1 → dataframely-1.5.0}/tests/test_random.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pixi.lock merge=binary linguist-language=YAML linguist-generated=true
|
|
@@ -21,14 +21,14 @@ jobs:
|
|
|
21
21
|
steps:
|
|
22
22
|
- name: Check valid conventional commit message
|
|
23
23
|
id: lint
|
|
24
|
-
uses: amannn/action-semantic-pull-request@v5
|
|
24
|
+
uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 # v5.5.3
|
|
25
25
|
with:
|
|
26
26
|
subjectPattern: ^[A-Z].+[^. ]$ # subject must start with uppercase letter and may not end with a dot/space
|
|
27
27
|
env:
|
|
28
28
|
GITHUB_TOKEN: ${{ github.token }}
|
|
29
29
|
- name: Post comment about invalid PR title
|
|
30
30
|
if: failure()
|
|
31
|
-
uses: marocchino/sticky-pull-request-comment@v2
|
|
31
|
+
uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2.9.1
|
|
32
32
|
with:
|
|
33
33
|
header: conventional-commit-pr-title
|
|
34
34
|
message: |
|
|
@@ -45,7 +45,7 @@ jobs:
|
|
|
45
45
|
</details>
|
|
46
46
|
- name: Delete comment about invalid PR title
|
|
47
47
|
if: success()
|
|
48
|
-
uses: marocchino/sticky-pull-request-comment@v2
|
|
48
|
+
uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 # v2.9.1
|
|
49
49
|
with:
|
|
50
50
|
header: conventional-commit-pr-title
|
|
51
51
|
delete: true
|
|
@@ -58,7 +58,7 @@ jobs:
|
|
|
58
58
|
pull-requests: write
|
|
59
59
|
steps:
|
|
60
60
|
- name: ${{ github.event_name == 'pull_request_target' && 'Assign labels' || 'Update release draft' }}
|
|
61
|
-
uses: release-drafter/release-drafter@v6
|
|
61
|
+
uses: release-drafter/release-drafter@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6.1.0
|
|
62
62
|
with:
|
|
63
63
|
disable-releaser: ${{ github.event_name == 'pull_request_target' }}
|
|
64
64
|
disable-autolabeler: ${{ github.event_name == 'push' }}
|
|
@@ -9,6 +9,9 @@ concurrency:
|
|
|
9
9
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
10
|
cancel-in-progress: true
|
|
11
11
|
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
12
15
|
jobs:
|
|
13
16
|
pre-commit-checks:
|
|
14
17
|
name: Pre-commit Checks
|
|
@@ -40,7 +43,7 @@ jobs:
|
|
|
40
43
|
environment: [py311, py312, py313]
|
|
41
44
|
steps:
|
|
42
45
|
- name: Checkout branch
|
|
43
|
-
uses: actions/checkout@v4
|
|
46
|
+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
44
47
|
- name: Set up pixi
|
|
45
48
|
uses: prefix-dev/setup-pixi@19eac09b398e3d0c747adc7921926a6d802df4da # v0.8.8
|
|
46
49
|
with:
|
|
@@ -50,7 +53,7 @@ jobs:
|
|
|
50
53
|
- name: Run pytest
|
|
51
54
|
run: pixi run -e ${{ matrix.environment }} test-coverage --color=yes
|
|
52
55
|
- name: Upload codecov
|
|
53
|
-
uses: codecov/codecov-action@v5
|
|
56
|
+
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
|
|
54
57
|
with:
|
|
55
58
|
files: ./coverage.xml
|
|
56
59
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub. They are provided
|
|
2
|
+
# by a third-party and are governed by separate terms of service, privacy
|
|
3
|
+
# policy, and support documentation.
|
|
4
|
+
|
|
5
|
+
name: Scorecard supply-chain security
|
|
6
|
+
on:
|
|
7
|
+
# For Branch-Protection check. Only the default branch is supported. See
|
|
8
|
+
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
|
|
9
|
+
branch_protection_rule:
|
|
10
|
+
# To guarantee Maintained check is occasionally updated. See
|
|
11
|
+
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
|
|
12
|
+
schedule:
|
|
13
|
+
- cron: "34 5 * * 0"
|
|
14
|
+
workflow_dispatch:
|
|
15
|
+
push:
|
|
16
|
+
branches: ["main"]
|
|
17
|
+
|
|
18
|
+
# Declare default permissions as read only.
|
|
19
|
+
permissions: read-all
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
analysis:
|
|
23
|
+
name: Scorecard analysis
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
# `publish_results: true` only works when run from the default branch. conditional can be removed if disabled.
|
|
26
|
+
if: (github.event.repository.default_branch == github.ref_name || github.event_name == 'pull_request') && github.repository == 'quantco/dataframely'
|
|
27
|
+
permissions:
|
|
28
|
+
# Needed to upload the results to code-scanning dashboard.
|
|
29
|
+
security-events: write
|
|
30
|
+
# Needed to publish results and get a badge (see publish_results below).
|
|
31
|
+
id-token: write
|
|
32
|
+
# Uncomment the permissions below if installing in a private repository.
|
|
33
|
+
# contents: read
|
|
34
|
+
# actions: read
|
|
35
|
+
|
|
36
|
+
steps:
|
|
37
|
+
- name: "Checkout code"
|
|
38
|
+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
39
|
+
with:
|
|
40
|
+
persist-credentials: false
|
|
41
|
+
|
|
42
|
+
- name: "Run analysis"
|
|
43
|
+
uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
|
|
44
|
+
with:
|
|
45
|
+
results_file: results.sarif
|
|
46
|
+
results_format: sarif
|
|
47
|
+
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
|
|
48
|
+
# - you want to enable the Branch-Protection check on a *public* repository, or
|
|
49
|
+
# - you are installing Scorecard on a *private* repository
|
|
50
|
+
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional.
|
|
51
|
+
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
|
|
52
|
+
|
|
53
|
+
# Public repositories:
|
|
54
|
+
# - Publish results to OpenSSF REST API for easy access by consumers
|
|
55
|
+
# - Allows the repository to include the Scorecard badge.
|
|
56
|
+
# - See https://github.com/ossf/scorecard-action#publishing-results.
|
|
57
|
+
# For private repositories:
|
|
58
|
+
# - `publish_results` will always be set to `false`, regardless
|
|
59
|
+
# of the value entered here.
|
|
60
|
+
publish_results: true
|
|
61
|
+
|
|
62
|
+
# (Optional) Uncomment file_mode if you have a .gitattributes with files marked export-ignore
|
|
63
|
+
# file_mode: git
|
|
64
|
+
|
|
65
|
+
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
|
66
|
+
# format to the repository Actions tab.
|
|
67
|
+
- name: "Upload artifact"
|
|
68
|
+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
|
69
|
+
with:
|
|
70
|
+
name: SARIF file
|
|
71
|
+
path: results.sarif
|
|
72
|
+
retention-days: 5
|
|
73
|
+
|
|
74
|
+
# Upload the results to GitHub's code scanning dashboard (optional).
|
|
75
|
+
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
|
|
76
|
+
- name: "Upload to code-scanning"
|
|
77
|
+
uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
|
|
78
|
+
with:
|
|
79
|
+
sarif_file: results.sarif
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dataframely
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.0
|
|
4
4
|
Classifier: Programming Language :: Python :: 3
|
|
5
5
|
Classifier: Programming Language :: Python :: 3.11
|
|
6
6
|
Classifier: Programming Language :: Python :: 3.12
|
|
7
7
|
Classifier: Programming Language :: Python :: 3.13
|
|
8
8
|
Requires-Dist: numpy
|
|
9
|
-
Requires-Dist: polars>=1.
|
|
9
|
+
Requires-Dist: polars>=1.30
|
|
10
10
|
License-File: LICENSE
|
|
11
11
|
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,7 @@
|
|
|
1
|
+
# Reporting Security Issues
|
|
2
|
+
|
|
3
|
+
We take security bugs in our projects seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
|
|
4
|
+
|
|
5
|
+
To report a security issue, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/quantco/dataframely/security/advisories/new) tab.
|
|
6
|
+
|
|
7
|
+
We will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.
|
|
@@ -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
|
+
)
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
# Copyright (c) QuantCo 2025-2025
|
|
2
2
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
3
3
|
|
|
4
|
-
import sys
|
|
5
4
|
import warnings
|
|
6
5
|
from abc import ABC
|
|
7
6
|
from collections.abc import Mapping, Sequence
|
|
8
7
|
from pathlib import Path
|
|
9
|
-
from typing import Any,
|
|
8
|
+
from typing import Any, Self, cast
|
|
10
9
|
|
|
11
10
|
import polars as pl
|
|
12
11
|
import polars.exceptions as plexc
|
|
@@ -18,15 +17,8 @@ from ._polars import FrameType, join_all_inner, join_all_outer
|
|
|
18
17
|
from .failure import FailureInfo
|
|
19
18
|
from .random import Generator
|
|
20
19
|
|
|
21
|
-
if sys.version_info >= (3, 13):
|
|
22
|
-
SamplingType = TypeVar(
|
|
23
|
-
"SamplingType", bound=Mapping[str, Any], default=Mapping[str, Any]
|
|
24
|
-
)
|
|
25
|
-
else: # pragma: no cover
|
|
26
|
-
SamplingType = TypeVar("SamplingType", bound=Mapping[str, Any])
|
|
27
20
|
|
|
28
|
-
|
|
29
|
-
class Collection(BaseCollection, ABC, Generic[SamplingType]):
|
|
21
|
+
class Collection(BaseCollection, ABC):
|
|
30
22
|
"""Base class for all collections of data frames with a predefined schema.
|
|
31
23
|
|
|
32
24
|
A collection is comprised of a set of *members* which are collectively "consistent",
|
|
@@ -86,7 +78,7 @@ class Collection(BaseCollection, ABC, Generic[SamplingType]):
|
|
|
86
78
|
cls,
|
|
87
79
|
num_rows: int | None = None,
|
|
88
80
|
*,
|
|
89
|
-
overrides: Sequence[
|
|
81
|
+
overrides: Sequence[Mapping[str, Any]] | None = None,
|
|
90
82
|
generator: Generator | None = None,
|
|
91
83
|
) -> Self:
|
|
92
84
|
"""Create a random sample from the members of this collection.
|
|
@@ -162,10 +154,11 @@ class Collection(BaseCollection, ABC, Generic[SamplingType]):
|
|
|
162
154
|
samples = (
|
|
163
155
|
overrides
|
|
164
156
|
if overrides is not None
|
|
165
|
-
else [
|
|
157
|
+
else [{} for _ in range(cast(int, num_rows))]
|
|
166
158
|
)
|
|
167
159
|
processed_samples = [
|
|
168
|
-
cls._preprocess_sample(sample, i, g)
|
|
160
|
+
cls._preprocess_sample(dict(sample.items()), i, g)
|
|
161
|
+
for i, sample in enumerate(samples)
|
|
169
162
|
]
|
|
170
163
|
|
|
171
164
|
# 2) Ensure that all samples have primary keys assigned to ensure that we
|
|
@@ -234,8 +227,8 @@ class Collection(BaseCollection, ABC, Generic[SamplingType]):
|
|
|
234
227
|
|
|
235
228
|
@classmethod
|
|
236
229
|
def _preprocess_sample(
|
|
237
|
-
cls, sample:
|
|
238
|
-
) ->
|
|
230
|
+
cls, sample: dict[str, Any], index: int, generator: Generator
|
|
231
|
+
) -> dict[str, Any]:
|
|
239
232
|
"""Overridable method to preprocess a sample passed to :meth:`sample`.
|
|
240
233
|
|
|
241
234
|
The purpose of this method is to (1) set the primary key columns to enable
|
|
@@ -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 =
|
|
33
|
+
nullable: bool | None = None,
|
|
32
34
|
primary_key: bool = False,
|
|
33
|
-
check:
|
|
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
|
|
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
|
-
|
|
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:
|
|
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
|
|
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:
|
|
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
|
|
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
|