Skip to content

Commit 8297e54

Browse files
authored
Merge pull request #3259 from plotly/update-pyright
Improve typing.
2 parents 7af76ee + 7ec55b9 commit 8297e54

File tree

8 files changed

+51
-22
lines changed

8 files changed

+51
-22
lines changed

dash/_callback.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def callback(
7777
cache_ignore_triggered=True,
7878
on_error: Optional[Callable[[Exception], Any]] = None,
7979
**_kwargs,
80-
):
80+
) -> Callable[..., Any]:
8181
"""
8282
Normally used as a decorator, `@dash.callback` provides a server-side
8383
callback relating the values of one or more `Output` items to one or

dash/dash.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1269,7 +1269,7 @@ def clientside_callback(self, clientside_function, *args, **kwargs):
12691269
**kwargs,
12701270
)
12711271

1272-
def callback(self, *_args, **_kwargs):
1272+
def callback(self, *_args, **_kwargs) -> Callable[..., Any]:
12731273
"""
12741274
Normally used as a decorator, `@app.callback` provides a server-side
12751275
callback relating the values of one or more `Output` items to one or

dash/dependencies.py

+24-9
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1+
from typing import Union, Sequence
2+
13
from dash.development.base_component import Component
24

35
from ._validate import validate_callback
46
from ._grouping import flatten_grouping, make_grouping_by_index
57
from ._utils import stringify_id
68

79

10+
ComponentIdType = Union[str, Component, dict]
11+
12+
813
class _Wildcard: # pylint: disable=too-few-public-methods
9-
def __init__(self, name):
14+
def __init__(self, name: str):
1015
self._name = name
1116

1217
def __str__(self):
@@ -15,7 +20,7 @@ def __str__(self):
1520
def __repr__(self):
1621
return f"<{self}>"
1722

18-
def to_json(self):
23+
def to_json(self) -> str:
1924
# used in serializing wildcards - arrays are not allowed as
2025
# id values, so make the wildcards look like length-1 arrays.
2126
return f'["{self._name}"]'
@@ -27,7 +32,12 @@ def to_json(self):
2732

2833

2934
class DashDependency: # pylint: disable=too-few-public-methods
30-
def __init__(self, component_id, component_property):
35+
component_id: ComponentIdType
36+
allow_duplicate: bool
37+
component_property: str
38+
allowed_wildcards: Sequence[_Wildcard]
39+
40+
def __init__(self, component_id: ComponentIdType, component_property: str):
3141

3242
if isinstance(component_id, Component):
3343
self.component_id = component_id._set_random_id()
@@ -43,10 +53,10 @@ def __str__(self):
4353
def __repr__(self):
4454
return f"<{self.__class__.__name__} `{self}`>"
4555

46-
def component_id_str(self):
56+
def component_id_str(self) -> str:
4757
return stringify_id(self.component_id)
4858

49-
def to_dict(self):
59+
def to_dict(self) -> dict:
5060
return {"id": self.component_id_str(), "property": self.component_property}
5161

5262
def __eq__(self, other):
@@ -61,7 +71,7 @@ def __eq__(self, other):
6171
and self._id_matches(other)
6272
)
6373

64-
def _id_matches(self, other):
74+
def _id_matches(self, other) -> bool:
6575
my_id = self.component_id
6676
other_id = other.component_id
6777
self_dict = isinstance(my_id, dict)
@@ -96,7 +106,7 @@ def _id_matches(self, other):
96106
def __hash__(self):
97107
return hash(str(self))
98108

99-
def has_wildcard(self):
109+
def has_wildcard(self) -> bool:
100110
"""
101111
Return true if id contains a wildcard (MATCH, ALL, or ALLSMALLER)
102112
"""
@@ -112,7 +122,12 @@ class Output(DashDependency): # pylint: disable=too-few-public-methods
112122

113123
allowed_wildcards = (MATCH, ALL)
114124

115-
def __init__(self, component_id, component_property, allow_duplicate=False):
125+
def __init__(
126+
self,
127+
component_id: ComponentIdType,
128+
component_property: str,
129+
allow_duplicate: bool = False,
130+
):
116131
super().__init__(component_id, component_property)
117132
self.allow_duplicate = allow_duplicate
118133

@@ -130,7 +145,7 @@ class State(DashDependency): # pylint: disable=too-few-public-methods
130145

131146

