├── .python-version ├── src └── polars_validator │ ├── py.typed │ ├── __init__.py │ ├── validator.py │ └── dataframe.py ├── tests └── test_validate_schema.py ├── pyproject.toml ├── justfile ├── README.md ├── .gitignore └── uv.lock /.python-version: -------------------------------------------------------------------------------- 1 | 3.10 2 | -------------------------------------------------------------------------------- /src/polars_validator/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/polars_validator/__init__.py: -------------------------------------------------------------------------------- 1 | from polars_validator.dataframe import DataFrame 2 | from polars_validator.validator import check_schema 3 | 4 | __all__ = [ 5 | "DataFrame", 6 | "check_schema", 7 | ] -------------------------------------------------------------------------------- /tests/test_validate_schema.py: -------------------------------------------------------------------------------- 1 | from typing import TypedDict 2 | 3 | import polars as pl 4 | 5 | from polars_validator import DataFrame, check_schema 6 | 7 | 8 | def test_validate_schema(): 9 | class User(TypedDict): 10 | id: int 11 | name: str 12 | email: str 13 | 14 | @check_schema(User) 15 | def get_users_from_db() -> pl.DataFrame: 16 | # Simulate database query 17 | data = [ 18 | {"id": 1, "name": "Alice", "email": "alice@example.com"}, 19 | {"id": 2, "name": "Bob", "email": "bob@example.com"}, 20 | ] 21 | return pl.DataFrame(data) 22 | 23 | users: DataFrame[User] = get_users_from_db() 24 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "polars-validator" 3 | version = "0.1.0" 4 | description = "Add your description here" 5 | readme = "README.md" 6 | authors = [ 7 | { name = "baggiponte", email = "57922983+baggiponte@users.noreply.github.com" } 8 | ] 9 | requires-python = ">=3.10" 10 | dependencies = [ 11 | "polars>=1.16.0", 12 | ] 13 | 14 | [build-system] 15 | requires = ["hatchling"] 16 | build-backend = "hatchling.build" 17 | 18 | [tool.ruff.lint] 19 | extend-select = ["ALL"] 20 | extend-ignore = [ 21 | "ISC001", 22 | "COM812", 23 | "PD" 24 | ] 25 | 26 | [tool.ruff.lint.pydocstyle] 27 | convention = "google" 28 | 29 | [tool.pyright] 30 | exclude = [ 31 | ".venv" 32 | ] 33 | venvPath = "." 34 | venv = ".venv" 35 | 36 | [dependency-groups] 37 | dev = [ 38 | "pytest>=8.3.4", 39 | ] 40 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | set quiet := true 2 | 3 | default: format lint check 4 | 5 | format: (needs "uv") 6 | uvx ruff format -- src 7 | uvx ruff check --select=I,RUF022 --fix -- src 8 | 9 | lint: (needs "uv") 10 | uvx ruff check -- src tests 11 | 12 | check: (needs "bun" "uv") 13 | echo "=========== mypy ============" 14 | # `-` will continue execution even if the command fails 15 | -uvx mypy --strict -- src tests 16 | 17 | echo "\n========== pyright ==========" 18 | bunx pyright src tests 19 | 20 | test: (needs "pytest") 21 | uv run pytest tests 22 | 23 | [private] 24 | needs +commands: 25 | #!/usr/bin/env zsh 26 | set -euo pipefail 27 | for cmd in "$@"; do 28 | if ! command -v $cmd &> /dev/null; then 29 | echo "$cmd binary not found. Make sure you install it first." 30 | exit 1 31 | fi 32 | done 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Polars Validator 2 | 3 | Make your Polars DataFrames generic types! 4 | 5 | ## Installation 6 | 7 | ```bash 8 | uv add git+https://github.com/baggiponte/polars-validator 9 | ``` 10 | 11 | ## Usage 12 | 13 | ```python 14 | from typing import TypedDict 15 | 16 | import polars as pl 17 | from polars_validator import validate_schema, DataFrame 18 | 19 | class User(TypedDict): 20 | id: int 21 | name: str 22 | email: str 23 | 24 | @validate_schema(User) 25 | def get_users_from_db() -> pl.DataFrame: 26 | # Simulate database query 27 | data = [ 28 | {"id": 1, "name": "Alice", "email": "alice@example.com"}, 29 | {"id": 2, "name": "Bob", "email": "bob@example.com"}, 30 | ] 31 | return pl.DataFrame(data) 32 | 33 | users: DataFrame[User] = get_users_from_db() 34 | ``` 35 | 36 | ## Development 37 | 38 | ### Run tests 39 | 40 | It's faster with [just](https://just.systems). 41 | -------------------------------------------------------------------------------- /src/polars_validator/validator.py: -------------------------------------------------------------------------------- 1 | import functools 2 | from collections.abc import Callable, Mapping 3 | from typing import ParamSpec, TypeVar 4 | 5 | import polars as pl 6 | 7 | from polars_validator.dataframe import DataFrame 8 | 9 | S = TypeVar("S", bound=Mapping) 10 | H = TypeVar("H", int, None, default=None) 11 | 12 | R = TypeVar("R") 13 | P = ParamSpec("P") 14 | 15 | __all__ = [ 16 | "check_schema", 17 | ] 18 | 19 | 20 | def check_schema( 21 | schema: type[S], 22 | ) -> Callable[[Callable[P, pl.DataFrame]], Callable[P, DataFrame[S]]]: 23 | def inner(func: Callable[P, pl.DataFrame]) -> Callable[P, DataFrame[S]]: 24 | @functools.wraps(func) 25 | def wrapper(*args: P.args, **kwargs: P.kwargs) -> DataFrame[S]: 26 | df = func(*args, **kwargs) 27 | 28 | df_ = DataFrame(df, schema) 29 | 30 | if not df_.validate(): 31 | raise ValueError("Schema validation failed") 32 | 33 | return df_ 34 | 35 | return wrapper 36 | 37 | return inner 38 | -------------------------------------------------------------------------------- /src/polars_validator/dataframe.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Mapping 2 | from typing import Generic, TypeVar 3 | 4 | import polars as pl 5 | 6 | __all__ = [ 7 | "DataFrame", 8 | "LazyFrame", 9 | ] 10 | 11 | 12 | S = TypeVar("S", bound=Mapping) 13 | H = TypeVar("H", int, None, default=None) 14 | 15 | 16 | class DataFrame(pl.DataFrame, Generic[S, H]): 17 | """No-op class to make Polars DataFrames generics.""" 18 | 19 | def __init__( 20 | self, 21 | data: pl.DataFrame, 22 | schema: type[S], 23 | height: H = None, 24 | ) -> None: 25 | super().__init__(data) 26 | self._schema_base: type[S] = schema 27 | self._schema_height: H = height 28 | self._validation_schema: pl.Schema = _convert_schema_to_polars(schema) 29 | 30 | 31 | class LazyFrame(pl.LazyFrame, Generic[S, H]): 32 | """No-op class to make Polars LazyFrames generics.""" 33 | 34 | def __init__( 35 | self, 36 | data: pl.LazyFrame, 37 | schema: type[S], 38 | height: H = None, 39 | ) -> None: 40 | super().__init__(data) 41 | self._schema_base: type[S] = schema 42 | self._schema_height: H = height 43 | self._validation_schema: pl.Schema = _convert_schema_to_polars(schema) 44 | 45 | 46 | def _convert_schema_to_polars(schema: type) -> pl.Schema: 47 | annotations = schema.__annotations__ 48 | converted = { 49 | name: annotation 50 | if issubclass(annotation, pl.DataType) 51 | else pl.DataType.from_python(annotation) 52 | for name, annotation in annotations.items() 53 | } 54 | return pl.Schema(converted) 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,pycharm+all,macos,windows,python,linux,asdf 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,pycharm+all,macos,windows,python,linux,asdf 3 | 4 | ### asdf ### 5 | /.tool-versions 6 | 7 | ### Linux ### 8 | *~ 9 | 10 | # temporary files which can be created if a process still has a handle open of a deleted file 11 | .fuse_hidden* 12 | 13 | # KDE directory preferences 14 | .directory 15 | 16 | # Linux trash folder which might appear on any partition or disk 17 | .Trash-* 18 | 19 | # .nfs files are created when an open file is removed but is still being accessed 20 | .nfs* 21 | 22 | ### macOS ### 23 | # General 24 | .DS_Store 25 | .AppleDouble 26 | .LSOverride 27 | 28 | # Icon must end with two \r 29 | Icon 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | .com.apple.timemachine.donotpresent 42 | 43 | # Directories potentially created on remote AFP share 44 | .AppleDB 45 | .AppleDesktop 46 | Network Trash Folder 47 | Temporary Items 48 | .apdisk 49 | 50 | ### macOS Patch ### 51 | # iCloud generated files 52 | *.icloud 53 | 54 | ### PyCharm+all ### 55 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 56 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 57 | 58 | # User-specific stuff 59 | .idea/**/workspace.xml 60 | .idea/**/tasks.xml 61 | .idea/**/usage.statistics.xml 62 | .idea/**/dictionaries 63 | .idea/**/shelf 64 | 65 | # AWS User-specific 66 | .idea/**/aws.xml 67 | 68 | # Generated files 69 | .idea/**/contentModel.xml 70 | 71 | # Sensitive or high-churn files 72 | .idea/**/dataSources/ 73 | .idea/**/dataSources.ids 74 | .idea/**/dataSources.local.xml 75 | .idea/**/sqlDataSources.xml 76 | .idea/**/dynamic.xml 77 | .idea/**/uiDesigner.xml 78 | .idea/**/dbnavigator.xml 79 | 80 | # Gradle 81 | .idea/**/gradle.xml 82 | .idea/**/libraries 83 | 84 | # Gradle and Maven with auto-import 85 | # When using Gradle or Maven with auto-import, you should exclude module files, 86 | # since they will be recreated, and may cause churn. Uncomment if using 87 | # auto-import. 88 | # .idea/artifacts 89 | # .idea/compiler.xml 90 | # .idea/jarRepositories.xml 91 | # .idea/modules.xml 92 | # .idea/*.iml 93 | # .idea/modules 94 | # *.iml 95 | # *.ipr 96 | 97 | # CMake 98 | cmake-build-*/ 99 | 100 | # Mongo Explorer plugin 101 | .idea/**/mongoSettings.xml 102 | 103 | # File-based project format 104 | *.iws 105 | 106 | # IntelliJ 107 | out/ 108 | 109 | # mpeltonen/sbt-idea plugin 110 | .idea_modules/ 111 | 112 | # JIRA plugin 113 | atlassian-ide-plugin.xml 114 | 115 | # Cursive Clojure plugin 116 | .idea/replstate.xml 117 | 118 | # SonarLint plugin 119 | .idea/sonarlint/ 120 | 121 | # Crashlytics plugin (for Android Studio and IntelliJ) 122 | com_crashlytics_export_strings.xml 123 | crashlytics.properties 124 | crashlytics-build.properties 125 | fabric.properties 126 | 127 | # Editor-based Rest Client 128 | .idea/httpRequests 129 | 130 | # Android studio 3.1+ serialized cache file 131 | .idea/caches/build_file_checksums.ser 132 | 133 | ### PyCharm+all Patch ### 134 | # Ignore everything but code style settings and run configurations 135 | # that are supposed to be shared within teams. 136 | 137 | .idea/* 138 | 139 | !.idea/codeStyles 140 | !.idea/runConfigurations 141 | 142 | ### Python ### 143 | # Byte-compiled / optimized / DLL files 144 | __pycache__/ 145 | *.py[cod] 146 | *$py.class 147 | 148 | # C extensions 149 | *.so 150 | 151 | # Distribution / packaging 152 | .Python 153 | build/ 154 | develop-eggs/ 155 | dist/ 156 | downloads/ 157 | eggs/ 158 | .eggs/ 159 | lib/ 160 | lib64/ 161 | parts/ 162 | sdist/ 163 | var/ 164 | wheels/ 165 | share/python-wheels/ 166 | *.egg-info/ 167 | .installed.cfg 168 | *.egg 169 | MANIFEST 170 | 171 | # PyInstaller 172 | # Usually these files are written by a python script from a template 173 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 174 | *.manifest 175 | *.spec 176 | 177 | # Installer logs 178 | pip-log.txt 179 | pip-delete-this-directory.txt 180 | 181 | # Unit test / coverage reports 182 | htmlcov/ 183 | .tox/ 184 | .nox/ 185 | .coverage 186 | .coverage.* 187 | .cache 188 | nosetests.xml 189 | coverage.xml 190 | *.cover 191 | *.py,cover 192 | .hypothesis/ 193 | .pytest_cache/ 194 | cover/ 195 | 196 | # Translations 197 | *.mo 198 | *.pot 199 | 200 | # Django stuff: 201 | *.log 202 | local_settings.py 203 | db.sqlite3 204 | db.sqlite3-journal 205 | 206 | # Flask stuff: 207 | instance/ 208 | .webassets-cache 209 | 210 | # Scrapy stuff: 211 | .scrapy 212 | 213 | # Sphinx documentation 214 | docs/_build/ 215 | 216 | # PyBuilder 217 | .pybuilder/ 218 | target/ 219 | 220 | # Jupyter Notebook 221 | .ipynb_checkpoints 222 | 223 | # IPython 224 | profile_default/ 225 | ipython_config.py 226 | 227 | # pyenv 228 | # For a library or package, you might want to ignore these files since the code is 229 | # intended to run in multiple environments; otherwise, check them in: 230 | # .python-version 231 | 232 | # pipenv 233 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 234 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 235 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 236 | # install all needed dependencies. 237 | #Pipfile.lock 238 | 239 | # poetry 240 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 241 | # This is especially recommended for binary packages to ensure reproducibility, and is more 242 | # commonly ignored for libraries. 243 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 244 | #poetry.lock 245 | 246 | # pdm 247 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 248 | #pdm.lock 249 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 250 | # in version control. 251 | # https://pdm.fming.dev/#use-with-ide 252 | .pdm.toml 253 | 254 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 255 | __pypackages__/ 256 | 257 | # Celery stuff 258 | celerybeat-schedule 259 | celerybeat.pid 260 | 261 | # SageMath parsed files 262 | *.sage.py 263 | 264 | # Environments 265 | .env 266 | .venv 267 | env/ 268 | venv/ 269 | ENV/ 270 | env.bak/ 271 | venv.bak/ 272 | 273 | # Spyder project settings 274 | .spyderproject 275 | .spyproject 276 | 277 | # Rope project settings 278 | .ropeproject 279 | 280 | # mkdocs documentation 281 | /site 282 | 283 | # mypy 284 | .mypy_cache/ 285 | .dmypy.json 286 | dmypy.json 287 | 288 | # Pyre type checker 289 | .pyre/ 290 | 291 | # pytype static type analyzer 292 | .pytype/ 293 | 294 | # Cython debug symbols 295 | cython_debug/ 296 | 297 | # PyCharm 298 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 299 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 300 | # and can be added to the global gitignore or merged into this file. For a more nuclear 301 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 302 | #.idea/ 303 | 304 | ### Python Patch ### 305 | # Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration 306 | poetry.toml 307 | 308 | # ruff 309 | .ruff_cache/ 310 | 311 | # LSP config files 312 | pyrightconfig.json 313 | 314 | ### VisualStudioCode ### 315 | .vscode/* 316 | !.vscode/settings.json 317 | !.vscode/tasks.json 318 | !.vscode/launch.json 319 | !.vscode/extensions.json 320 | !.vscode/*.code-snippets 321 | 322 | # Local History for Visual Studio Code 323 | .history/ 324 | 325 | # Built Visual Studio Code Extensions 326 | *.vsix 327 | 328 | ### VisualStudioCode Patch ### 329 | # Ignore all local history of files 330 | .history 331 | .ionide 332 | 333 | ### Windows ### 334 | # Windows thumbnail cache files 335 | Thumbs.db 336 | Thumbs.db:encryptable 337 | ehthumbs.db 338 | ehthumbs_vista.db 339 | 340 | # Dump file 341 | *.stackdump 342 | 343 | # Folder config file 344 | [Dd]esktop.ini 345 | 346 | # Recycle Bin used on file shares 347 | $RECYCLE.BIN/ 348 | 349 | # Windows Installer files 350 | *.cab 351 | *.msi 352 | *.msix 353 | *.msm 354 | *.msp 355 | 356 | # Windows shortcuts 357 | *.lnk 358 | 359 | # End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,pycharm+all,macos,windows,python,linux,asdf 360 | 361 | -------------------------------------------------------------------------------- /uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | requires-python = ">=3.10" 3 | 4 | [[package]] 5 | name = "colorama" 6 | version = "0.4.6" 7 | source = { registry = "https://pypi.python.org/simple" } 8 | sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } 9 | wheels = [ 10 | { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, 11 | ] 12 | 13 | [[package]] 14 | name = "exceptiongroup" 15 | version = "1.2.2" 16 | source = { registry = "https://pypi.python.org/simple" } 17 | sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } 18 | wheels = [ 19 | { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, 20 | ] 21 | 22 | [[package]] 23 | name = "iniconfig" 24 | version = "2.0.0" 25 | source = { registry = "https://pypi.python.org/simple" } 26 | sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } 27 | wheels = [ 28 | { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, 29 | ] 30 | 31 | [[package]] 32 | name = "packaging" 33 | version = "24.2" 34 | source = { registry = "https://pypi.python.org/simple" } 35 | sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } 36 | wheels = [ 37 | { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, 38 | ] 39 | 40 | [[package]] 41 | name = "pluggy" 42 | version = "1.5.0" 43 | source = { registry = "https://pypi.python.org/simple" } 44 | sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } 45 | wheels = [ 46 | { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, 47 | ] 48 | 49 | [[package]] 50 | name = "polars" 51 | version = "1.16.0" 52 | source = { registry = "https://pypi.python.org/simple" } 53 | sdist = { url = "https://files.pythonhosted.org/packages/43/80/d845897273be97a3e73b59be711deda375b638330d591a7ef8132c20f52f/polars-1.16.0.tar.gz", hash = "sha256:dd99808b833872babe02434a809fd45c1cffe66a3d57123cdc5e447c7753d328", size = 4192568 } 54 | wheels = [ 55 | { url = "https://files.pythonhosted.org/packages/8e/b0/51c944ecd58b3ebc81eb03b50448127ff85fd9448063094524e0c6693c75/polars-1.16.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:072f5ff3b5fe05797c59890de0e464b34ede75a9735e7d7221622fa3a0616d8e", size = 34735038 }, 56 | { url = "https://files.pythonhosted.org/packages/61/2f/d0b45007f2ae4b4926070b420c8525840b9757013cd96077bcde40807ecb/polars-1.16.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ebaf7a1ea114b042fa9f1cd17d49436279eb30545dd74361a2f5e3febeb867cd", size = 30577461 }, 57 | { url = "https://files.pythonhosted.org/packages/31/9e/21e05959323883abcee799837d8cac08adf10a48c233432993757e41791a/polars-1.16.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e626d21dcd2566e1442dac414fe177bc70ebfc2f16620d59d778b1b774361018", size = 36006233 }, 58 | { url = "https://files.pythonhosted.org/packages/25/80/da5c3cd248c7642d1feb896f0a27a0860c607f8cdde3e75457182e4c76c6/polars-1.16.0-cp39-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:53debcce55f68731ee2c7d6c787afdee26860ed6576f1ffa0cb9111b57f82857", size = 32348398 }, 59 | { url = "https://files.pythonhosted.org/packages/08/0b/677c905f9dd5bc37708694e8f7367659c5382bd011f5dc1d564474032d0b/polars-1.16.0-cp39-abi3-win_amd64.whl", hash = "sha256:17efcb550c42d51034ff79702612b9184d8eac0d500de1dd7fb98490459276d3", size = 35743314 }, 60 | ] 61 | 62 | [[package]] 63 | name = "polars-validator" 64 | version = "0.1.0" 65 | source = { editable = "." } 66 | dependencies = [ 67 | { name = "polars" }, 68 | ] 69 | 70 | [package.dev-dependencies] 71 | dev = [ 72 | { name = "pytest" }, 73 | ] 74 | 75 | [package.metadata] 76 | requires-dist = [{ name = "polars", specifier = ">=1.16.0" }] 77 | 78 | [package.metadata.requires-dev] 79 | dev = [{ name = "pytest", specifier = ">=8.3.4" }] 80 | 81 | [[package]] 82 | name = "pytest" 83 | version = "8.3.4" 84 | source = { registry = "https://pypi.python.org/simple" } 85 | dependencies = [ 86 | { name = "colorama", marker = "sys_platform == 'win32'" }, 87 | { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, 88 | { name = "iniconfig" }, 89 | { name = "packaging" }, 90 | { name = "pluggy" }, 91 | { name = "tomli", marker = "python_full_version < '3.11'" }, 92 | ] 93 | sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 } 94 | wheels = [ 95 | { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 }, 96 | ] 97 | 98 | [[package]] 99 | name = "tomli" 100 | version = "2.2.1" 101 | source = { registry = "https://pypi.python.org/simple" } 102 | sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } 103 | wheels = [ 104 | { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 }, 105 | { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 }, 106 | { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 }, 107 | { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 }, 108 | { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 }, 109 | { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 }, 110 | { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 }, 111 | { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 }, 112 | { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 }, 113 | { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 }, 114 | { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 }, 115 | { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 }, 116 | { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 }, 117 | { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 }, 118 | { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 }, 119 | { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 }, 120 | { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 }, 121 | { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 }, 122 | { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 }, 123 | { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 }, 124 | { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 }, 125 | { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 }, 126 | { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 }, 127 | { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 }, 128 | { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 }, 129 | { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 }, 130 | { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 }, 131 | { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 }, 132 | { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 }, 133 | { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 }, 134 | { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, 135 | ] 136 | --------------------------------------------------------------------------------