Repository: unionai-oss/pandera

Issue:
Annotated parametrized dtypes error on version >= 0.19.0
Hi, there is `TypeError: Annotation 'Annotated' requires all positional arguments ['args', 'kwargs'].` error when it is specified annotated parametrized dtype in schema (e.g. `Annotated[pd.PeriodDtype, "Q"]`). It occurs on version equal or above `0.19.0`.

#### Code Sample

```python
import pandas as pd
import pandera as pa
from pandera.typing import Series

try:
    from typing import Annotated  # python 3.9+
except ImportError:
    from typing_extensions import Annotated


class FooSchema(pa.SchemaModel):
    col: Series[Annotated[pd.PeriodDtype, "Q"]]


FooSchema.to_schema()  # TypeError: Annotation 'Annotated' requires all positional arguments ['args', 'kwargs'].
```

#### Expected behavior

Annotated parametrized dtypes work without error according with [documentation](https://pandera.readthedocs.io/en/stable/dataframe_models.html#annotated).

#### Desktop

 - OS: `Windows`, `Linux`
 - Version: `0.19.2`, `0.19.1`, `0.19.0`

#### Additional context
I think it is the similar problem with `Annotated[pd.DatetimeTZDtype, "ns", "est"]` dtype but the error is different `TypeError: DatetimeTZDtype.__init__() got an unexpected keyword argument 'args'`.

```python
import pandas as pd
import pandera as pa
from pandera.typing import Series

try:
    from typing import Annotated  # python 3.9+
except ImportError:
    from typing_extensions import Annotated


class FooSchema(pa.SchemaModel):
    col: Series[Annotated[pd.DatetimeTZDtype, "ns", "est"]]


FooSchema.to_schema()  # TypeError: DatetimeTZDtype.__init__() got an unexpected keyword argument 'args'
```


Discussion:
this is a bug with using `Series`. Looking into this. in the mean time, can you just use the type without `Series`?

```python
class FooSchema(pa.SchemaModel):
    col: Annotated[pd.DatetimeTZDtype, "ns", "est"]
```

Resolving patch:
diff --git a/pandera/api/polars/components.py b/pandera/api/polars/components.py
--- a/pandera/api/polars/components.py
+++ b/pandera/api/polars/components.py
@@ -1,5 +1,7 @@
 """Schema components for polars."""
 
+from __future__ import annotations
+
 import logging
 from typing import Any, Optional
 
@@ -153,6 +155,26 @@ def validate(
             )
         return output
 
+    @property
+    def properties(self) -> dict[str, Any]:
+        """Get column properties."""
+        return {
+            "dtype": self.dtype,
+            "parsers": self.parsers,
+            "checks": self.checks,
+            "nullable": self.nullable,
+            "unique": self.unique,
+            "report_duplicates": self.report_duplicates,
+            "coerce": self.coerce,
+            "required": self.required,
+            "name": self.name,
+            "regex": self.regex,
+            "title": self.title,
+            "description": self.description,
+            "default": self.default,
+            "metadata": self.metadata,
+        }
+
     @property
     def dtype(self):
         return self._dtype
diff --git a/pandera/typing/common.py b/pandera/typing/common.py
--- a/pandera/typing/common.py
+++ b/pandera/typing/common.py
@@ -269,8 +269,8 @@ def _parse_annotation(self, raw_annotation: Type) -> None:
         metadata = getattr(raw_annotation, "__metadata__", None)
         if metadata:
             self.is_annotated_type = True
-        else:
-            metadata = getattr(self.arg, "__metadata__", None)
+        elif metadata := getattr(self.arg, "__metadata__", None):
+            self.arg = typing_inspect.get_args(self.arg)[0]
 
         self.metadata = metadata
         self.literal = typing_inspect.is_literal_type(self.arg)
@@ -286,5 +286,4 @@ def _parse_annotation(self, raw_annotation: Type) -> None:
             else:
                 # otherwise assume that the annotation is the data type itself.
                 self.arg = raw_annotation
-
         self.default_dtype = getattr(raw_annotation, "default_dtype", None)


Test patch:
diff --git a/tests/core/test_typing.py b/tests/core/test_typing.py
--- a/tests/core/test_typing.py
+++ b/tests/core/test_typing.py
@@ -322,78 +322,85 @@ class SchemaAnnotatedIntervalDtype(pa.DataFrameModel):
     class SchemaAnnotatedIntervalDtype(pa.DataFrameModel):  # type: ignore
         col: Series[Annotated[pd.IntervalDtype, "int32"]]
 
-    class SchemaAnnotatedPeriodDtype(pa.DataFrameModel):
-        col: Series[Annotated[pd.PeriodDtype, "D"]]
 
-    class SchemaAnnotatedSparseDtype(pa.DataFrameModel):
-        col: Series[Annotated[pd.SparseDtype, np.int32, 0]]
+class SchemaAnnotatedPeriodDtype(pa.DataFrameModel):
+    col: Series[Annotated[pd.PeriodDtype, "D"]]
 
-    @pytest.mark.parametrize(
-        "model, dtype, dtype_kwargs",
-        [
-            (
-                SchemaAnnotatedCategoricalDtype,
-                pd.CategoricalDtype,
-                {"categories": ["b", "a"], "ordered": True},
-            ),
-            (
-                SchemaAnnotatedDatetimeTZDtype,
-                pd.DatetimeTZDtype,
-                {"unit": "ns", "tz": "EST"},
-            ),
-            (
-                SchemaAnnotatedIntervalDtype,
-                pd.IntervalDtype,
-                (
-                    {"subtype": "int32", "closed": "both"}
-                    if pa.PANDAS_1_3_0_PLUS
-                    else {"subtype": "int32"}
-                ),
-            ),
-            (SchemaAnnotatedPeriodDtype, pd.PeriodDtype, {"freq": "D"}),
+
+class SchemaAnnotatedSparseDtype(pa.DataFrameModel):
+    col: Series[Annotated[pd.SparseDtype, np.int32, 0]]
+
+
+@pytest.mark.parametrize(
+    "model, dtype, dtype_kwargs",
+    [
+        (
+            SchemaAnnotatedCategoricalDtype,
+            pd.CategoricalDtype,
+            {"categories": ["b", "a"], "ordered": True},
+        ),
+        (
+            SchemaAnnotatedDatetimeTZDtype,
+            pd.DatetimeTZDtype,
+            {"unit": "ns", "tz": "EST"},
+        ),
+        (
+            SchemaAnnotatedIntervalDtype,
+            pd.IntervalDtype,
             (
-                SchemaAnnotatedSparseDtype,
-                pd.SparseDtype,
-                {"dtype": np.int32, "fill_value": 0},
+                {"subtype": "int32", "closed": "both"}
+                if pa.PANDAS_1_3_0_PLUS
+                else {"subtype": "int32"}
             ),
-        ],
+        ),
+        (SchemaAnnotatedPeriodDtype, pd.PeriodDtype, {"freq": "D"}),
+        (
+            SchemaAnnotatedSparseDtype,
+            pd.SparseDtype,
+            {"dtype": np.int32, "fill_value": 0},
+        ),
+    ],
+)
+def test_annotated_dtype(
+    model: Type[pa.DataFrameModel],
+    dtype: Type,
+    dtype_kwargs: Dict[str, Any],
+):
+    """Test type annotations for parametrized pandas extension dtypes."""
+    _test_annotated_dtype(model, dtype, dtype_kwargs)
+
+
+class SchemaInvalidAnnotatedDtype(pa.DataFrameModel):
+    col: Series[Annotated[pd.DatetimeTZDtype, "utc"]]
+
+
+def test_invalid_annotated_dtype():
+    """
+    Test incorrect number of parameters for parametrized pandas extension
+    dtypes.
+    """
+    err_msg = re.escape(
+        "Annotation 'DatetimeTZDtype' requires all "
+        r"positional arguments ['unit', 'tz']."
     )
-    def test_annotated_dtype(
-        model: Type[pa.DataFrameModel],
-        dtype: Type,
-        dtype_kwargs: Dict[str, Any],
-    ):
-        """Test type annotations for parametrized pandas extension dtypes."""
-        _test_annotated_dtype(model, dtype, dtype_kwargs)
-
-    class SchemaInvalidAnnotatedDtype(pa.DataFrameModel):
-        col: Series[Annotated[pd.DatetimeTZDtype, "utc"]]
-
-    def test_invalid_annotated_dtype():
-        """
-        Test incorrect number of parameters for parametrized pandas extension
-        dtypes.
-        """
-        err_msg = re.escape(
-            "Annotation 'DatetimeTZDtype' requires all "
-            r"positional arguments ['unit', 'tz']."
-        )
-        with pytest.raises(TypeError, match=err_msg):
-            SchemaInvalidAnnotatedDtype.to_schema()
-
-    class SchemaRedundantField(pa.DataFrameModel):
-        col: Series[Annotated[pd.DatetimeTZDtype, "utc"]] = pa.Field(
-            dtype_kwargs={"tz": "utc"}
-        )
-
-    def test_pandas_extension_dtype_redundant_field():
-        """
-        Test incorrect number of parameters for parametrized pandas extension
-        dtypes.
-        """
-        err_msg = r"Cannot specify redundant 'dtype_kwargs' for"
-        with pytest.raises(TypeError, match=err_msg):
-            SchemaRedundantField.to_schema()
+    with pytest.raises(TypeError, match=err_msg):
+        SchemaInvalidAnnotatedDtype.to_schema()
+
+
+class SchemaRedundantField(pa.DataFrameModel):
+    col: Series[Annotated[pd.DatetimeTZDtype, "utc"]] = pa.Field(
+        dtype_kwargs={"tz": "utc"}
+    )
+
+
+def test_pandas_extension_dtype_redundant_field():
+    """
+    Test incorrect number of parameters for parametrized pandas extension
+    dtypes.
+    """
+    err_msg = r"Cannot specify redundant 'dtype_kwargs' for"
+    with pytest.raises(TypeError, match=err_msg):
+        SchemaRedundantField.to_schema()
 
 
 class SchemaInt8Dtype(pa.DataFrameModel):