dataframely 1.4.0__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.4.0 → dataframely-1.5.0}/.copier-answers.yml +1 -1
- dataframely-1.5.0/.gitattributes +1 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/.github/workflows/build.yml +2 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/.github/workflows/chore.yml +4 -4
- {dataframely-1.4.0 → dataframely-1.5.0}/.github/workflows/ci.yml +5 -2
- dataframely-1.5.0/.github/workflows/scorecard.yml +79 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/PKG-INFO +2 -2
- dataframely-1.5.0/SECURITY.md +7 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/collection.py +8 -15
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/columns/datetime.py +7 -2
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/failure.py +20 -12
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/random.py +6 -2
- {dataframely-1.4.0 → dataframely-1.5.0}/pixi.lock +3591 -3676
- {dataframely-1.4.0 → dataframely-1.5.0}/pixi.toml +1 -1
- {dataframely-1.4.0 → dataframely-1.5.0}/pyproject.toml +2 -2
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/column_types/test_datetime.py +7 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/columns/test_pyarrow.py +7 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/test_failure_info.py +33 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/test_typing.py +1 -1
- dataframely-1.4.0/.gitattributes +0 -1
- {dataframely-1.4.0 → dataframely-1.5.0}/.envrc +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/.github/CODEOWNERS +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/.github/dependabot.yml +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/.github/release-drafter.yml +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/.gitignore +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/.pre-commit-config.yaml +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/.prettierignore +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/.prettierrc +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/.readthedocs.yml +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/Cargo.lock +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/Cargo.toml +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/LICENSE +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/README.md +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/__init__.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/_base_collection.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/_base_schema.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/_compat.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/_deprecation.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/_extre.pyi +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/_filter.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/_polars.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/_rule.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/_typing.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/_validation.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/columns/__init__.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/columns/_base.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/columns/_mixins.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/columns/_utils.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/columns/any.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/columns/array.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/columns/bool.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/columns/decimal.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/columns/enum.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/columns/float.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/columns/integer.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/columns/list.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/columns/object.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/columns/string.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/columns/struct.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/config.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/exc.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/functional.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/mypy.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/py.typed +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/schema.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/testing/__init__.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/testing/const.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/testing/factory.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/testing/mask.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/testing/rules.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/dataframely/testing/typing.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docker-compose.yml +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/Makefile +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.collection.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.columns.any.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.columns.bool.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.columns.datetime.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.columns.decimal.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.columns.enum.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.columns.float.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.columns.integer.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.columns.list.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.columns.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.columns.string.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.columns.struct.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.config.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.exc.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.failure.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.functional.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.mypy.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.random.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.schema.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.testing.const.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.testing.factory.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.testing.mask.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.testing.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.testing.rules.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/dataframely.testing.typing.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_api/modules.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_static/custom.css +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/_static/favicon.ico +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/conf.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/index.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/make.bat +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/sites/development.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/sites/examples/real-world.ipynb +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/sites/faq.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/sites/installation.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/sites/quickstart.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/docs/sites/versioning.rst +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/src/errdefs.rs +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/src/lib.rs +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/src/regex_repr.rs +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/collection/test_base.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/collection/test_cast.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/collection/test_create_empty.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/collection/test_filter_one_to_n.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/collection/test_filter_validate.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/collection/test_ignore_in_filter.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/collection/test_implementation.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/collection/test_optional_members.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/collection/test_sample.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/collection/test_validate_input.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/column_types/__init__.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/column_types/test_any.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/column_types/test_array.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/column_types/test_decimal.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/column_types/test_enum.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/column_types/test_float.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/column_types/test_integer.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/column_types/test_list.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/column_types/test_object.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/column_types/test_string.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/column_types/test_struct.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/columns/__init__.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/columns/test_alias.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/columns/test_check.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/columns/test_default_dtypes.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/columns/test_metadata.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/columns/test_polars_schema.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/columns/test_rules.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/columns/test_sample.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/columns/test_sql_schema.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/columns/test_str.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/columns/test_utils.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/core_validation/__init__.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/core_validation/test_column_validation.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/core_validation/test_dtype_validation.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/core_validation/test_rule_evaluation.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/functional/test_concat.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/functional/test_relationships.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/schema/test_base.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/schema/test_cast.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/schema/test_create_empty.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/schema/test_create_empty_if_none.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/schema/test_filter.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/schema/test_inheritance.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/schema/test_rule_implementation.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/schema/test_sample.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/schema/test_validate.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/test_compat.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/test_config.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/test_deprecation.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/test_exc.py +0 -0
- {dataframely-1.4.0 → dataframely-1.5.0}/tests/test_extre.py +0 -0
- {dataframely-1.4.0 → 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,12 +1,12 @@
|
|
|
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>
|
|
@@ -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.
|
|
@@ -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
|
|
@@ -8,6 +8,7 @@ from collections.abc import Callable
|
|
|
8
8
|
from typing import Any, cast
|
|
9
9
|
|
|
10
10
|
import polars as pl
|
|
11
|
+
from polars._typing import TimeUnit
|
|
11
12
|
|
|
12
13
|
from dataframely._compat import pa, sa, sa_mssql, sa_TypeEngine
|
|
13
14
|
from dataframely._polars import (
|
|
@@ -300,6 +301,7 @@ class Datetime(OrdinalMixin[dt.datetime], Column):
|
|
|
300
301
|
max_exclusive: dt.datetime | None = None,
|
|
301
302
|
resolution: str | None = None,
|
|
302
303
|
time_zone: str | dt.tzinfo | None = None,
|
|
304
|
+
time_unit: TimeUnit = "us",
|
|
303
305
|
check: (
|
|
304
306
|
Callable[[pl.Expr], pl.Expr]
|
|
305
307
|
| list[Callable[[pl.Expr], pl.Expr]]
|
|
@@ -330,6 +332,7 @@ class Datetime(OrdinalMixin[dt.datetime], Column):
|
|
|
330
332
|
time_zone: The time zone that datetimes in the column must have. The time
|
|
331
333
|
zone must use a valid IANA time zone name identifier e.x. ``Etc/UTC`` or
|
|
332
334
|
``America/New_York``.
|
|
335
|
+
time_unit: Unit of time. Defaults to ``us`` (microseconds).
|
|
333
336
|
check: A custom rule or multiple rules to run for this column. This can be:
|
|
334
337
|
- A single callable that returns a non-aggregated boolean expression.
|
|
335
338
|
The name of the rule is derived from the callable name, or defaults to
|
|
@@ -373,10 +376,11 @@ class Datetime(OrdinalMixin[dt.datetime], Column):
|
|
|
373
376
|
)
|
|
374
377
|
self.resolution = resolution
|
|
375
378
|
self.time_zone = time_zone
|
|
379
|
+
self.time_unit = time_unit
|
|
376
380
|
|
|
377
381
|
@property
|
|
378
382
|
def dtype(self) -> pl.DataType:
|
|
379
|
-
return pl.Datetime(time_zone=self.time_zone)
|
|
383
|
+
return pl.Datetime(time_zone=self.time_zone, time_unit=self.time_unit)
|
|
380
384
|
|
|
381
385
|
def validation_rules(self, expr: pl.Expr) -> dict[str, pl.Expr]:
|
|
382
386
|
result = super().validation_rules(expr)
|
|
@@ -400,7 +404,7 @@ class Datetime(OrdinalMixin[dt.datetime], Column):
|
|
|
400
404
|
if isinstance(self.time_zone, dt.tzinfo)
|
|
401
405
|
else self.time_zone
|
|
402
406
|
)
|
|
403
|
-
return pa.timestamp(
|
|
407
|
+
return pa.timestamp(self.time_unit, time_zone)
|
|
404
408
|
|
|
405
409
|
def _sample_unchecked(self, generator: Generator, n: int) -> pl.Series:
|
|
406
410
|
return generator.sample_datetime(
|
|
@@ -416,6 +420,7 @@ class Datetime(OrdinalMixin[dt.datetime], Column):
|
|
|
416
420
|
allow_null_response=True,
|
|
417
421
|
),
|
|
418
422
|
resolution=self.resolution,
|
|
423
|
+
time_unit=self.time_unit,
|
|
419
424
|
time_zone=self.time_zone,
|
|
420
425
|
null_probability=self._null_probability,
|
|
421
426
|
)
|
|
@@ -79,17 +79,13 @@ class FailureInfo(Generic[S]):
|
|
|
79
79
|
Args:
|
|
80
80
|
file: The file path or writable file-like object to write to.
|
|
81
81
|
"""
|
|
82
|
-
# NOTE: We add a dummy column with metadata in the column name to allow writing
|
|
83
|
-
# the rule columns and schema to the same file.
|
|
84
82
|
metadata_json = json.dumps(
|
|
85
83
|
{
|
|
86
84
|
"rule_columns": self._rule_columns,
|
|
87
85
|
"schema": f"{self.schema.__module__}.{self.schema.__name__}",
|
|
88
86
|
}
|
|
89
87
|
)
|
|
90
|
-
self._df.
|
|
91
|
-
pl.lit(None).alias(metadata_json),
|
|
92
|
-
).write_parquet(file)
|
|
88
|
+
self._df.write_parquet(file, metadata={"dataframely": metadata_json})
|
|
93
89
|
|
|
94
90
|
@classmethod
|
|
95
91
|
def scan_parquet(cls, source: str | Path | IO[bytes]) -> Self:
|
|
@@ -102,15 +98,27 @@ class FailureInfo(Generic[S]):
|
|
|
102
98
|
The failure info object.
|
|
103
99
|
"""
|
|
104
100
|
lf = pl.scan_parquet(source)
|
|
105
|
-
|
|
106
|
-
#
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
rule_columns
|
|
110
|
-
|
|
101
|
+
|
|
102
|
+
# We can read the rule columns either from the metadata of the Parquet file
|
|
103
|
+
# or, to remain backwards-compatible, from the last column of the lazy frame if
|
|
104
|
+
# the parquet file is missing metadata.
|
|
105
|
+
rule_columns: list[str]
|
|
106
|
+
schema_name: str
|
|
107
|
+
if (meta := pl.read_parquet_metadata(source).get("dataframely")) is not None:
|
|
108
|
+
metadata = json.loads(meta)
|
|
109
|
+
rule_columns = metadata["rule_columns"]
|
|
110
|
+
schema_name = metadata["schema"]
|
|
111
|
+
else:
|
|
112
|
+
last_column = lf.collect_schema().names()[-1]
|
|
113
|
+
metadata = json.loads(last_column)
|
|
114
|
+
rule_columns = metadata["rule_columns"]
|
|
115
|
+
schema_name = metadata["schema"]
|
|
116
|
+
lf = lf.drop(last_column)
|
|
117
|
+
|
|
118
|
+
*schema_module_parts, schema_name = schema_name.split(".")
|
|
111
119
|
module = importlib.import_module(".".join(schema_module_parts))
|
|
112
120
|
schema = cast(type[S], getattr(module, schema_name))
|
|
113
|
-
return cls(lf
|
|
121
|
+
return cls(lf, rule_columns, schema=schema)
|
|
114
122
|
|
|
115
123
|
|
|
116
124
|
# ------------------------------------ COMPUTATION ----------------------------------- #
|
|
@@ -7,6 +7,7 @@ from typing import TypeVar
|
|
|
7
7
|
|
|
8
8
|
import numpy as np
|
|
9
9
|
import polars as pl
|
|
10
|
+
from polars._typing import TimeUnit
|
|
10
11
|
|
|
11
12
|
from ._extre import sample as extre_sample
|
|
12
13
|
from ._polars import (
|
|
@@ -294,6 +295,7 @@ class Generator:
|
|
|
294
295
|
max: dt.datetime | None,
|
|
295
296
|
resolution: str | None = None,
|
|
296
297
|
time_zone: str | dt.tzinfo | None = None,
|
|
298
|
+
time_unit: TimeUnit = "us",
|
|
297
299
|
null_probability: float = 0.0,
|
|
298
300
|
) -> pl.Series:
|
|
299
301
|
"""Sample a list of datetimes in the provided range.
|
|
@@ -303,7 +305,9 @@ class Generator:
|
|
|
303
305
|
min: The minimum datetime to sample (inclusive).
|
|
304
306
|
max: The maximum datetime to sample (exclusive). '10000-01-01' when ``None``.
|
|
305
307
|
resolution: The resolution that datetimes in the column must have. This uses
|
|
306
|
-
the formatting language used by :mod:`polars` datetime ``round``
|
|
308
|
+
the formatting language used by :mod:`polars` datetime ``round``
|
|
309
|
+
method.
|
|
310
|
+
time_unit: The time unit of the datetime column. Defaults to ``us`` (microseconds).
|
|
307
311
|
time_zone: The time zone that datetimes in the column must have. The time
|
|
308
312
|
zone must use a valid IANA time zone name identifier e.x. ``Etc/UTC`` or
|
|
309
313
|
``America/New_York``.
|
|
@@ -333,7 +337,7 @@ class Generator:
|
|
|
333
337
|
)
|
|
334
338
|
# NOTE: polars tracks datetimes relative to epoch
|
|
335
339
|
- _datetime_to_microseconds(EPOCH_DATETIME)
|
|
336
|
-
).cast(pl.Datetime(time_zone=time_zone))
|
|
340
|
+
).cast(pl.Datetime(time_unit=time_unit, time_zone=time_zone))
|
|
337
341
|
|
|
338
342
|
if resolution is not None:
|
|
339
343
|
return result.dt.truncate(resolution)
|