Repository: unionai-oss/pandera

Issue:
Output from `schema.to_script()` no longer works as standalone script
**Describe the bug**
When using the `to_script()` method the `dtype` values are from `pandera.engines` but `pandera` is not included in the imports on the script 

- [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.
- [ ] (optional) I have confirmed this bug exists on the master branch of pandera.

**Note**: Please read [this guide](https://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports) detailing how to provide the necessary information for us to reproduce your bug.

#### Code Sample, a copy-pastable example

```python
import pandas as pd
import pandera as pa

titanic = pd.read_csv("https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv")
schema = pa.infer_schema(titanic)

exec(schema.to_script())
```

#### Expected behavior
I would expect the code generated to be executable, this used to be the case when I first started using the library.

#### Desktop (please complete the following information):

 - OS: Ubuntu
 - Browser: Chrome
 - Version: 0.13.3

#### Screenshots
Error:
![Screenshot 2022-11-01 at 10 53 40](https://user-images.githubusercontent.com/12260327/199217658-27eacdea-18a6-4ea6-87ca-9301710141a6.png)

Missing Import:
![Screenshot 2022-11-01 at 10 54 27](https://user-images.githubusercontent.com/12260327/199218155-f5d8e63d-0883-4a4c-8dac-c62536fbfc98.png)


#### Additional context
Add any other context about the problem here.



Discussion:

Resolving patch:
diff --git a/pandera/engines/pandas_engine.py b/pandera/engines/pandas_engine.py
--- a/pandera/engines/pandas_engine.py
+++ b/pandera/engines/pandas_engine.py
@@ -745,7 +745,11 @@ def _get_to_datetime_fn(obj: Any) -> Callable:
 )
 @immutable(init=True)
 class DateTime(_BaseDateTime, dtypes.Timestamp):
-    """Semantic representation of a :class:`pandas.DatetimeTZDtype`."""
+    """Semantic representation of a potentially timezone-aware datetime.
+
+    Uses ``np.dtype("datetime64[ns]")`` for non-timezone aware datetimes and
+    :class:`pandas.DatetimeTZDtype` for timezone-aware datetimes.
+    """
 
     type: Optional[_PandasDatetime] = dataclasses.field(
         default=None, init=False
diff --git a/pandera/io.py b/pandera/io.py
--- a/pandera/io.py
+++ b/pandera/io.py
@@ -34,8 +34,22 @@
 DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
 
 
-def _get_qualified_name(cls: type) -> str:
-    return f"{cls.__module__}.{cls.__qualname__}"
+def _get_dtype_string_alias(dtype: pandas_engine.DataType) -> str:
+    """Get string alias of the datatype for serialization.
+
+    Calling pandas_engine.Engine.dtype(<string_alias>) should be a valid
+    operation
+    """
+    str_alias = str(dtype)
+    try:
+        pandas_engine.Engine.dtype(str_alias)
+    except TypeError as e:  # pragma: no cover
+        raise TypeError(
+            f"string alias {str_alias} for datatype "
+            f"'{dtype.__module__}.{dtype.__class__.__name__}' not "
+            "recognized."
+        ) from e
+    return f'"{dtype}"'
 
 
 def _serialize_check_stats(check_stats, dtype=None):
@@ -152,10 +166,16 @@ def serialize_schema(dataframe_schema):
         "columns": columns,
         "checks": checks,
         "index": index,
+        "dtype": dataframe_schema.dtype,
         "coerce": dataframe_schema.coerce,
         "strict": dataframe_schema.strict,
-        "unique": dataframe_schema.unique,
+        "name": dataframe_schema.name,
         "ordered": dataframe_schema.ordered,
+        "unique": dataframe_schema.unique,
+        "report_duplicates": dataframe_schema._report_duplicates,
+        "unique_column_names": dataframe_schema.unique_column_names,
+        "title": dataframe_schema.title,
+        "description": dataframe_schema.description,
     }
 
 
@@ -272,10 +292,18 @@ def deserialize_schema(serialized_schema):
         columns=columns,
         checks=checks,
         index=index,
+        dtype=serialized_schema.get("dtype", None),
         coerce=serialized_schema.get("coerce", False),
         strict=serialized_schema.get("strict", False),
-        unique=serialized_schema.get("unique", None),
+        name=serialized_schema.get("name", None),
         ordered=serialized_schema.get("ordered", False),
+        unique=serialized_schema.get("unique", None),
+        report_duplicates=serialized_schema.get("_report_duplicates", "all"),
+        unique_column_names=serialized_schema.get(
+            "unique_column_names", False
+        ),
+        title=serialized_schema.get("title", None),
+        description=serialized_schema.get("description", None),
     )
 
 
@@ -370,10 +398,18 @@ def to_json(dataframe_schema, target=None, **kwargs):
 
 schema = DataFrameSchema(
     columns={{{columns}}},
+    checks={checks},
     index={index},
+    dtype={dtype},
     coerce={coerce},
     strict={strict},
     name={name},
+    ordered={ordered},
+    unique={unique},
+    report_duplicates={report_duplicates},
+    unique_column_names={unique_column_names},
+    title={title},
+    description={description},
 )
 """
 
@@ -434,7 +470,7 @@ def _format_index(index_statistics):
         description = properties.get("description")
         title = properties.get("title")
         index_code = INDEX_TEMPLATE.format(
-            dtype=f"{_get_qualified_name(dtype.__class__)}",
+            dtype=(None if dtype is None else _get_dtype_string_alias(dtype)),
             checks=(
                 "None"
                 if properties["checks"] is None
@@ -479,9 +515,7 @@ def to_script(dataframe_schema, path_or_buf=None):
         description = properties["description"]
         title = properties["title"]
         column_code = COLUMN_TEMPLATE.format(
-            dtype=(
-                None if dtype is None else _get_qualified_name(dtype.__class__)
-            ),
+            dtype=(None if dtype is None else _get_dtype_string_alias(dtype)),
             checks=_format_checks(properties["checks"]),
             nullable=properties["nullable"],
             unique=properties["unique"],
@@ -503,11 +537,18 @@ def to_script(dataframe_schema, path_or_buf=None):
 
     script = SCRIPT_TEMPLATE.format(
         columns=column_str,
+        checks=statistics["checks"],
         index=index,
+        dtype=dataframe_schema.dtype,
         coerce=dataframe_schema.coerce,
         strict=dataframe_schema.strict,
         name=dataframe_schema.name.__repr__(),
+        ordered=dataframe_schema.ordered,
         unique=dataframe_schema.unique,
+        report_duplicates=f'"{dataframe_schema._report_duplicates}"',
+        unique_column_names=dataframe_schema.unique_column_names,
+        title=dataframe_schema.title,
+        description=dataframe_schema.description,
     ).strip()
 
     # add pandas imports to handle datetime and timedelta.


Test patch:
diff --git a/tests/io/test_io.py b/tests/io/test_io.py
--- a/tests/io/test_io.py
+++ b/tests/io/test_io.py
@@ -235,10 +235,16 @@ def _create_schema(index="single"):
   name: null
   unique: false
   coerce: false
+dtype: null
 coerce: false
 strict: true
-unique: null
+name: null
 ordered: false
+unique: null
+report_duplicates: all
+unique_column_names: false
+title: null
+description: null
 """
 
 
@@ -1215,10 +1221,16 @@ def datetime_check(pandas_obj, *, stat):
     regex: false
 checks: null
 index: null
+dtype: null
 coerce: true
 strict: true
-unique: null
+name: null
 ordered: false
+unique: null
+report_duplicates: all
+unique_column_names: false
+title: null
+description: null
 """
 
 VALID_FRICTIONLESS_DF = pd.DataFrame(