We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Nullability for `pl.Float64` in `pl.DataFrame` fails
**Describe the bug**
The nullability constraint is not enforced in `pl.DataFrame` when the underlying data type is `pl.Float64`. When I provide a `pl.DataFrame` with a float column that contains `None`, it passes.

- [x] I have checked that this issue has not already been reported.
- [x] I have confirmed this bug exists on the latest version of pandera.

#### Code Sample, a copy-pastable example

```python
import polars as pl
import pandera.polars as pa


class Schema(pa.DataFrameModel):
    col: float = pa.Field(nullable=False)


df = pl.DataFrame(data={"col": [1.0, 2.5, None]}, schema={"col": pl.Float64})

Schema.validate(df)


```

#### Expected behavior
The validation should vail as the column `col` contains a `None` value, but the schema requires it to be non-nullable.

#### Desktop (please complete the following information):

 - OS: MacOS
 - Browser: Chrome

#### Additional context
The nullability constraint is correctly enforced if the underlying data type is `int` or `str`.
For `float`, the nullability constraint correctly detects NULL values in the form of `np.nan`.



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pandera/backends/polars/components.py`
Content:
```
1 """Validation backend for polars components."""
2 
3 import warnings
4 from typing import Any, Callable, Iterable, List, Optional, cast
5 
6 import polars as pl
7 
8 from pandera.api.base.error_handler import ErrorHandler
9 from pandera.api.polars.components import Column
10 from pandera.api.polars.types import PolarsData
11 from pandera.backends.base import CoreCheckResult
12 from pandera.backends.polars.base import PolarsSchemaBackend, is_float_dtype
13 from pandera.config import ValidationDepth, ValidationScope, get_config_context
14 from pandera.constants import CHECK_OUTPUT_KEY
15 from pandera.errors import (
16     ParserError,
17     SchemaDefinitionError,
18     SchemaError,
19     SchemaErrorReason,
20     SchemaErrors,
21 )
22 from pandera.validation_depth import validate_scope, validation_type
23 
24 
25 class ColumnBackend(PolarsSchemaBackend):
26     """Column backend for polars LazyFrames."""
27 
28     def preprocess(self, check_obj, inplace: bool = False):
29         """Returns a copy of the object if inplace is False."""
30         # NOTE: is this even necessary?
31         return check_obj if inplace else check_obj.clone()
32 
33     # pylint: disable=too-many-locals
34     def validate(
35         self,
36         check_obj: pl.LazyFrame,
37         schema: Column,
38         *,
39         head: Optional[int] = None,
40         tail: Optional[int] = None,
41         sample: Optional[int] = None,
42         random_state: Optional[int] = None,
43         lazy: bool = False,
44         inplace: bool = False,
45     ) -> pl.LazyFrame:
46 
47         if inplace:
48             warnings.warn("setting inplace=True will have no effect.")
49 
50         if schema.name is None:
51             raise SchemaDefinitionError(
52                 "Column schema must have a name specified."
53             )
54 
55         error_handler = ErrorHandler(lazy)
56         check_obj = self.preprocess(check_obj, inplace)
57 
58         if getattr(schema, "drop_invalid_rows", False) and not lazy:
59             raise SchemaDefinitionError(
60                 "When drop_invalid_rows is True, lazy must be set to True."
61             )
62 
63         core_parsers: List[Callable[..., Any]] = [
64             self.coerce_dtype,
65             self.set_default,
66         ]
67 
68         for parser in core_parsers:
69             try:
70                 check_obj = parser(check_obj, schema)
71             except SchemaError as exc:
72                 error_handler.collect_error(
73                     validation_type(exc.reason_code),
74                     exc.reason_code,
75                     exc,
76                 )
77             except SchemaErrors as exc:
78                 error_handler.collect_errors(exc.schema_errors)
79 
80         error_handler = self.run_checks_and_handle_errors(
81             error_handler,
82             schema,
83             check_obj,
84             head=head,
85             tail=tail,
86             sample=sample,
87             random_state=random_state,
88         )
89 
90         if lazy and error_handler.collected_errors:
91             if getattr(schema, "drop_invalid_rows", False):
92                 check_obj = self.drop_invalid_rows(check_obj, error_handler)
93             else:
94                 raise SchemaErrors(
95                     schema=schema,
96                     schema_errors=error_handler.schema_errors,
97                     data=check_obj,
98                 )
99 
100         return check_obj
101 
102     def get_regex_columns(self, schema, check_obj) -> Iterable:
103         return check_obj.select(pl.col(schema.selector)).columns
104 
105     def run_checks_and_handle_errors(
106         self,
107         error_handler: ErrorHandler,
108         schema,
109         check_obj: pl.LazyFrame,
110         **subsample_kwargs,
111     ):
112         """Run checks on schema"""
113         # pylint: disable=too-many-locals
114         check_obj_subsample = self.subsample(check_obj, **subsample_kwargs)
115 
116         core_checks = [
117             self.check_nullable,
118             self.check_unique,
119             self.check_dtype,
120             self.run_checks,
121         ]
122         args = (check_obj_subsample, schema)
123         for core_check in core_checks:
124             results = core_check(*args)
125             if isinstance(results, CoreCheckResult):
126                 results = [results]
127             results = cast(List[CoreCheckResult], results)
128             for result in results:
129                 if result.passed:
130                     continue
131 
132                 if result.schema_error is not None:
133                     error = result.schema_error
134                 else:
135                     assert result.reason_code is not None
136                     error = SchemaError(
137                         schema=schema,
138                         data=check_obj,
139                         message=result.message,
140                         failure_cases=result.failure_cases,
141                         check=result.check,
142                         check_index=result.check_index,
143                         check_output=result.check_output,
144                         reason_code=result.reason_code,
145                     )
146                     error_handler.collect_error(
147                         validation_type(result.reason_code),
148                         result.reason_code,
149                         error,
150                         original_exc=result.original_exc,
151                     )
152 
153         return error_handler
154 
155     def coerce_dtype(
156         self,
157         check_obj: pl.LazyFrame,
158         schema=None,
159         # pylint: disable=unused-argument
160     ) -> pl.LazyFrame:
161         """Coerce type of a pd.Series by type specified in dtype.
162 
163         :param check_obj: LazyFrame to coerce
164         :returns: coerced LazyFrame
165         """
166         assert schema is not None, "The `schema` argument must be provided."
167         if schema.dtype is None or not schema.coerce:
168             return check_obj
169 
170         config_ctx = get_config_context(validation_depth_default=None)
171         coerce_fn: Callable[[pl.LazyFrame], pl.LazyFrame] = (
172             schema.dtype.coerce
173             if config_ctx.validation_depth == ValidationDepth.SCHEMA_ONLY
174             else schema.dtype.try_coerce
175         )
176 
177         try:
178             return coerce_fn(check_obj)
179         except ParserError as exc:
180             raise SchemaError(
181                 schema=schema,
182                 data=check_obj,
183                 message=(
184                     f"Error while coercing '{schema.selector}' to type "
185                     f"{schema.dtype}: {exc}"
186                 ),
187                 check=f"coerce_dtype('{schema.dtype}')",
188                 reason_code=SchemaErrorReason.DATATYPE_COERCION,
189             ) from exc
190 
191     @validate_scope(scope=ValidationScope.DATA)
192     def check_nullable(
193         self,
194         check_obj: pl.LazyFrame,
195         schema,
196     ) -> List[CoreCheckResult]:
197         """Check if a column is nullable.
198 
199         This check considers nulls and nan values as effectively equivalent.
200         """
201         if schema.nullable:
202             return [
203                 CoreCheckResult(
204                     passed=True,
205                     check="not_nullable",
206                     reason_code=SchemaErrorReason.SERIES_CONTAINS_NULLS,
207                 )
208             ]
209 
210         if is_float_dtype(check_obj, schema.selector):
211             expr = pl.col(schema.selector).is_not_nan()
212         else:
213             expr = pl.col(schema.selector).is_not_null()
214 
215         isna = check_obj.select(expr)
216         passed = isna.select([pl.col("*").all()]).collect()
217         results = []
218         for column in isna.columns:
219             if passed.select(column).item():
220                 continue
221             failure_cases = (
222                 check_obj.with_context(
223                     isna.select(pl.col(column).alias(CHECK_OUTPUT_KEY))
224                 )
225                 .filter(pl.col(CHECK_OUTPUT_KEY).not_())
226                 .select(column)
227                 .collect()
228             )
229             results.append(
230                 CoreCheckResult(
231                     passed=cast(bool, passed.select(column).item()),
232                     check_output=isna.collect().rename(
233                         {column: CHECK_OUTPUT_KEY}
234                     ),
235                     check="not_nullable",
236                     reason_code=SchemaErrorReason.SERIES_CONTAINS_NULLS,
237                     message=(
238                         f"non-nullable column '{schema.selector}' contains "
239                         f"null values"
240                     ),
241                     failure_cases=failure_cases,
242                 )
243             )
244         return results
245 
246     @validate_scope(scope=ValidationScope.DATA)
247     def check_unique(
248         self,
249         check_obj: pl.LazyFrame,
250         schema,
251     ) -> List[CoreCheckResult]:
252         check_name = "field_uniqueness"
253         if not schema.unique:
254             return [
255                 CoreCheckResult(
256                     passed=True,
257                     check=check_name,
258                     reason_code=SchemaErrorReason.SERIES_CONTAINS_DUPLICATES,
259                 )
260             ]
261 
262         results = []
263         duplicates = (
264             check_obj.select(schema.selector)
265             .collect()
266             .select(pl.col("*").is_duplicated())
267         )
268         for column in duplicates.columns:
269             if duplicates.select(pl.col(column).any()).item():
270                 failure_cases = (
271                     check_obj.with_context(
272                         duplicates.select(
273                             pl.col(column).alias("_duplicated")
274                         ).lazy()
275                     )
276                     .filter(pl.col("_duplicated"))
277                     .select(column)
278                     .collect()
279                 )
280                 results.append(
281                     CoreCheckResult(
282                         passed=False,
283                         check=check_name,
284                         check_output=duplicates.select(
285                             pl.col(column).not_().alias(CHECK_OUTPUT_KEY)
286                         ),
287                         reason_code=SchemaErrorReason.SERIES_CONTAINS_DUPLICATES,
288                         message=(
289                             f"column '{schema.selector}' "
290                             f"not unique:\n{failure_cases}"
291                         ),
292                         failure_cases=failure_cases,
293                     )
294                 )
295 
296         return results
297 
298     @validate_scope(scope=ValidationScope.SCHEMA)
299     def check_dtype(
300         self,
301         check_obj: pl.LazyFrame,
302         schema: Column,
303     ) -> List[CoreCheckResult]:
304 
305         passed = True
306         failure_cases = None
307         msg = None
308 
309         if schema.dtype is None:
310             return [
311                 CoreCheckResult(
312                     passed=passed,
313                     check=f"dtype('{schema.dtype}')",
314                     reason_code=SchemaErrorReason.WRONG_DATATYPE,
315                     message=msg,
316                     failure_cases=failure_cases,
317                 )
318             ]
319 
320         results = []
321         check_obj_subset = check_obj.select(schema.selector)
322         for column in check_obj_subset.columns:
323             obj_dtype = check_obj_subset.schema[column]
324             results.append(
325                 CoreCheckResult(
326                     passed=schema.dtype.check(
327                         obj_dtype,
328                         PolarsData(check_obj_subset, schema.selector),
329                     ),
330                     check=f"dtype('{schema.dtype}')",
331                     reason_code=SchemaErrorReason.WRONG_DATATYPE,
332                     message=(
333                         f"expected column '{column}' to have type "
334                         f"{schema.dtype}, got {obj_dtype}"
335                     ),
336                     failure_cases=str(obj_dtype),
337                 )
338             )
339         return results
340 
341     # pylint: disable=unused-argument
342     @validate_scope(scope=ValidationScope.DATA)
343     def run_checks(self, check_obj, schema) -> List[CoreCheckResult]:
344         check_results: List[CoreCheckResult] = []
345         for check_index, check in enumerate(schema.checks):
346             try:
347                 check_results.append(
348                     self.run_check(
349                         check_obj,
350                         schema,
351                         check,
352                         check_index,
353                         schema.selector,
354                     )
355                 )
356             except Exception as err:  # pylint: disable=broad-except
357                 # catch other exceptions that may occur when executing the Check
358                 err_msg = f'"{err.args[0]}"' if len(err.args) > 0 else ""
359                 msg = f"{err.__class__.__name__}({err_msg})"
360                 check_results.append(
361                     CoreCheckResult(
362                         passed=False,
363                         check=check,
364                         check_index=check_index,
365                         reason_code=SchemaErrorReason.CHECK_ERROR,
366                         message=msg,
367                         failure_cases=msg,
368                         original_exc=err,
369                     )
370                 )
371         return check_results
372 
373     def set_default(self, check_obj: pl.LazyFrame, schema) -> pl.LazyFrame:
374         """Set default values for columns with missing values."""
375         if hasattr(schema, "default") and schema.default is None:
376             return check_obj
377 
378         default_value = pl.lit(schema.default, dtype=schema.dtype.type)
379         expr = pl.col(schema.selector)
380         if is_float_dtype(check_obj, schema.selector):
381             expr = expr.fill_nan(default_value)
382         else:
383             expr = expr.fill_null(default_value)
384 
385         return check_obj.with_columns(expr)
386
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pandera/backends/polars/components.py b/pandera/backends/polars/components.py
--- a/pandera/backends/polars/components.py
+++ b/pandera/backends/polars/components.py
@@ -207,10 +207,9 @@
                 )
             ]
 
