Repository: Fatal1ty/mashumaro

Issue:
Inconsistent Application of serialization_strategy
* mashumaro version: 3.2 and 3.3
* Python version: 3.10
* Operating System: macOS

### Description

There is an apparent regression in serialization behavior when the serialization_strategy object is being used and there are multiple properties of the same type on the class being serialized. It worked as I expected in 3.1.1, but fails in 3.2 and 3.3.

If the existing unit test `test_config.test_serialization_strategy` is modified to include a third property called `c` of type `str`, it will fail to properly deserialize `c`. Here's what the modified test looks like in full:

```
def test_serialization_strategy():
    class TestSerializationStrategy(SerializationStrategy):
        def serialize(self, value):
            return [value]

        def deserialize(self, value):
            return value[0]

    @dataclass
    class DataClass(DataClassDictMixin):
        a: int
        b: str
        c: str

        class Config(BaseConfig):
            serialization_strategy = {
                int: TestSerializationStrategy(),
                str: {
                    "serialize": lambda v: [v],
                    "deserialize": lambda v: v[0],
                },
            }

    instance = DataClass(a=123, b="abc", c="abc")
    assert DataClass.from_dict({"a": [123], "b": ["abc"], "c": ["abc"]}) == instance
    assert instance.to_dict() == {"a": [123], "b": ["abc"], "c": ["abc"]}
```

It appears to fail because the custom serialize/deserialize methods are called for b, but not for c.

```AssertionError: assert test_serialization_strategy.<locals>.DataClass(a=123, b='abc', c=['abc']) == test_serialization_strategy.<locals>.DataClass(a=123, b='abc', c='abc')```

Comments:

Patch:
diff --git a/mashumaro/config.py b/mashumaro/config.py
index 719e249..6c8bad4 100644
--- a/mashumaro/config.py
+++ b/mashumaro/config.py
@@ -10,6 +10,15 @@ else:
     from typing_extensions import Literal  # type: ignore
 
 
+__all__ = [
+    "BaseConfig",
+    "TO_DICT_ADD_BY_ALIAS_FLAG",
+    "TO_DICT_ADD_OMIT_NONE_FLAG",
+    "ADD_DIALECT_SUPPORT",
+    "SerializationStrategyValueType",
+]
+
+
 TO_DICT_ADD_BY_ALIAS_FLAG = "TO_DICT_ADD_BY_ALIAS_FLAG"
 TO_DICT_ADD_OMIT_NONE_FLAG = "TO_DICT_ADD_OMIT_NONE_FLAG"
 ADD_DIALECT_SUPPORT = "ADD_DIALECT_SUPPORT"
@@ -38,12 +47,3 @@ class BaseConfig:
     dialect: Optional[Type[Dialect]] = None
     omit_none: Union[bool, Literal[Sentinel.MISSING]] = Sentinel.MISSING
     orjson_options: Optional[int] = 0
-
-
-__all__ = [
-    "BaseConfig",
-    "TO_DICT_ADD_BY_ALIAS_FLAG",
-    "TO_DICT_ADD_OMIT_NONE_FLAG",
-    "ADD_DIALECT_SUPPORT",
-    "SerializationStrategyValueType",
-]
diff --git a/mashumaro/core/meta/code/builder.py b/mashumaro/core/meta/code/builder.py
index 453da7f..dde2889 100644
--- a/mashumaro/core/meta/code/builder.py
+++ b/mashumaro/core/meta/code/builder.py
@@ -1,6 +1,5 @@
 import importlib
 import inspect
-import sys
 import types
 import typing
 from contextlib import contextmanager
@@ -115,12 +114,8 @@ class CodeBuilder:
         self, recursive: bool = True
     ) -> typing.Dict[str, typing.Any]:
         fields = {}
-        globalns = sys.modules[self.cls.__module__].__dict__.copy()
-        globalns[self.cls.__name__] = self.cls
         try:
-            field_type_hints = typing.get_type_hints(
-                self.cls, globalns, self.cls.__dict__  # type: ignore
-            )
+            field_type_hints = typing.get_type_hints(self.cls)
         except NameError as e:
             name = get_name_error_name(e)
             raise UnresolvedTypeReferenceError(self.cls, name) from None
@@ -899,7 +894,6 @@ class CodeBuilder:
         yield metadata.get("serialization_strategy")
         yield from self.__iter_serialization_strategies(ftype)
 
