Repository: strawberry-graphql/strawberry

Issue:
Schema's `scalar_overrides` type annotation.
Following scalars revamping, `Schema` signature appears outdated.

Applying mypy on [example](https://strawberry.rocks/docs/types/scalars#overriding-built-in-scalars):
```python
from datetime import datetime, timezone
import strawberry

# Define your custom scalar
EpochDateTime = strawberry.scalar(
    datetime,
    serialize=lambda value: int(value.timestamp()),
    parse_value=lambda value: datetime.fromtimestamp(int(value), timezone.utc),
)

@strawberry.type
class Query:
    @strawberry.field
    def current_time(self) -> datetime:
        return datetime.now()

schema = strawberry.Schema(
  Query,
  scalar_overrides={
    datetime: EpochDateTime,
  }
)
result = schema.execute_sync("{ currentTime }")
assert result.data == {"currentTime": 1628683200}
```
yields

```bash
example.py:20: error: Dict entry 0 has incompatible type "Type[datetime]": "Type[datetime]"; expected "object": "Union[ScalarWrapper, ScalarDefinition]"  [dict-item]
Found 1 error in 1 file (checked 1 source file)
```


Discussion:
i can take a look at this, encountered it too. think it is because dict is invariant, and we should use Mapping instead which is covariant?
I'd say that since scalars are now cast to their own type, the value part of the dict `Union[ScalarWrapper, ScalarDefinition]` is outdated.

Resolving patch:
diff --git a/strawberry/federation/schema.py b/strawberry/federation/schema.py
--- a/strawberry/federation/schema.py
+++ b/strawberry/federation/schema.py
@@ -42,7 +42,7 @@ def __init__(
         execution_context_class: Optional[Type[GraphQLExecutionContext]] = None,
         config: Optional[StrawberryConfig] = None,
         scalar_overrides: Optional[
-            Dict[object, Union[ScalarWrapper, ScalarDefinition]]
+            Dict[object, Union[Type, ScalarWrapper, ScalarDefinition]]
         ] = None,
         schema_directives: Iterable[object] = (),
         enable_federation_2: bool = False,
diff --git a/strawberry/schema/schema.py b/strawberry/schema/schema.py
--- a/strawberry/schema/schema.py
+++ b/strawberry/schema/schema.py
@@ -1,5 +1,5 @@
 from functools import lru_cache
-from typing import Any, Dict, Iterable, List, Optional, Type, Union
+from typing import Any, Dict, Iterable, List, Optional, Type, Union, cast
 
 from graphql import (
     ExecutionContext as GraphQLExecutionContext,
@@ -56,7 +56,7 @@ def __init__(
         execution_context_class: Optional[Type[GraphQLExecutionContext]] = None,
         config: Optional[StrawberryConfig] = None,
         scalar_overrides: Optional[
-            Dict[object, Union[ScalarWrapper, ScalarDefinition]]
+            Dict[object, Union[Type, ScalarWrapper, ScalarDefinition]]
         ] = None,
         schema_directives: Iterable[object] = (),
     ):
@@ -68,11 +68,14 @@ def __init__(
         self.execution_context_class = execution_context_class
         self.config = config or StrawberryConfig()
 
-        scalar_registry: Dict[object, Union[ScalarWrapper, ScalarDefinition]] = {
-            **DEFAULT_SCALAR_REGISTRY
-        }
+        SCALAR_OVERRIDES_DICT_TYPE = Dict[
+            object, Union[ScalarWrapper, ScalarDefinition]
+        ]
+
+        scalar_registry: SCALAR_OVERRIDES_DICT_TYPE = {**DEFAULT_SCALAR_REGISTRY}
         if scalar_overrides:
-            scalar_registry.update(scalar_overrides)
+            # TODO: check that the overrides are valid
+            scalar_registry.update(cast(SCALAR_OVERRIDES_DICT_TYPE, scalar_overrides))
 
         self.schema_converter = GraphQLCoreConverter(self.config, scalar_registry)
         self.directives = directives
diff --git a/strawberry/schema/schema_converter.py b/strawberry/schema/schema_converter.py
--- a/strawberry/schema/schema_converter.py
+++ b/strawberry/schema/schema_converter.py
@@ -524,6 +524,7 @@ def from_scalar(self, scalar: Type) -> GraphQLScalarType:
 
         if scalar in self.scalar_registry:
             _scalar_definition = self.scalar_registry[scalar]
+            # TODO: check why we need the cast and we are not trying with getattr first
             if isinstance(_scalar_definition, ScalarWrapper):
                 scalar_definition = _scalar_definition._scalar_definition
             else:


Test patch:
diff --git a/tests/mypy/test_scalar.yml b/tests/mypy/test_scalar.yml
--- a/tests/mypy/test_scalar.yml
+++ b/tests/mypy/test_scalar.yml
@@ -53,7 +53,6 @@
     main:11: note: Revealed type is "builtins.str"
     main:12: note: Revealed type is "builtins.int"
 
-
 - case: test_scalar_as_function_new_type
   main: |
     from typing import NewType
@@ -70,3 +69,25 @@
   out: |
     main:10: note: Revealed type is "Any"
     main:11: note: Revealed type is "Any"
+
+- case: test_we_can_pass_scalar_overrides_to_schema
+  main: |
+    import strawberry
+    from datetime import datetime, timezone
+
+    EpochDateTime = strawberry.scalar(
+        datetime,
+    )
+
+    @strawberry.type
+    class Query:
+        a: datetime
+
+    schema = strawberry.Schema(query=Query, scalar_overrides={
+        datetime: EpochDateTime,
+    })
+
+    reveal_type(EpochDateTime)
+
+  out: |
+    main:16: note: Revealed type is "def (year: builtins.int, month: builtins.int, day: builtins.int, hour: builtins.int =, minute: builtins.int =, second: builtins.int =, microsecond: builtins.int =, tzinfo: Union[datetime.tzinfo, None] =, *, fold: builtins.int =) -> datetime.datetime"
diff --git a/tests/pyright/test_scalars.py b/tests/pyright/test_scalars.py
--- a/tests/pyright/test_scalars.py
+++ b/tests/pyright/test_scalars.py
@@ -71,3 +71,37 @@ def test_pyright():
             column=13,
         ),
     ]
+
+
+CODE_SCHEMA_OVERRIDES = """
+import strawberry
+from datetime import datetime, timezone
+
+EpochDateTime = strawberry.scalar(
+    datetime,
+)
+
+@strawberry.type
+class Query:
+    a: datetime
+
+schema = strawberry.Schema(query=Query, scalar_overrides={
+    datetime: EpochDateTime,
+})
+
+reveal_type(EpochDateTime)
+"""
+
+
+def test_schema_overrides():
+    # TODO: change strict to true when we improve type hints for scalar
+    results = run_pyright(CODE_SCHEMA_OVERRIDES, strict=False)
+
+    assert results == [
+        Result(
+            type="information",
+            message='Type of "EpochDateTime" is "Type[datetime]"',
+            line=17,
+            column=13,
+        ),
+    ]