+        expr = pl.col(schema.selector).is_not_null()
         if is_float_dtype(check_obj, schema.selector):
-            expr = pl.col(schema.selector).is_not_nan()
-        else:
-            expr = pl.col(schema.selector).is_not_null()
+            expr = expr & pl.col(schema.selector).is_not_nan()
 
         isna = check_obj.select(expr)
         passed = isna.select([pl.col("*").all()]).collect()

{"golden_diff": "diff --git a/pandera/backends/polars/components.py b/pandera/backends/polars/components.py\n--- a/pandera/backends/polars/components.py\n+++ b/pandera/backends/polars/components.py\n@@ -207,10 +207,9 @@\n                 )\n             ]\n \n+        expr = pl.col(schema.selector).is_not_null()\n         if is_float_dtype(check_obj, schema.selector):\n-            expr = pl.col(schema.selector).is_not_nan()\n-        else:\n-            expr = pl.col(schema.selector).is_not_null()\n+            expr = expr & pl.col(schema.selector).is_not_nan()\n \n         isna = check_obj.select(expr)\n         passed = isna.select([pl.col(\"*\").all()]).collect()\n", "issue": "Nullability for `pl.Float64` in `pl.DataFrame` fails\n**Describe the bug**\r\nThe nullability constraint is not enforced in `pl.DataFrame` when the underlying data type is `pl.Float64`. When I provide a `pl.DataFrame` with a float column that contains `None`, it passes.\r\n\r\n- [x] I have checked that this issue has not already been reported.\r\n- [x] I have confirmed this bug exists on the latest version of pandera.\r\n\r\n#### Code Sample, a copy-pastable example\r\n\r\n```python\r\nimport polars as pl\r\nimport pandera.polars as pa\r\n\r\n\r\nclass Schema(pa.DataFrameModel):\r\n    col: float = pa.Field(nullable=False)\r\n\r\n\r\ndf = pl.DataFrame(data={\"col\": [1.0, 2.5, None]}, schema={\"col\": pl.Float64})\r\n\r\nSchema.validate(df)\r\n\r\n\r\n```\r\n\r\n#### Expected behavior\r\nThe validation should vail as the column `col` contains a `None` value, but the schema requires it to be non-nullable.\r\n\r\n#### Desktop (please complete the following information):\r\n\r\n - OS: MacOS\r\n - Browser: Chrome\r\n\r\n#### Additional context\r\nThe nullability constraint is correctly enforced if the underlying data type is `int` or `str`.\r\nFor `float`, the nullability constraint correctly detects NULL values in the form of `np.nan`.\r\n\r\n\n", "before_files": [{"content": "\"\"\"Validation backend for polars components.\"\"\"\n\nimport warnings\nfrom typing import Any, Callable, Iterable, List, Optional, cast\n\nimport polars as pl\n\nfrom pandera.api.base.error_handler import ErrorHandler\nfrom pandera.api.polars.components import Column\nfrom pandera.api.polars.types import PolarsData\nfrom pandera.backends.base import CoreCheckResult\nfrom pandera.backends.polars.base import PolarsSchemaBackend, is_float_dtype\nfrom pandera.config import ValidationDepth, ValidationScope, get_config_context\nfrom pandera.constants import CHECK_OUTPUT_KEY\nfrom pandera.errors import (\n    ParserError,\n    SchemaDefinitionError,\n    SchemaError,\n    SchemaErrorReason,\n    SchemaErrors,\n)\nfrom pandera.validation_depth import validate_scope, validation_type\n\n\nclass ColumnBackend(PolarsSchemaBackend):\n    \"\"\"Column backend for polars LazyFrames.\"\"\"\n\n    def preprocess(self, check_obj, inplace: bool = False):\n        \"\"\"Returns a copy of the object if inplace is False.\"\"\"\n        # NOTE: is this even necessary?\n        return check_obj if inplace else check_obj.clone()\n\n    # pylint: disable=too-many-locals\n    def validate(\n        self,\n        check_obj: pl.LazyFrame,\n        schema: Column,\n        *,\n        head: Optional[int] = None,\n        tail: Optional[int] = None,\n        sample: Optional[int] = None,\n        random_state: Optional[int] = None,\n        lazy: bool = False,\n        inplace: bool = False,\n    ) -> pl.LazyFrame:\n\n        if inplace:\n            warnings.warn(\"setting inplace=True will have no effect.\")\n\n        if schema.name is None:\n            raise SchemaDefinitionError(\n                \"Column schema must have a name specified.\"\n            )\n\n        error_handler = ErrorHandler(lazy)\n        check_obj = self.preprocess(check_obj, inplace)\n\n        if getattr(schema, \"drop_invalid_rows\", False) and not lazy:\n            raise SchemaDefinitionError(\n                \"When drop_invalid_rows is True, lazy must be set to True.\"\n            )\n\n        core_parsers: List[Callable[..., Any]] = [\n            self.coerce_dtype,\n            self.set_default,\n        ]\n\n        for parser in core_parsers:\n            try:\n                check_obj = parser(check_obj, schema)\n            except SchemaError as exc:\n                error_handler.collect_error(\n                    validation_type(exc.reason_code),\n                    exc.reason_code,\n                    exc,\n                )\n            except SchemaErrors as exc:\n                error_handler.collect_errors(exc.schema_errors)\n\n        error_handler = self.run_checks_and_handle_errors(\n            error_handler,\n            schema,\n            check_obj,\n            head=head,\n            tail=tail,\n            sample=sample,\n            random_state=random_state,\n        )\n\n        if lazy and error_handler.collected_errors:\n            if getattr(schema, \"drop_invalid_rows\", False):\n                check_obj = self.drop_invalid_rows(check_obj, error_handler)\n            else:\n                raise SchemaErrors(\n                    schema=schema,\n                    schema_errors=error_handler.schema_errors,\n                    data=check_obj,\n                )\n\n        return check_obj\n\n    def get_regex_columns(self, schema, check_obj) -> Iterable:\n        return check_obj.select(pl.col(schema.selector)).columns\n\n    def run_checks_and_handle_errors(\n        self,\n        error_handler: ErrorHandler,\n        schema,\n        check_obj: pl.LazyFrame,\n        **subsample_kwargs,\n    ):\n        \"\"\"Run checks on schema\"\"\"\n        # pylint: disable=too-many-locals\n        check_obj_subsample = self.subsample(check_obj, **subsample_kwargs)\n\n        core_checks = [\n            self.check_nullable,\n            self.check_unique,\n            self.check_dtype,\n            self.run_checks,\n        ]\n        args = (check_obj_subsample, schema)\n        for core_check in core_checks:\n            results = core_check(*args)\n            if isinstance(results, CoreCheckResult):\n                results = [results]\n            results = cast(List[CoreCheckResult], results)\n            for result in results:\n                if result.passed:\n                    continue\n\n                if result.schema_error is not None:\n                    error = result.schema_error\n                else:\n                    assert result.reason_code is not None\n                    error = SchemaError(\n                        schema=schema,\n                        data=check_obj,\n                        message=result.message,\n                        failure_cases=result.failure_cases,\n                        check=result.check,\n                        check_index=result.check_index,\n                        check_output=result.check_output,\n                        reason_code=result.reason_code,\n                    )\n                    error_handler.collect_error(\n                        validation_type(result.reason_code),\n                        result.reason_code,\n                        error,\n                        original_exc=result.original_exc,\n                    )\n\n        return error_handler\n\n    def coerce_dtype(\n        self,\n        check_obj: pl.LazyFrame,\n        schema=None,\n        # pylint: disable=unused-argument\n    ) -> pl.LazyFrame:\n        \"\"\"Coerce type of a pd.Series by type specified in dtype.\n\n        :param check_obj: LazyFrame to coerce\n        :returns: coerced LazyFrame\n        \"\"\"\n        assert schema is not None, \"The `schema` argument must be provided.\"\n        if schema.dtype is None or not schema.coerce:\n            return check_obj\n\n        config_ctx = get_config_context(validation_depth_default=None)\n        coerce_fn: Callable[[pl.LazyFrame], pl.LazyFrame] = (\n            schema.dtype.coerce\n            if config_ctx.validation_depth == ValidationDepth.SCHEMA_ONLY\n            else schema.dtype.try_coerce\n        )\n\n        try:\n            return coerce_fn(check_obj)\n        except ParserError as exc:\n            raise SchemaError(\n                schema=schema,\n                data=check_obj,\n                message=(\n                    f\"Error while coercing '{schema.selector}' to type \"\n                    f\"{schema.dtype}: {exc}\"\n                ),\n                check=f\"coerce_dtype('{schema.dtype}')\",\n                reason_code=SchemaErrorReason.DATATYPE_COERCION,\n            ) from exc\n\n    @validate_scope(scope=ValidationScope.DATA)\n    def check_nullable(\n        self,\n        check_obj: pl.LazyFrame,\n        schema,\n    ) -> List[CoreCheckResult]:\n        \"\"\"Check if a column is nullable.\n\n        This check considers nulls and nan values as effectively equivalent.\n        \"\"\"\n        if schema.nullable:\n            return [\n                CoreCheckResult(\n                    passed=True,\n                    check=\"not_nullable\",\n                    reason_code=SchemaErrorReason.SERIES_CONTAINS_NULLS,\n                )\n            ]\n\n        if is_float_dtype(check_obj, schema.selector):\n            expr = pl.col(schema.selector).is_not_nan()\n        else:\n            expr = pl.col(schema.selector).is_not_null()\n\n        isna = check_obj.select(expr)\n        passed = isna.select([pl.col(\"*\").all()]).collect()\n        results = []\n        for column in isna.columns:\n            if passed.select(column).item():\n                continue\n            failure_cases = (\n                check_obj.with_context(\n                    isna.select(pl.col(column).alias(CHECK_OUTPUT_KEY))\n                )\n                .filter(pl.col(CHECK_OUTPUT_KEY).not_())\n                .select(column)\n                .collect()\n            )\n            results.append(\n                CoreCheckResult(\n                    passed=cast(bool, passed.select(column).item()),\n                    check_output=isna.collect().rename(\n                        {column: CHECK_OUTPUT_KEY}\n                    ),\n                    check=\"not_nullable\",\n                    reason_code=SchemaErrorReason.SERIES_CONTAINS_NULLS,\n                    message=(\n                        f\"non-nullable column '{schema.selector}' contains \"\n                        f\"null values\"\n                    ),\n                    failure_cases=failure_cases,\n                )\n            )\n        return results\n\n    @validate_scope(scope=ValidationScope.DATA)\n    def check_unique(\n        self,\n        check_obj: pl.LazyFrame,\n        schema,\n    ) -> List[CoreCheckResult]:\n        check_name = \"field_uniqueness\"\n        if not schema.unique:\n            return [\n                CoreCheckResult(\n                    passed=True,\n                    check=check_name,\n                    reason_code=SchemaErrorReason.SERIES_CONTAINS_DUPLICATES,\n                )\n            ]\n\n        results = []\n        duplicates = (\n            check_obj.select(schema.selector)\n            .collect()\n            .select(pl.col(\"*\").is_duplicated())\n        )\n        for column in duplicates.columns:\n            if duplicates.select(pl.col(column).any()).item():\n                failure_cases = (\n                    check_obj.with_context(\n                        duplicates.select(\n                            pl.col(column).alias(\"_duplicated\")\n                        ).lazy()\n                    )\n                    .filter(pl.col(\"_duplicated\"))\n                    .select(column)\n                    .collect()\n                )\n                results.append(\n                    CoreCheckResult(\n                        passed=False,\n                        check=check_name,\n                        check_output=duplicates.select(\n                            pl.col(column).not_().alias(CHECK_OUTPUT_KEY)\n                        ),\n                        reason_code=SchemaErrorReason.SERIES_CONTAINS_DUPLICATES,\n                        message=(\n                            f\"column '{schema.selector}' \"\n                            f\"not unique:\\n{failure_cases}\"\n                        ),\n                        failure_cases=failure_cases,\n                    )\n                )\n\n        return results\n\n    @validate_scope(scope=ValidationScope.SCHEMA)\n    def check_dtype(\n        self,\n        check_obj: pl.LazyFrame,\n        schema: Column,\n    ) -> List[CoreCheckResult]:\n\n        passed = True\n        failure_cases = None\n        msg = None\n\n        if schema.dtype is None:\n            return [\n                CoreCheckResult(\n                    passed=passed,\n                    check=f\"dtype('{schema.dtype}')\",\n                    reason_code=SchemaErrorReason.WRONG_DATATYPE,\n                    message=msg,\n                    failure_cases=failure_cases,\n                )\n            ]\n\n        results = []\n        check_obj_subset = check_obj.select(schema.selector)\n        for column in check_obj_subset.columns:\n            obj_dtype = check_obj_subset.schema[column]\n            results.append(\n                CoreCheckResult(\n                    passed=schema.dtype.check(\n                        obj_dtype,\n                        PolarsData(check_obj_subset, schema.selector),\n                    ),\n                    check=f\"dtype('{schema.dtype}')\",\n                    reason_code=SchemaErrorReason.WRONG_DATATYPE,\n                    message=(\n                        f\"expected column '{column}' to have type \"\n                        f\"{schema.dtype}, got {obj_dtype}\"\n                    ),\n                    failure_cases=str(obj_dtype),\n                )\n            )\n        return results\n\n    # pylint: disable=unused-argument\n    @validate_scope(scope=ValidationScope.DATA)\n    def run_checks(self, check_obj, schema) -> List[CoreCheckResult]:\n        check_results: List[CoreCheckResult] = []\n        for check_index, check in enumerate(schema.checks):\n            try:\n                check_results.append(\n                    self.run_check(\n                        check_obj,\n                        schema,\n                        check,\n                        check_index,\n                        schema.selector,\n                    )\n                )\n            except Exception as err:  # pylint: disable=broad-except\n                # catch other exceptions that may occur when executing the Check\n                err_msg = f'\"{err.args[0]}\"' if len(err.args) > 0 else \"\"\n                msg = f\"{err.__class__.__name__}({err_msg})\"\n                check_results.append(\n                    CoreCheckResult(\n                        passed=False,\n                        check=check,\n                        check_index=check_index,\n                        reason_code=SchemaErrorReason.CHECK_ERROR,\n                        message=msg,\n                        failure_cases=msg,\n                        original_exc=err,\n                    )\n                )\n        return check_results\n\n    def set_default(self, check_obj: pl.LazyFrame, schema) -> pl.LazyFrame:\n        \"\"\"Set default values for columns with missing values.\"\"\"\n        if hasattr(schema, \"default\") and schema.default is None:\n            return check_obj\n\n        default_value = pl.lit(schema.default, dtype=schema.dtype.type)\n        expr = pl.col(schema.selector)\n        if is_float_dtype(check_obj, schema.selector):\n            expr = expr.fill_nan(default_value)\n        else:\n            expr = expr.fill_null(default_value)\n\n        return check_obj.with_columns(expr)\n", "path": "pandera/backends/polars/components.py"}], "after_files": [{"content": "\"\"\"Validation backend for polars components.\"\"\"\n\nimport warnings\nfrom typing import Any, Callable, Iterable, List, Optional, cast\n\nimport polars as pl\n\nfrom pandera.api.base.error_handler import ErrorHandler\nfrom pandera.api.polars.components import Column\nfrom pandera.api.polars.types import PolarsData\nfrom pandera.backends.base import CoreCheckResult\nfrom pandera.backends.polars.base import PolarsSchemaBackend, is_float_dtype\nfrom pandera.config import ValidationDepth, ValidationScope, get_config_context\nfrom pandera.constants import CHECK_OUTPUT_KEY\nfrom pandera.errors import (\n    ParserError,\n    SchemaDefinitionError,\n    SchemaError,\n    SchemaErrorReason,\n    SchemaErrors,\n)\nfrom pandera.validation_depth import validate_scope, validation_type\n\n\nclass ColumnBackend(PolarsSchemaBackend):\n    \"\"\"Column backend for polars LazyFrames.\"\"\"\n\n    def preprocess(self, check_obj, inplace: bool = False):\n        \"\"\"Returns a copy of the object if inplace is False.\"\"\"\n        # NOTE: is this even necessary?\n        return check_obj if inplace else check_obj.clone()\n\n    # pylint: disable=too-many-locals\n    def validate(\n        self,\n        check_obj: pl.LazyFrame,\n        schema: Column,\n        *,\n        head: Optional[int] = None,\n        tail: Optional[int] = None,\n        sample: Optional[int] = None,\n        random_state: Optional[int] = None,\n        lazy: bool = False,\n        inplace: bool = False,\n    ) -> pl.LazyFrame:\n\n        if inplace:\n            warnings.warn(\"setting inplace=True will have no effect.\")\n\n        if schema.name is None:\n            raise SchemaDefinitionError(\n                \"Column schema must have a name specified.\"\n            )\n\n        error_handler = ErrorHandler(lazy)\n        check_obj = self.preprocess(check_obj, inplace)\n\n        if getattr(schema, \"drop_invalid_rows\", False) and not lazy:\n            raise SchemaDefinitionError(\n                \"When drop_invalid_rows is True, lazy must be set to True.\"\n            )\n\n        core_parsers: List[Callable[..., Any]] = [\n            self.coerce_dtype,\n            self.set_default,\n        ]\n\n        for parser in core_parsers:\n            try:\n                check_obj = parser(check_obj, schema)\n            except SchemaError as exc:\n                error_handler.collect_error(\n                    validation_type(exc.reason_code),\n                    exc.reason_code,\n                    exc,\n                )\n            except SchemaErrors as exc:\n                error_handler.collect_errors(exc.schema_errors)\n\n        error_handler = self.run_checks_and_handle_errors(\n            error_handler,\n            schema,\n            check_obj,\n            head=head,\n            tail=tail,\n            sample=sample,\n            random_state=random_state,\n        )\n\n        if lazy and error_handler.collected_errors:\n            if getattr(schema, \"drop_invalid_rows\", False):\n                check_obj = self.drop_invalid_rows(check_obj, error_handler)\n            else:\n                raise SchemaErrors(\n                    schema=schema,\n                    schema_errors=error_handler.schema_errors,\n                    data=check_obj,\n                )\n\n        return check_obj\n\n    def get_regex_columns(self, schema, check_obj) -> Iterable:\n        return check_obj.select(pl.col(schema.selector)).columns\n\n    def run_checks_and_handle_errors(\n        self,\n        error_handler: ErrorHandler,\n        schema,\n        check_obj: pl.LazyFrame,\n        **subsample_kwargs,\n    ):\n        \"\"\"Run checks on schema\"\"\"\n        # pylint: disable=too-many-locals\n        check_obj_subsample = self.subsample(check_obj, **subsample_kwargs)\n\n        core_checks = [\n            self.check_nullable,\n            self.check_unique,\n            self.check_dtype,\n            self.run_checks,\n        ]\n        args = (check_obj_subsample, schema)\n        for core_check in core_checks:\n            results = core_check(*args)\n            if isinstance(results, CoreCheckResult):\n                results = [results]\n            results = cast(List[CoreCheckResult], results)\n            for result in results:\n                if result.passed:\n                    continue\n\n                if result.schema_error is not None:\n                    error = result.schema_error\n                else:\n                    assert result.reason_code is not None\n                    error = SchemaError(\n                        schema=schema,\n                        data=check_obj,\n                        message=result.message,\n                        failure_cases=result.failure_cases,\n                        check=result.check,\n                        check_index=result.check_index,\n                        check_output=result.check_output,\n                        reason_code=result.reason_code,\n                    )\n                    error_handler.collect_error(\n                        validation_type(result.reason_code),\n                        result.reason_code,\n                        error,\n                        original_exc=result.original_exc,\n                    )\n\n        return error_handler\n\n    def coerce_dtype(\n        self,\n        check_obj: pl.LazyFrame,\n        schema=None,\n        # pylint: disable=unused-argument\n    ) -> pl.LazyFrame:\n        \"\"\"Coerce type of a pd.Series by type specified in dtype.\n\n        :param check_obj: LazyFrame to coerce\n        :returns: coerced LazyFrame\n        \"\"\"\n        assert schema is not None, \"The `schema` argument must be provided.\"\n        if schema.dtype is None or not schema.coerce:\n            return check_obj\n\n        config_ctx = get_config_context(validation_depth_default=None)\n        coerce_fn: Callable[[pl.LazyFrame], pl.LazyFrame] = (\n            schema.dtype.coerce\n            if config_ctx.validation_depth == ValidationDepth.SCHEMA_ONLY\n            else schema.dtype.try_coerce\n        )\n\n        try:\n            return coerce_fn(check_obj)\n        except ParserError as exc:\n            raise SchemaError(\n                schema=schema,\n                data=check_obj,\n                message=(\n                    f\"Error while coercing '{schema.selector}' to type \"\n                    f\"{schema.dtype}: {exc}\"\n                ),\n                check=f\"coerce_dtype('{schema.dtype}')\",\n                reason_code=SchemaErrorReason.DATATYPE_COERCION,\n            ) from exc\n\n    @validate_scope(scope=ValidationScope.DATA)\n    def check_nullable(\n        self,\n        check_obj: pl.LazyFrame,\n        schema,\n    ) -> List[CoreCheckResult]:\n        \"\"\"Check if a column is nullable.\n\n        This check considers nulls and nan values as effectively equivalent.\n        \"\"\"\n        if schema.nullable:\n            return [\n                CoreCheckResult(\n                    passed=True,\n                    check=\"not_nullable\",\n                    reason_code=SchemaErrorReason.SERIES_CONTAINS_NULLS,\n                )\n            ]\n\n        expr = pl.col(schema.selector).is_not_null()\n        if is_float_dtype(check_obj, schema.selector):\n            expr = expr & pl.col(schema.selector).is_not_nan()\n\n        isna = check_obj.select(expr)\n        passed = isna.select([pl.col(\"*\").all()]).collect()\n        results = []\n        for column in isna.columns:\n            if passed.select(column).item():\n                continue\n            failure_cases = (\n                check_obj.with_context(\n                    isna.select(pl.col(column).alias(CHECK_OUTPUT_KEY))\n                )\n                .filter(pl.col(CHECK_OUTPUT_KEY).not_())\n                .select(column)\n                .collect()\n            )\n            results.append(\n                CoreCheckResult(\n                    passed=cast(bool, passed.select(column).item()),\n                    check_output=isna.collect().rename(\n                        {column: CHECK_OUTPUT_KEY}\n                    ),\n                    check=\"not_nullable\",\n                    reason_code=SchemaErrorReason.SERIES_CONTAINS_NULLS,\n                    message=(\n                        f\"non-nullable column '{schema.selector}' contains \"\n                        f\"null values\"\n                    ),\n                    failure_cases=failure_cases,\n                )\n            )\n        return results\n\n    @validate_scope(scope=ValidationScope.DATA)\n    def check_unique(\n        self,\n        check_obj: pl.LazyFrame,\n        schema,\n    ) -> List[CoreCheckResult]:\n        check_name = \"field_uniqueness\"\n        if not schema.unique:\n            return [\n                CoreCheckResult(\n                    passed=True,\n                    check=check_name,\n                    reason_code=SchemaErrorReason.SERIES_CONTAINS_DUPLICATES,\n                )\n            ]\n\n        results = []\n        duplicates = (\n            check_obj.select(schema.selector)\n            .collect()\n            .select(pl.col(\"*\").is_duplicated())\n        )\n        for column in duplicates.columns:\n            if duplicates.select(pl.col(column).any()).item():\n                failure_cases = (\n                    check_obj.with_context(\n                        duplicates.select(\n                            pl.col(column).alias(\"_duplicated\")\n                        ).lazy()\n                    )\n                    .filter(pl.col(\"_duplicated\"))\n                    .select(column)\n                    .collect()\n                )\n                results.append(\n                    CoreCheckResult(\n                        passed=False,\n                        check=check_name,\n                        check_output=duplicates.select(\n                            pl.col(column).not_().alias(CHECK_OUTPUT_KEY)\n                        ),\n                        reason_code=SchemaErrorReason.SERIES_CONTAINS_DUPLICATES,\n                        message=(\n                            f\"column '{schema.selector}' \"\n                            f\"not unique:\\n{failure_cases}\"\n                        ),\n                        failure_cases=failure_cases,\n                    )\n                )\n\n        return results\n\n    @validate_scope(scope=ValidationScope.SCHEMA)\n    def check_dtype(\n        self,\n        check_obj: pl.LazyFrame,\n        schema: Column,\n    ) -> List[CoreCheckResult]:\n\n        passed = True\n        failure_cases = None\n        msg = None\n\n        if schema.dtype is None:\n            return [\n                CoreCheckResult(\n                    passed=passed,\n                    check=f\"dtype('{schema.dtype}')\",\n                    reason_code=SchemaErrorReason.WRONG_DATATYPE,\n                    message=msg,\n                    failure_cases=failure_cases,\n                )\n            ]\n\n        results = []\n        check_obj_subset = check_obj.select(schema.selector)\n        for column in check_obj_subset.columns:\n            obj_dtype = check_obj_subset.schema[column]\n            results.append(\n                CoreCheckResult(\n                    passed=schema.dtype.check(\n                        obj_dtype,\n                        PolarsData(check_obj_subset, schema.selector),\n                    ),\n                    check=f\"dtype('{schema.dtype}')\",\n                    reason_code=SchemaErrorReason.WRONG_DATATYPE,\n                    message=(\n                        f\"expected column '{column}' to have type \"\n                        f\"{schema.dtype}, got {obj_dtype}\"\n                    ),\n                    failure_cases=str(obj_dtype),\n                )\n            )\n        return results\n\n    # pylint: disable=unused-argument\n    @validate_scope(scope=ValidationScope.DATA)\n    def run_checks(self, check_obj, schema) -> List[CoreCheckResult]:\n        check_results: List[CoreCheckResult] = []\n        for check_index, check in enumerate(schema.checks):\n            try:\n                check_results.append(\n                    self.run_check(\n                        check_obj,\n                        schema,\n                        check,\n                        check_index,\n                        schema.selector,\n                    )\n                )\n            except Exception as err:  # pylint: disable=broad-except\n                # catch other exceptions that may occur when executing the Check\n                err_msg = f'\"{err.args[0]}\"' if len(err.args) > 0 else \"\"\n                msg = f\"{err.__class__.__name__}({err_msg})\"\n                check_results.append(\n                    CoreCheckResult(\n                        passed=False,\n                        check=check,\n                        check_index=check_index,\n                        reason_code=SchemaErrorReason.CHECK_ERROR,\n                        message=msg,\n                        failure_cases=msg,\n                        original_exc=err,\n                    )\n                )\n        return check_results\n\n    def set_default(self, check_obj: pl.LazyFrame, schema) -> pl.LazyFrame:\n        \"\"\"Set default values for columns with missing values.\"\"\"\n        if hasattr(schema, \"default\") and schema.default is None:\n            return check_obj\n\n        default_value = pl.lit(schema.default, dtype=schema.dtype.type)\n        expr = pl.col(schema.selector)\n        if is_float_dtype(check_obj, schema.selector):\n            expr = expr.fill_nan(default_value)\n        else:\n            expr = expr.fill_null(default_value)\n\n        return check_obj.with_columns(expr)\n", "path": "pandera/backends/polars/components.py"}]}