-    @lru_cache()
     @typing.no_type_check
     def __iter_serialization_strategies(
         self, ftype: typing.Type
diff --git a/mashumaro/dialect.py b/mashumaro/dialect.py
index e6aba5f..b3ec3f0 100644
--- a/mashumaro/dialect.py
+++ b/mashumaro/dialect.py
@@ -5,6 +5,9 @@ from typing_extensions import Literal
 from mashumaro.core.const import Sentinel
 from mashumaro.types import SerializationStrategy
 
+__all__ = ["Dialect"]
+
+
 SerializationStrategyValueType = Union[
     SerializationStrategy, Dict[str, Union[str, Callable]]
 ]
@@ -13,6 +16,3 @@ SerializationStrategyValueType = Union[
 class Dialect:
     serialization_strategy: Dict[Any, SerializationStrategyValueType] = {}
     omit_none: Union[bool, Literal[Sentinel.MISSING]] = Sentinel.MISSING
-
-
-__all__ = ["Dialect"]
diff --git a/mashumaro/helper.py b/mashumaro/helper.py
index 96c9fec..f21f7fa 100644
--- a/mashumaro/helper.py
+++ b/mashumaro/helper.py
@@ -4,6 +4,12 @@ from typing_extensions import Literal
 
 from mashumaro.types import SerializationStrategy
 
+__all__ = [
+    "field_options",
+    "pass_through",
+]
+
+
 NamedTupleDeserializationEngine = Literal["as_dict", "as_list"]
 DateTimeDeserializationEngine = Literal["ciso8601", "pendulum"]
 AnyDeserializationEngine = Literal[
@@ -47,6 +53,3 @@ class _PassThrough(SerializationStrategy):
 
 
 pass_through = _PassThrough()
-
-
-__all__ = ["field_options", "pass_through"]
diff --git a/mashumaro/types.py b/mashumaro/types.py
index b1cab34..6a45eeb 100644
--- a/mashumaro/types.py
+++ b/mashumaro/types.py
@@ -5,6 +5,13 @@ from typing_extensions import Literal
 
 from mashumaro.core.const import Sentinel
 
+__all__ = [
+    "SerializableType",
+    "GenericSerializableType",
+    "SerializationStrategy",
+    "RoundedDecimal",
+]
+
 
 class SerializableType:
     __use_annotations__ = False
@@ -65,11 +72,3 @@ class RoundedDecimal(SerializationStrategy):
 
     def deserialize(self, value: str) -> decimal.Decimal:
         return decimal.Decimal(str(value))
-
-
-__all__ = [
-    "SerializableType",
-    "GenericSerializableType",
-    "SerializationStrategy",
-    "RoundedDecimal",
-]


Test patch:
diff --git a/tests/test_config.py b/tests/test_config.py
index 17f0abb..c7ffa68 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -142,6 +142,7 @@ def test_serialization_strategy():
     class DataClass(DataClassDictMixin):
         a: int
         b: str
+        c: int
 
         class Config(BaseConfig):
             serialization_strategy = {
@@ -152,9 +153,9 @@ def test_serialization_strategy():
                 },
             }
 
-    instance = DataClass(a=123, b="abc")
-    assert DataClass.from_dict({"a": [123], "b": ["abc"]}) == instance
-    assert instance.to_dict() == {"a": [123], "b": ["abc"]}
+    instance = DataClass(a=123, b="abc", c=123)
+    assert DataClass.from_dict({"a": [123], "b": ["abc"], "c": [123]}) == instance
+    assert instance.to_dict() == {"a": [123], "b": ["abc"], "c": [123]}
 
 
 def test_named_tuple_as_dict():
diff --git a/tests/test_forward_refs/__init__.py b/tests/test_forward_refs/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/test_forward_refs/test_baz.py b/tests/test_forward_refs/test_baz.py
new file mode 100644
index 0000000..495441c
--- /dev/null
+++ b/tests/test_forward_refs/test_baz.py
@@ -0,0 +1,15 @@
+from __future__ import annotations
+
+from dataclasses import dataclass
+
+from .test_foobar import Bar, Foo
+
+
+@dataclass
+class Baz(Foo[int]):
+    pass
+
+
+def test_class_with_base_in_another_module():
+    assert Bar(x=1).to_json() == '{"x": 1}'
+    assert Baz(x=1).to_json() == '{"x": 1}'
diff --git a/tests/test_forward_refs/test_foobar.py b/tests/test_forward_refs/test_foobar.py
new file mode 100644
index 0000000..effbe3a
--- /dev/null
+++ b/tests/test_forward_refs/test_foobar.py
@@ -0,0 +1,18 @@
+from __future__ import annotations
+
+from dataclasses import dataclass
+from typing import Generic, TypeVar
+
+from mashumaro.mixins.json import DataClassJSONMixin
+
+T = TypeVar("T")
+
+
+@dataclass
+class Foo(Generic[T], DataClassJSONMixin):
+    x: T
+
+
+@dataclass
+class Bar(Foo[int]):
+    pass