Repository: Fatal1ty/mashumaro

Issue:
Add support for typing.Pattern and re.Pattern
**Is your feature request related to a problem? Please describe.**
There is a standard type `Pattern` https://docs.python.org/3/library/typing.html#typing.Pattern. Support for annotations `re.Pattern` and `typing.Pattern` could be useful.

**Describe the solution you'd like**
A `Pattern` object can be deserialized from string using `re.compile`:
```python
print(type(re.compile("[a-z]+")))  # <class 're.Pattern'>
```
For serialization we can use `pattern` property:
```python
print(repr(re.compile("[a-z]+").pattern))  # '[a-z]+'
```

I'm not sure if we should distinguish different variations of a generic `Pattern` type. We can treat them all like `Pattern[str]` unless there is a reasonable use of `Pattern[bytes]`.

Discussion:

Solution patch:
diff --git a/README.md b/README.md
index 91b93450..6ee46975 100644
--- a/README.md
+++ b/README.md
@@ -265,6 +265,8 @@ for other less popular built-in types:
 * [`ipaddress.IPv6Network`](https://docs.python.org/3/library/ipaddress.html#ipaddress.IPv6Network)
 * [`ipaddress.IPv4Interface`](https://docs.python.org/3/library/ipaddress.html#ipaddress.IPv4Interface)
 * [`ipaddress.IPv6Interface`](https://docs.python.org/3/library/ipaddress.html#ipaddress.IPv6Interface)
+* [`typing.Pattern`](https://docs.python.org/3/library/typing.html#typing.Pattern)
+* [`re.Pattern`](https://docs.python.org/3/library/re.html#re.Pattern)
 
 for backported types from [`typing-extensions`](https://github.com/python/typing_extensions):
 * [`OrderedDict`](https://docs.python.org/3/library/typing.html#typing.OrderedDict)
diff --git a/mashumaro/core/meta/types/pack.py b/mashumaro/core/meta/types/pack.py
index d819938c..7c364654 100644
--- a/mashumaro/core/meta/types/pack.py
+++ b/mashumaro/core/meta/types/pack.py
@@ -2,6 +2,7 @@
 import enum
 import ipaddress
 import os
+import re
 import typing
 import uuid
 from base64 import encodebytes
@@ -856,3 +857,9 @@ def pack_pathlike(spec: ValueSpec) -> Optional[Expression]:
 def pack_enum(spec: ValueSpec) -> Optional[Expression]:
     if issubclass(spec.origin_type, enum.Enum):
         return f"{spec.expression}.value"
+
+
+@register
+def pack_pattern(spec: ValueSpec) -> Optional[Expression]:
+    if spec.origin_type in (typing.Pattern, re.Pattern):
+        return f"{spec.expression}.pattern"
diff --git a/mashumaro/core/meta/types/unpack.py b/mashumaro/core/meta/types/unpack.py
index 43b8d8d4..a9f589e1 100644
--- a/mashumaro/core/meta/types/unpack.py
+++ b/mashumaro/core/meta/types/unpack.py
@@ -5,6 +5,7 @@
 import ipaddress
 import os
 import pathlib
+import re
 import types
 import typing
 import uuid
@@ -1275,3 +1276,11 @@ def unpack_enum(spec: ValueSpec) -> Optional[Expression]:
     if issubclass(spec.origin_type, enum.Enum):
         field_type = spec.builder.get_type_name_identifier(spec.origin_type)
         return f"{field_type}({spec.expression})"
+
+
+@register
+def unpack_pattern(spec: ValueSpec) -> Optional[Expression]:
+    if spec.origin_type in (typing.Pattern, re.Pattern):
+        method = "__re_compile"
+        spec.builder.ensure_object_imported(re.compile, method)
+        return f"{method}({spec.expression})"


Test patch:
diff --git a/tests/test_data_types.py b/tests/test_data_types.py
index 4c82f8c0..08163431 100644
--- a/tests/test_data_types.py
+++ b/tests/test_data_types.py
@@ -4,6 +4,7 @@
 import fractions
 import ipaddress
 import os
+import re
 import uuid
 from dataclasses import InitVar, dataclass, field
 from datetime import date, datetime, time, timedelta, timezone
@@ -175,6 +176,8 @@ class Fixture:
     GENERIC_SERIALIZABLE_LIST_INT = GenericSerializableList([1, 2, 3])
     GENERIC_SERIALIZABLE_LIST_STR = GenericSerializableList(["a", "b", "c"])
     LITERAL_STRING = "foo"
+    PATTERN_STR = re.compile("[a-z]+")
+    PATTERN_BYTES = re.compile(b"[a-z]+")
 
 
 inner_values = [
@@ -254,6 +257,7 @@ class Fixture:
     ),
     (MyDatetimeNewType, Fixture.DATETIME, Fixture.DATETIME_STR),
     (LiteralString, Fixture.LITERAL_STRING, Fixture.LITERAL_STRING),
+    (re.Pattern, Fixture.PATTERN_STR, Fixture.PATTERN_STR.pattern),
 ]
 
 if os.name == "posix":
@@ -333,6 +337,16 @@ class Fixture:
             (collections.abc.Sequence, Fixture.LIST, Fixture.LIST),
             (collections.abc.MutableSequence[int], Fixture.LIST, Fixture.LIST),
             (collections.abc.MutableSequence, Fixture.LIST, Fixture.LIST),
+            (
+                re.Pattern[str],
+                Fixture.PATTERN_STR,
+                Fixture.PATTERN_STR.pattern,
+            ),
+            (
+                re.Pattern[bytes],
+                Fixture.PATTERN_BYTES,
+                Fixture.PATTERN_BYTES.pattern,
+            ),
         ]
     )