dataframely 2.3.1__tar.gz → 2.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.
- {dataframely-2.3.1 → dataframely-2.4.0}/.github/copilot-instructions.md +23 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/PKG-INFO +1 -1
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_base_schema.py +13 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/decimal.py +5 -1
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/list.py +5 -2
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/string.py +4 -2
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/schema.py +58 -19
- {dataframely-2.3.1 → dataframely-2.4.0}/pyproject.toml +1 -1
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_sample.py +13 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/column_types/test_decimal.py +56 -1
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/column_types/test_list.py +13 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/columns/test_str.py +17 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/schema/test_base.py +16 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/schema/test_sample.py +26 -17
- {dataframely-2.3.1 → dataframely-2.4.0}/.copier-answers.yml +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.envrc +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.gitattributes +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.github/CODEOWNERS +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.github/dependabot.yml +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.github/instructions/tests.instructions.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.github/release-drafter.yml +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.github/workflows/build.yml +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.github/workflows/chore.yml +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.github/workflows/ci.yml +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.github/workflows/copilot-setup-steps.yml +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.github/workflows/nightly.yml +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.github/workflows/scorecard.yml +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.gitignore +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.pre-commit-config.yaml +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.prettierignore +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.prettierrc +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/.readthedocs.yml +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/Cargo.lock +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/Cargo.toml +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/LICENSE +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/README.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/SECURITY.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/__init__.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_compat.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_deprecation.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_filter.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_match_to_schema.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_native.pyi +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_plugin.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_polars.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_pydantic.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_rule.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_serialization.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_storage/__init__.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_storage/_base.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_storage/_exc.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_storage/constants.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_storage/delta.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_storage/parquet.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/_typing.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/collection/__init__.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/collection/_base.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/collection/collection.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/collection/filter_result.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/__init__.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/_base.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/_mixins.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/_registry.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/_utils.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/any.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/array.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/binary.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/bool.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/categorical.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/datetime.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/enum.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/float.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/integer.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/object.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/columns/struct.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/config.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/exc.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/filter_result.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/functional.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/py.typed +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/random.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/testing/__init__.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/testing/const.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/testing/factory.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/testing/mask.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/testing/rules.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/dataframely/testing/storage.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docker-compose.yml +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/_static/custom.css +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/_static/favicon.ico +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/_templates/autosummary/class.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/_templates/autosummary/method.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/_templates/classes/column.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/_templates/classes/error.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/_templates/classes/filter_result.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/collection/generation.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/collection/index.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/collection/io.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/collection/metadata.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/collection/operations.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/collection/validation.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/columns/index.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/errors/index.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/filter_result/failure_info.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/filter_result/index.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/index.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/misc/index.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/schema/conversion.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/schema/generation.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/schema/index.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/schema/io.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/schema/metadata.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/api/schema/validation.rst +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/conf.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/css/custom.css +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/guides/development.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/guides/examples/index.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/guides/examples/real-world.ipynb +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/guides/faq.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/guides/features/column-metadata.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/guides/features/data-generation.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/guides/features/index.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/guides/features/lazy-validation.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/guides/features/primary-keys.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/guides/features/serialization.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/guides/features/sql-generation.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/guides/index.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/guides/migration/index.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/guides/migration/v1-v2.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/guides/quickstart.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/docs/index.md +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/pixi.lock +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/pixi.toml +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/rust-toolchain.toml +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/src/lib.rs +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/src/polars_plugin/mod.rs +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/src/polars_plugin/rule_failure.rs +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/src/polars_plugin/utils.rs +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/src/polars_plugin/validation_error.rs +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/src/regex/errdefs.rs +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/src/regex/mod.rs +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/src/regex/repr.rs +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/benches/conftest.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/benches/test_collection.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/benches/test_failure.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/benches/test_schema.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_base.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_cast.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_collection_future_annotations.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_create_empty.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_filter_one_to_n.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_filter_validate.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_ignore_in_filter.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_implementation.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_join.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_matches.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_optional_members.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_propagate_row_failures.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_repr.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_serialization.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_storage.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/collection/test_validate_input.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/column_types/__init__.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/column_types/test_any.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/column_types/test_array.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/column_types/test_binary.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/column_types/test_datetime.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/column_types/test_enum.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/column_types/test_float.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/column_types/test_integer.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/column_types/test_object.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/column_types/test_string.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/column_types/test_struct.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/columns/__init__.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/columns/test_alias.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/columns/test_base.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/columns/test_check.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/columns/test_default_dtypes.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/columns/test_matches.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/columns/test_metadata.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/columns/test_polars_schema.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/columns/test_pyarrow.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/columns/test_rules.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/columns/test_sample.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/columns/test_sqlalchemy_columns.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/columns/test_utils.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/conftest.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/core_validation/__init__.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/core_validation/test_match_to_schema.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/core_validation/test_rule_evaluation.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/failure_info/test_storage.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/functional/test_concat.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/functional/test_relationships.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/schema/test_cast.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/schema/test_create_empty.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/schema/test_create_empty_if_none.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/schema/test_filter.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/schema/test_inheritance.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/schema/test_matches.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/schema/test_read_write_parquet.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/schema/test_repr.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/schema/test_rule_implementation.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/schema/test_serialization.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/schema/test_storage.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/schema/test_validate.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/storage/test_delta.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/test_compat.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/test_config.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/test_deprecation.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/test_factory.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/test_native_regex.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/test_pydantic.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/test_random.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/test_serialization.py +0 -0
- {dataframely-2.3.1 → dataframely-2.4.0}/tests/test_typing.py +0 -0
|
@@ -206,6 +206,29 @@ validated_df: dy.DataFrame[MySchema] = MySchema.validate(df, cast=True)
|
|
|
206
206
|
4. **Documentation**: Update docstrings
|
|
207
207
|
5. **API changes**: Ensure backward compatibility or document migration path
|
|
208
208
|
|
|
209
|
+
### Pull request titles (required)
|
|
210
|
+
|
|
211
|
+
Pull request titles must follow the Conventional Commits format: `<type>[!]: <Subject>`
|
|
212
|
+
|
|
213
|
+
Allowed `type` values:
|
|
214
|
+
|
|
215
|
+
- `feat`: A new feature
|
|
216
|
+
- `fix`: A bug fix
|
|
217
|
+
- `docs`: Documentation only changes
|
|
218
|
+
- `style`: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
|
|
219
|
+
- `refactor`: A code change that neither fixes a bug nor adds a feature
|
|
220
|
+
- `perf`: A code change that improves performance
|
|
221
|
+
- `test`: Adding missing tests or correcting existing tests
|
|
222
|
+
- `build`: Changes that affect the build system or external dependencies
|
|
223
|
+
- `ci`: Changes to our CI configuration files and scripts
|
|
224
|
+
- `chore`: Other changes that don't modify src or test files
|
|
225
|
+
- `revert`: Reverts a previous commit
|
|
226
|
+
|
|
227
|
+
Additional rules:
|
|
228
|
+
|
|
229
|
+
- Use `!` only for **breaking changes**
|
|
230
|
+
- `Subject` must start with an **uppercase** letter and must **not** end with `.` or a trailing space
|
|
231
|
+
|
|
209
232
|
## Performance Considerations
|
|
210
233
|
|
|
211
234
|
- Validation uses native polars expressions for performance
|
|
@@ -162,6 +162,19 @@ class SchemaMeta(ABCMeta):
|
|
|
162
162
|
f"Did you forget to add parentheses?"
|
|
163
163
|
)
|
|
164
164
|
|
|
165
|
+
# Check for pl.DataType instance or type (e.g., pl.String() or pl.String instead of dy.String())
|
|
166
|
+
if isinstance(value, pl.DataType) or (
|
|
167
|
+
isinstance(value, type) and issubclass(value, pl.DataType)
|
|
168
|
+
):
|
|
169
|
+
value_type = "instance" if isinstance(value, pl.DataType) else "type"
|
|
170
|
+
example = (
|
|
171
|
+
"pl.String()" if isinstance(value, pl.DataType) else "pl.String"
|
|
172
|
+
)
|
|
173
|
+
raise TypeError(
|
|
174
|
+
f"Schema member '{attr}' is a polars DataType {value_type}. "
|
|
175
|
+
f"Use dataframely column types (e.g., dy.String()) instead of polars types (e.g., {example})."
|
|
176
|
+
)
|
|
177
|
+
|
|
165
178
|
return cls
|
|
166
179
|
|
|
167
180
|
if not TYPE_CHECKING:
|
|
@@ -98,7 +98,11 @@ class Decimal(OrdinalMixin[decimal.Decimal], Column):
|
|
|
98
98
|
return pl.Decimal(self.precision, self.scale)
|
|
99
99
|
|
|
100
100
|
def validate_dtype(self, dtype: PolarsDataType) -> bool:
|
|
101
|
-
return
|
|
101
|
+
return (
|
|
102
|
+
isinstance(dtype, pl.Decimal)
|
|
103
|
+
and dtype.scale == self.scale
|
|
104
|
+
and (self.precision is None or dtype.precision == self.precision)
|
|
105
|
+
)
|
|
102
106
|
|
|
103
107
|
def sqlalchemy_dtype(self, dialect: sa.Dialect) -> sa_TypeEngine:
|
|
104
108
|
if self.scale and not self.precision:
|
|
@@ -131,9 +131,12 @@ class List(Column):
|
|
|
131
131
|
def _sample_unchecked(self, generator: Generator, n: int) -> pl.Series:
|
|
132
132
|
# First, sample the number of items per list element
|
|
133
133
|
# NOTE: We default to 32 for the upper bound as we need some kind of reasonable
|
|
134
|
-
# upper bound if none is set.
|
|
134
|
+
# upper bound if none is set. If min_length is greater than 32, we use
|
|
135
|
+
# min_length as the default upper bound instead.
|
|
136
|
+
min_len = self.min_length or 0
|
|
137
|
+
default_max = max(32, min_len)
|
|
135
138
|
element_lengths = generator.sample_int(
|
|
136
|
-
n, min=
|
|
139
|
+
n, min=min_len, max=(self.max_length or default_max) + 1
|
|
137
140
|
)
|
|
138
141
|
|
|
139
142
|
# Then, we can sample the inner elements in a flat series
|
|
@@ -14,6 +14,8 @@ from dataframely.random import Generator
|
|
|
14
14
|
from ._base import Check, Column
|
|
15
15
|
from ._registry import register
|
|
16
16
|
|
|
17
|
+
DEFAULT_SAMPLING_REGEX = r"[0-9a-zA-Z]"
|
|
18
|
+
|
|
17
19
|
|
|
18
20
|
@register
|
|
19
21
|
class String(Column):
|
|
@@ -126,9 +128,9 @@ class String(Column):
|
|
|
126
128
|
str_max = f"{self.max_length}" if self.max_length is not None else ""
|
|
127
129
|
# NOTE: We generate single-byte unicode characters here as validation uses
|
|
128
130
|
# `len_bytes()`. Potentially we need to be more accurate at some point...
|
|
129
|
-
regex = f"
|
|
131
|
+
regex = f"{DEFAULT_SAMPLING_REGEX}{{{str_min},{str_max}}}"
|
|
130
132
|
else:
|
|
131
|
-
regex =
|
|
133
|
+
regex = rf"{DEFAULT_SAMPLING_REGEX}*"
|
|
132
134
|
|
|
133
135
|
return generator.sample_string(
|
|
134
136
|
n,
|
|
@@ -7,7 +7,7 @@ import json
|
|
|
7
7
|
import sys
|
|
8
8
|
import warnings
|
|
9
9
|
from abc import ABC
|
|
10
|
-
from collections.abc import
|
|
10
|
+
from collections.abc import Mapping, Sequence
|
|
11
11
|
from json import JSONDecodeError
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
from typing import IO, Any, Literal, overload
|
|
@@ -177,7 +177,7 @@ class Schema(BaseSchema, ABC):
|
|
|
177
177
|
num_rows: int | None = None,
|
|
178
178
|
*,
|
|
179
179
|
overrides: (
|
|
180
|
-
Mapping[str,
|
|
180
|
+
Mapping[str, Sequence[Any] | Any] | Sequence[Mapping[str, Any]] | None
|
|
181
181
|
) = None,
|
|
182
182
|
generator: Generator | None = None,
|
|
183
183
|
) -> DataFrame[Self]:
|
|
@@ -234,26 +234,22 @@ class Schema(BaseSchema, ABC):
|
|
|
234
234
|
g = generator or Generator()
|
|
235
235
|
|
|
236
236
|
# Precondition: valid overrides. We put them into a data frame to remember which
|
|
237
|
-
# values have been used in the algorithm below.
|
|
238
|
-
|
|
237
|
+
# values have been used in the algorithm below. When the user passes a sequence
|
|
238
|
+
# of mappings, they do not require to have the same keys. Hence, we have to
|
|
239
|
+
# remember that the data frame has "holes".
|
|
240
|
+
missing_override_indices: dict[str, pl.Series] = {}
|
|
241
|
+
if overrides is not None:
|
|
239
242
|
override_keys = (
|
|
240
|
-
set(overrides)
|
|
243
|
+
set(overrides)
|
|
244
|
+
if isinstance(overrides, Mapping)
|
|
245
|
+
else (
|
|
246
|
+
set.union(*[set(o.keys()) for o in overrides])
|
|
247
|
+
if len(overrides) > 0
|
|
248
|
+
else set()
|
|
249
|
+
)
|
|
241
250
|
)
|
|
242
|
-
if isinstance(overrides, Sequence):
|
|
243
|
-
# Check that overrides entries are consistent. Not necessary for mapping
|
|
244
|
-
# overrides as polars checks the series lists upon data frame construction.
|
|
245
|
-
inconsistent_override_keys = [
|
|
246
|
-
index
|
|
247
|
-
for index, current in enumerate(overrides)
|
|
248
|
-
if set(current) != override_keys
|
|
249
|
-
]
|
|
250
|
-
if len(inconsistent_override_keys) > 0:
|
|
251
|
-
raise ValueError(
|
|
252
|
-
"The `overrides` entries at the following indices "
|
|
253
|
-
"do not provide the same keys as the first entry: "
|
|
254
|
-
f"{inconsistent_override_keys}."
|
|
255
|
-
)
|
|
256
251
|
|
|
252
|
+
# Check that all override keys refer to valid columns
|
|
257
253
|
column_names = set(cls.column_names())
|
|
258
254
|
if not override_keys.issubset(column_names):
|
|
259
255
|
raise ValueError(
|
|
@@ -261,6 +257,19 @@ class Schema(BaseSchema, ABC):
|
|
|
261
257
|
"which are not in the schema."
|
|
262
258
|
)
|
|
263
259
|
|
|
260
|
+
# Remember the "holes" of the inputs if overrides are provided as a sequence
|
|
261
|
+
if isinstance(overrides, Sequence):
|
|
262
|
+
for key in override_keys:
|
|
263
|
+
indices = [
|
|
264
|
+
i for i, override in enumerate(overrides) if key not in override
|
|
265
|
+
]
|
|
266
|
+
if len(indices) > 0:
|
|
267
|
+
missing_override_indices[key] = pl.Series(indices)
|
|
268
|
+
|
|
269
|
+
# NOTE: Even if the user-provided overrides have "holes", we can still just
|
|
270
|
+
# create the data frame. Polars will fill the missing values with nulls, we
|
|
271
|
+
# will replace them later during sampling. If we were to already replace
|
|
272
|
+
# them here, we would not be able to resample these values.
|
|
264
273
|
values = pl.DataFrame(
|
|
265
274
|
overrides,
|
|
266
275
|
schema={
|
|
@@ -323,6 +332,7 @@ class Schema(BaseSchema, ABC):
|
|
|
323
332
|
used_values=values.slice(0, 0),
|
|
324
333
|
remaining_values=values,
|
|
325
334
|
override_expressions=override_expressions,
|
|
335
|
+
missing_value_indices=missing_override_indices,
|
|
326
336
|
)
|
|
327
337
|
|
|
328
338
|
sampling_rounds = 1
|
|
@@ -360,6 +370,7 @@ class Schema(BaseSchema, ABC):
|
|
|
360
370
|
used_values=used_values,
|
|
361
371
|
remaining_values=remaining_values,
|
|
362
372
|
override_expressions=override_expressions,
|
|
373
|
+
missing_value_indices=missing_override_indices,
|
|
363
374
|
)
|
|
364
375
|
sampling_rounds += 1
|
|
365
376
|
|
|
@@ -388,6 +399,7 @@ class Schema(BaseSchema, ABC):
|
|
|
388
399
|
used_values: pl.DataFrame,
|
|
389
400
|
remaining_values: pl.DataFrame,
|
|
390
401
|
override_expressions: list[pl.Expr],
|
|
402
|
+
missing_value_indices: dict[str, pl.Series],
|
|
391
403
|
) -> tuple[pl.DataFrame, pl.DataFrame, pl.DataFrame]:
|
|
392
404
|
"""Private method to sample a data frame with the schema including subsequent
|
|
393
405
|
filtering.
|
|
@@ -406,6 +418,33 @@ class Schema(BaseSchema, ABC):
|
|
|
406
418
|
}
|
|
407
419
|
)
|
|
408
420
|
|
|
421
|
+
# If we have missing value indices, we need to sample new values for the
|
|
422
|
+
# indices that overlap with indices in the remaining values and replace them
|
|
423
|
+
# in the sampled data frame.
|
|
424
|
+
for name, indices in missing_value_indices.items():
|
|
425
|
+
remapped_indices = (
|
|
426
|
+
indices.to_frame("idx")
|
|
427
|
+
.join(
|
|
428
|
+
remaining_values.select("__row_index__").with_row_index(
|
|
429
|
+
"__row_index_loop__"
|
|
430
|
+
),
|
|
431
|
+
left_on="idx",
|
|
432
|
+
right_on="__row_index__",
|
|
433
|
+
)
|
|
434
|
+
.select("__row_index_loop__")
|
|
435
|
+
.to_series()
|
|
436
|
+
)
|
|
437
|
+
if (num := len(remapped_indices)) > 0:
|
|
438
|
+
sampled_values = cls.columns()[name].sample(generator, num)
|
|
439
|
+
sampled = sampled.with_columns(
|
|
440
|
+
sampled[name]
|
|
441
|
+
# NOTE: We need to sort here as `scatter` requires sorted indices.
|
|
442
|
+
# Due to concatenations in `remaining_values`, the indices can go
|
|
443
|
+
# out of order.
|
|
444
|
+
.scatter(remapped_indices.sort(), sampled_values)
|
|
445
|
+
.alias(name)
|
|
446
|
+
)
|
|
447
|
+
|
|
409
448
|
combined_dataframe = pl.concat([previous_result, sampled])
|
|
410
449
|
# Pre-process columns before filtering.
|
|
411
450
|
combined_dataframe = combined_dataframe.with_columns(override_expressions)
|
|
@@ -27,7 +27,7 @@ description = "A declarative, polars-native data frame validation library"
|
|
|
27
27
|
name = "dataframely"
|
|
28
28
|
readme = "README.md"
|
|
29
29
|
requires-python = ">=3.10"
|
|
30
|
-
version = "2.
|
|
30
|
+
version = "2.4.0"
|
|
31
31
|
|
|
32
32
|
[project.optional-dependencies]
|
|
33
33
|
deltalake = ["deltalake"]
|
|
@@ -189,3 +189,16 @@ def test_duplicate_column_inlined_for_sampling() -> None:
|
|
|
189
189
|
],
|
|
190
190
|
},
|
|
191
191
|
)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def test_sample_override_sequence_with_missing_keys() -> None:
|
|
195
|
+
collection = MyCollection.sample(
|
|
196
|
+
overrides=[{"first": {"a": 1}, "second": [{"c": 2}, {}, {"b": 5}]}]
|
|
197
|
+
)
|
|
198
|
+
assert collection.first.collect().height == 1
|
|
199
|
+
assert collection.second is not None
|
|
200
|
+
|
|
201
|
+
second = collection.second.collect()
|
|
202
|
+
assert second.height == 3
|
|
203
|
+
assert second["c"].item(0) == 2
|
|
204
|
+
assert second["b"].item(2) == 5
|
|
@@ -66,7 +66,7 @@ def test_invalid_args(kwargs: dict[str, Any]) -> None:
|
|
|
66
66
|
|
|
67
67
|
|
|
68
68
|
@pytest.mark.parametrize(
|
|
69
|
-
"dtype", [pl.Decimal, pl.Decimal(12), pl.Decimal(None,
|
|
69
|
+
"dtype", [pl.Decimal, pl.Decimal(12), pl.Decimal(None, 0), pl.Decimal(6, 0)]
|
|
70
70
|
)
|
|
71
71
|
def test_any_decimal_dtype_passes(dtype: DataTypeClass) -> None:
|
|
72
72
|
df = pl.DataFrame(schema={"a": dtype})
|
|
@@ -171,3 +171,58 @@ def test_validate_range(
|
|
|
171
171
|
actual = evaluate_rules(lf, rules_from_exprs(column.validation_rules(pl.col("a"))))
|
|
172
172
|
expected = pl.LazyFrame(valid)
|
|
173
173
|
assert_frame_equal(actual, expected)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@pytest.mark.parametrize(
|
|
177
|
+
("schema_precision", "schema_scale", "dtype", "should_pass"),
|
|
178
|
+
[
|
|
179
|
+
# Exact match should pass
|
|
180
|
+
(38, 10, pl.Decimal(38, 10), True),
|
|
181
|
+
# Wrong scale should fail
|
|
182
|
+
(38, 10, pl.Decimal(38, 3), False),
|
|
183
|
+
# Wrong precision should fail
|
|
184
|
+
(10, 2, pl.Decimal(38, 2), False),
|
|
185
|
+
# Both wrong should fail
|
|
186
|
+
(10, 2, pl.Decimal(38, 5), False),
|
|
187
|
+
# precision=None should accept any precision with matching scale
|
|
188
|
+
(None, 5, pl.Decimal(10, 5), True),
|
|
189
|
+
(None, 5, pl.Decimal(20, 5), True),
|
|
190
|
+
# precision=None with wrong scale should fail
|
|
191
|
+
(None, 5, pl.Decimal(10, 3), False),
|
|
192
|
+
],
|
|
193
|
+
)
|
|
194
|
+
def test_precision_scale_validation(
|
|
195
|
+
schema_precision: int | None,
|
|
196
|
+
schema_scale: int,
|
|
197
|
+
dtype: DataTypeClass,
|
|
198
|
+
should_pass: bool,
|
|
199
|
+
) -> None:
|
|
200
|
+
class TestSchema(dy.Schema):
|
|
201
|
+
a = dy.Decimal(precision=schema_precision, scale=schema_scale)
|
|
202
|
+
|
|
203
|
+
df = pl.DataFrame(schema={"a": dtype})
|
|
204
|
+
assert TestSchema.is_valid(df) == should_pass
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@pytest.mark.parametrize(
|
|
208
|
+
("schema_precision", "schema_scale", "input_dtype"),
|
|
209
|
+
[
|
|
210
|
+
(38, 10, pl.Decimal(38, 3)),
|
|
211
|
+
(10, 2, pl.Decimal(38, 2)),
|
|
212
|
+
(10, 5, pl.Decimal(20, 3)),
|
|
213
|
+
],
|
|
214
|
+
)
|
|
215
|
+
def test_precision_scale_casting(
|
|
216
|
+
schema_precision: int,
|
|
217
|
+
schema_scale: int,
|
|
218
|
+
input_dtype: pl.DataType,
|
|
219
|
+
) -> None:
|
|
220
|
+
class TestSchema(dy.Schema):
|
|
221
|
+
a = dy.Decimal(precision=schema_precision, scale=schema_scale)
|
|
222
|
+
|
|
223
|
+
df_input = pl.DataFrame({"a": [decimal.Decimal("12.34")]}).with_columns(
|
|
224
|
+
pl.col("a").cast(input_dtype)
|
|
225
|
+
)
|
|
226
|
+
df_validated = TestSchema.validate(df_input, cast=True)
|
|
227
|
+
assert df_validated.schema["a"].precision == schema_precision # type: ignore[attr-defined]
|
|
228
|
+
assert df_validated.schema["a"].scale == schema_scale # type: ignore[attr-defined]
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Copyright (c) QuantCo 2025-2025
|
|
2
2
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
3
3
|
|
|
4
|
+
from typing import cast
|
|
5
|
+
|
|
4
6
|
import polars as pl
|
|
5
7
|
import pytest
|
|
6
8
|
|
|
@@ -179,3 +181,14 @@ def test_inner_primary_key_struct(
|
|
|
179
181
|
_, failure = schema.filter(df)
|
|
180
182
|
assert failure.counts() == {"a|primary_key": failure_count}
|
|
181
183
|
assert validation_mask(df, failure).to_list() == mask
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@pytest.mark.parametrize("min_length", [0, 10, 33, 100])
|
|
187
|
+
def test_list_sampling_with_min_length(min_length: int) -> None:
|
|
188
|
+
"""Test that sampling works correctly when min_length > 32."""
|
|
189
|
+
schema = create_schema("test", {"a": dy.List(dy.Int64(), min_length=min_length)})
|
|
190
|
+
df = schema.sample(num_rows=10)
|
|
191
|
+
assert len(df) == 10
|
|
192
|
+
# Verify all lists have at least min_length elements
|
|
193
|
+
min_list_len = cast(int, df["a"].list.len().min())
|
|
194
|
+
assert min_list_len >= min_length
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# Copyright (c) QuantCo 2025-2025
|
|
2
2
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
3
|
+
import re
|
|
3
4
|
|
|
4
5
|
import pytest
|
|
5
6
|
|
|
6
7
|
import dataframely as dy
|
|
7
8
|
from dataframely.columns import Column
|
|
9
|
+
from dataframely.columns.string import DEFAULT_SAMPLING_REGEX
|
|
10
|
+
from dataframely.random import Generator
|
|
8
11
|
from dataframely.testing import ALL_COLUMN_TYPES
|
|
9
12
|
|
|
10
13
|
|
|
@@ -32,3 +35,17 @@ def test_string_representation_array() -> None:
|
|
|
32
35
|
def test_string_representation_struct() -> None:
|
|
33
36
|
column = dy.Struct({"a": dy.String()})
|
|
34
37
|
assert str(column) == dy.Struct.__name__.lower()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@pytest.mark.parametrize("min_length", [None, 5, 10])
|
|
41
|
+
@pytest.mark.parametrize("max_length", [None, 20])
|
|
42
|
+
def test_string_sampling_without_regex(
|
|
43
|
+
min_length: int | None, max_length: int | None
|
|
44
|
+
) -> None:
|
|
45
|
+
# Check that if no regex is provided, the sampled strings only use
|
|
46
|
+
# characters from the DEFAULT_SAMPLING_REGEX.
|
|
47
|
+
column = dy.String(min_length=min_length, max_length=max_length)
|
|
48
|
+
generator = Generator(seed=42)
|
|
49
|
+
sample = column.sample(generator=generator, n=1000)
|
|
50
|
+
|
|
51
|
+
assert all(re.match(f"{DEFAULT_SAMPLING_REGEX}*", value) for value in sample)
|
|
@@ -125,3 +125,19 @@ def test_user_error_column_type_not_instance() -> None:
|
|
|
125
125
|
class MySchemaWithColumnTypeNotInstance(dy.Schema):
|
|
126
126
|
a = dy.Int32(nullable=False, primary_key=True)
|
|
127
127
|
b = dy.Float64 # User error: Forgot parentheses!
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def test_user_error_polars_datatype_instance() -> None:
|
|
131
|
+
with pytest.raises(TypeError, match="polars DataType instance"):
|
|
132
|
+
|
|
133
|
+
class MySchemaWithPolarsDataTypeInstance(dy.Schema):
|
|
134
|
+
a = dy.Int32(nullable=False)
|
|
135
|
+
b = pl.String() # User error: Used pl.String() instead of dy.String()
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_user_error_polars_datatype_type() -> None:
|
|
139
|
+
with pytest.raises(TypeError, match="polars DataType type"):
|
|
140
|
+
|
|
141
|
+
class MySchemaWithPolarsDataTypeType(dy.Schema):
|
|
142
|
+
a = dy.Int32(nullable=False)
|
|
143
|
+
b = pl.String # User error: Used pl.String instead of dy.String()
|
|
@@ -9,6 +9,7 @@ from polars.testing import assert_frame_equal
|
|
|
9
9
|
|
|
10
10
|
import dataframely as dy
|
|
11
11
|
from dataframely.random import Generator
|
|
12
|
+
from dataframely.testing import create_schema
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class MySimpleSchema(dy.Schema):
|
|
@@ -214,23 +215,6 @@ def test_sample_raises_superfluous_column_override() -> None:
|
|
|
214
215
|
SchemaWithIrrelevantColumnPreProcessing.sample(100)
|
|
215
216
|
|
|
216
217
|
|
|
217
|
-
def test_sample_with_inconsistent_overrides_keys_raises() -> None:
|
|
218
|
-
with pytest.raises(
|
|
219
|
-
ValueError,
|
|
220
|
-
match=(
|
|
221
|
-
r"The `overrides` entries at the following indices do not provide "
|
|
222
|
-
r"the same keys as the first entry: \[1, 2\]."
|
|
223
|
-
),
|
|
224
|
-
):
|
|
225
|
-
MySimpleSchema.sample(
|
|
226
|
-
overrides=[
|
|
227
|
-
{"a": 1, "b": "one"},
|
|
228
|
-
{"a": 2},
|
|
229
|
-
{"b": 2},
|
|
230
|
-
]
|
|
231
|
-
)
|
|
232
|
-
|
|
233
|
-
|
|
234
218
|
@pytest.mark.parametrize(
|
|
235
219
|
"overrides,failed_column,failed_rule,failed_rows",
|
|
236
220
|
[
|
|
@@ -252,3 +236,28 @@ def test_sample_invalid_override_values_raises(
|
|
|
252
236
|
):
|
|
253
237
|
with dy.Config(max_sampling_iterations=100): # speed up the test
|
|
254
238
|
MyAdvancedSchema.sample(overrides=overrides)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def test_sample_empty_override_sequence() -> None:
|
|
242
|
+
df = MySimpleSchema.sample(overrides=[])
|
|
243
|
+
assert len(df) == 0
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def test_sample_override_sequence_with_missing_keys() -> None:
|
|
247
|
+
df = MySimpleSchema.sample(overrides=[{"a": 1}, {"b": "two"}])
|
|
248
|
+
assert df.item(0, 0) == 1
|
|
249
|
+
assert df.item(1, 1) == "two"
|
|
250
|
+
assert len(df) == 2
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def test_sample_override_sequence_with_missing_keys_and_resampling() -> None:
|
|
254
|
+
schema = create_schema("test", {"a": dy.UInt8(primary_key=True), "b": dy.String()})
|
|
255
|
+
generator = Generator(seed=42)
|
|
256
|
+
df = schema.sample(
|
|
257
|
+
overrides=[{"a": i} for i in range(250)] + [{"b": "two"}, {"b": "three"}],
|
|
258
|
+
generator=generator,
|
|
259
|
+
)
|
|
260
|
+
assert len(df) == 252
|
|
261
|
+
assert all(df.item(i, 0) == i for i in range(250))
|
|
262
|
+
assert df.item(250, 1) == "two"
|
|
263
|
+
assert df.item(251, 1) == "three"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|