132147
class ClientsideFunction: # pylint: disable=too-few-public-methods
133-
def __init__(self, namespace=None, function_name=None):
148+
def __init__(self, namespace: str, function_name: str):
134149

135150
if namespace.startswith("_dashprivate_"):
136151
raise ValueError("Namespaces cannot start with '_dashprivate_'.")

dash/development/_py_components_generation.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import typing # noqa: F401
2525
import numbers # noqa: F401
2626
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
27-
from dash.development.base_component import Component, _explicitize_args
27+
from dash.development.base_component import Component
2828
try:
2929
from dash.development.base_component import ComponentType # noqa: F401
3030
except ImportError:
@@ -80,7 +80,8 @@ def generate_class_string(
8080
_namespace = '{namespace}'
8181
_type = '{typename}'
8282
{shapes}
83-
@_explicitize_args
83+
_explicitize_dash_init = True
84+
8485
def __init__(
8586
self,
8687
{default_argtext}

dash/development/base_component.py

+14-4
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,21 @@ class ComponentMeta(abc.ABCMeta):
5151

5252
# pylint: disable=arguments-differ
5353
def __new__(mcs, name, bases, attributes):
54-
component = abc.ABCMeta.__new__(mcs, name, bases, attributes)
5554
module = attributes["__module__"].split(".")[0]
55+
56+
if attributes.get("_explicitize_dash_init", False):
57+
# We only want to patch the new generated component without
58+
# the `@_explicitize_args` decorator for mypy support
59+
# See issue: https://github.com/plotly/dash/issues/3226
60+
attributes["__init__"] = _explicitize_args(attributes["__init__"])
61+
62+
_component = abc.ABCMeta.__new__(mcs, name, bases, attributes)
63+
5664
if name == "Component" or module == "builtins":
57-
# Don't do the base component
65+
# Don't add to the registry the base component
5866
# and the components loaded dynamically by load_component
5967
# as it doesn't have the namespace.
60-
return component
68+
return _component
6169

6270
_namespace = attributes.get("_namespace", module)
6371
ComponentRegistry.namespace_to_package[_namespace] = module
@@ -66,7 +74,7 @@ def __new__(mcs, name, bases, attributes):
6674
"_children_props"
6775
)
6876

69-
return component
77+
return _component
7078

7179

7280
def is_number(s):
@@ -435,6 +443,8 @@ def _validate_deprecation(self):
435443

436444
ComponentType = typing.TypeVar("ComponentType", bound=Component)
437445

446+
ComponentTemplate = typing.TypeVar("ComponentTemplate")
447+
438448

439449
# This wrapper adds an argument given to generated Component.__init__
440450
# with the actual given parameters by the user as a list of string.

requirements/ci.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ pyzmq==25.1.2
1818
xlrd>=2.0.1
1919
pytest-rerunfailures
2020
jupyterlab<4.0.0
21-
pyright==1.1.376;python_version>="3.7"
21+
pyright==1.1.398;python_version>="3.7"

tests/integration/test_typing.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -223,15 +223,17 @@ def assert_pyright_output(
223223
"obj={}",
224224
{
225225
"expected_status": 1,
226-
"expected_outputs": ['"dict[Any, Any]" is incompatible with "Obj"'],
226+
"expected_outputs": [
227+
'"dict[Any, Any]" cannot be assigned to parameter "obj" of type "Obj | None"'
228+
],
227229
},
228230
),
229231
(
230232
"obj={'value': 'a', 'label': 1}",
231233
{
232234
"expected_status": 1,
233235
"expected_outputs": [
234-
'"dict[str, str | int]" is incompatible with "Obj"'
236+
'"dict[str, str | int]" cannot be assigned to parameter "obj" of type "Obj | None"'
235237
],
236238
},
237239
),

tests/unit/development/metadata_test.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import typing # noqa: F401
44
import numbers # noqa: F401
55
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
6-
from dash.development.base_component import Component, _explicitize_args
6+
from dash.development.base_component import Component
77
try:
88
from dash.development.base_component import ComponentType # noqa: F401
99
except ImportError:
@@ -131,7 +131,8 @@ class Table(Component):
131131
}
132132
)
133133

134-
@_explicitize_args
134+
_explicitize_dash_init = True
135+
135136
def __init__(
136137
self,
137138
children: typing.Optional[typing.Union[str, int, float, ComponentType, typing.Sequence[typing.Union[str, int, float, ComponentType]]]] = None,

0 commit comments

Comments
 (0)