Skip to content

Commit 8dd9417

Browse files
Update test_node Types (#1464)
* Update test_node types Signed-off-by: Michael Carlstrom <[email protected]> * don't attempt to use typevar defaults Signed-off-by: Michael Carlstrom <[email protected]> --------- Signed-off-by: Michael Carlstrom <[email protected]>
1 parent 684bb13 commit 8dd9417

24 files changed

+269
-100
lines changed

rclpy/docs/source/conf.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#
2929
import os
3030
import sys
31+
from typing import Dict
32+
from typing import List
3133
sys.path.insert(0, os.path.abspath('.'))
3234

3335

@@ -82,7 +84,7 @@
8284
# List of patterns, relative to source directory, that match files and
8385
# directories to ignore when looking for source files.
8486
# This pattern also affects html_static_path and html_extra_path.
85-
exclude_patterns = []
87+
exclude_patterns: List[str] = []
8688

8789
# The name of the Pygments (syntax highlighting) style to use.
8890
pygments_style = None
@@ -104,7 +106,7 @@
104106
# Add any paths that contain custom static files (such as style sheets) here,
105107
# relative to this directory. They are copied after the builtin static files,
106108
# so a file named "default.css" will overwrite the builtin "default.css".
107-
html_static_path = []
109+
html_static_path: List[str] = []
108110

109111
# Custom sidebar templates, must be a dictionary that maps document names
110112
# to template names.
@@ -125,7 +127,7 @@
125127

126128
# -- Options for LaTeX output ------------------------------------------------
127129

128-
latex_elements = {
130+
latex_elements: Dict[str, str] = {
129131
# The paper size ('letterpaper' or 'a4paper').
130132
#
131133
# 'papersize': 'letterpaper',

rclpy/rclpy/guard_condition.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,23 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from typing import Callable, Optional
15+
from typing import Callable
16+
from typing import Coroutine
17+
from typing import Optional
18+
from typing import Union
1619

1720
from rclpy.callback_groups import CallbackGroup
1821
from rclpy.context import Context
1922
from rclpy.impl.implementation_singleton import rclpy_implementation as _rclpy
2023
from rclpy.utilities import get_default_context
24+
from typing_extensions import TypeAlias
25+
26+
GuardConditionCallbackType: TypeAlias = Callable[[], Union[Coroutine[None, None, None], None]]
2127

2228

2329
class GuardCondition:
2430

25-
def __init__(self, callback: Optional[Callable[[], None]],
31+
def __init__(self, callback: Optional[GuardConditionCallbackType],
2632
callback_group: Optional[CallbackGroup],
2733
context: Optional[Context] = None) -> None:
2834
"""

rclpy/rclpy/node.py

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from typing import Final
2323
from typing import Iterator
2424
from typing import List
25+
from typing import Literal
2526
from typing import Optional
2627
from typing import overload
2728
from typing import Sequence
@@ -66,6 +67,7 @@
6667
from rclpy.executors import Executor
6768
from rclpy.expand_topic_name import expand_topic_name
6869
from rclpy.guard_condition import GuardCondition
70+
from rclpy.guard_condition import GuardConditionCallbackType
6971
from rclpy.impl.implementation_singleton import rclpy_implementation as _rclpy
7072
from rclpy.impl.rcutils_logger import RcutilsLogger
7173
from rclpy.logging import get_logger
@@ -81,11 +83,13 @@
8183
from rclpy.qos_overriding_options import _declare_qos_parameters
8284
from rclpy.qos_overriding_options import QoSOverridingOptions
8385
from rclpy.service import Service
84-
from rclpy.subscription import MessageInfo
86+
from rclpy.subscription import GenericSubscriptionCallback
8587
from rclpy.subscription import Subscription
88+
from rclpy.subscription import SubscriptionCallbackUnion
8689
from rclpy.time_source import TimeSource
8790
from rclpy.timer import Rate
88-
from rclpy.timer import Timer, TimerInfo
91+
from rclpy.timer import Timer
92+
from rclpy.timer import TimerCallbackType
8993
from rclpy.topic_endpoint_info import TopicEndpointInfo
9094
from rclpy.type_description_service import TypeDescriptionService
9195
from rclpy.type_support import check_is_valid_msg_type
@@ -117,6 +121,8 @@
117121
# `Node.get_*_names_and_types_by_node` methods may raise this error.
118122
NodeNameNonExistentError: TypeAlias = _rclpy.NodeNameNonExistentError
119123

124+
ParameterInput: TypeAlias = Union[AllowableParameterValue, Parameter.Type, ParameterValue]
125+
120126

121127
class Node:
122128
"""
@@ -381,8 +387,7 @@ def get_logger(self) -> RcutilsLogger:
381387
return self._logger
382388

383389
@overload
384-
def declare_parameter(self, name: str, value: Union[AllowableParameterValueT,
385-
Parameter.Type, ParameterValue],
390+
def declare_parameter(self, name: str, value: AllowableParameterValueT,
386391
descriptor: Optional[ParameterDescriptor] = None,
387392
ignore_override: bool = False
388393
) -> Parameter[AllowableParameterValueT]: ...
@@ -421,36 +426,19 @@ def declare_parameter(
421426
"""
422427
if value is None and descriptor is None:
423428
# Temporal patch so we get deprecation warning if only a name is provided.
424-
args: Union[Tuple[str], Tuple[str, Union[AllowableParameterValue,
425-
Parameter.Type, ParameterValue],
426-
ParameterDescriptor]] = (name, )
429+
args: Union[Tuple[str], Tuple[str, ParameterInput, ParameterDescriptor]] = (name, )
427430
else:
428431
descriptor = ParameterDescriptor() if descriptor is None else descriptor
429432
args = (name, value, descriptor)
430433
return self.declare_parameters('', [args], ignore_override)[0]
431434

432-
ParameterInput: TypeAlias = Union[AllowableParameterValue, Parameter.Type, ParameterValue]
433-
434-
@overload
435435
def declare_parameters(
436436
self,
437437
namespace: str,
438438
parameters: Sequence[Union[
439-
Tuple[str, ParameterInput],
440-
Tuple[str, ParameterInput, ParameterDescriptor],
441-
]],
442-
ignore_override: bool = False
443-
) -> List[Parameter[Any]]: ...
444-
445-
def declare_parameters(
446-
self,
447-
namespace: str,
448-
parameters: Union[Sequence[Union[
439+
Tuple[str],
449440
Tuple[str, ParameterInput],
450441
Tuple[str, ParameterInput, ParameterDescriptor]]],
451-
Sequence[Union[
452-
Tuple[str, ParameterInput],
453-
Tuple[str, ParameterInput, ParameterDescriptor]]]],
454442
ignore_override: bool = False
455443
) -> List[Parameter[Any]]:
456444
"""
@@ -701,7 +689,7 @@ def get_parameter_type(self, name: str) -> Parameter.Type:
701689
and the parameter hadn't been declared beforehand.
702690
"""
703691
if self.has_parameter(name):
704-
return self._parameters[name].type_.value
692+
return self._parameters[name].type_
705693
elif self._allow_undeclared_parameters:
706694
return Parameter.Type.NOT_SET
707695
else:
@@ -1643,11 +1631,39 @@ def create_publisher(
16431631

16441632
return publisher
16451633

1634+
@overload
1635+
def create_subscription(
1636+
self,
1637+
msg_type: Type[MsgT],
1638+
topic: str,
1639+
callback: GenericSubscriptionCallback[bytes],
1640+
qos_profile: Union[QoSProfile, int],
1641+
*,
1642+
callback_group: Optional[CallbackGroup] = None,
1643+
event_callbacks: Optional[SubscriptionEventCallbacks] = None,
1644+
qos_overriding_options: Optional[QoSOverridingOptions] = None,
1645+
raw: Literal[True]
1646+
) -> Subscription[MsgT]: ...
1647+
1648+
@overload
1649+
def create_subscription(
1650+
self,
1651+
msg_type: Type[MsgT],
1652+
topic: str,
1653+
callback: GenericSubscriptionCallback[MsgT],
1654+
qos_profile: Union[QoSProfile, int],
1655+
*,
1656+
callback_group: Optional[CallbackGroup] = None,
1657+
event_callbacks: Optional[SubscriptionEventCallbacks] = None,
1658+
qos_overriding_options: Optional[QoSOverridingOptions] = None,
1659+
raw: bool = False
1660+
) -> Subscription[MsgT]: ...
1661+
16461662
def create_subscription(
16471663
self,
16481664
msg_type: Type[MsgT],
16491665
topic: str,
1650-
callback: Union[Callable[[MsgT], None], Callable[[MsgT, MessageInfo], None]],
1666+
callback: SubscriptionCallbackUnion[MsgT],
16511667
qos_profile: Union[QoSProfile, int],
16521668
*,
16531669
callback_group: Optional[CallbackGroup] = None,
@@ -1810,7 +1826,7 @@ def create_service(
18101826
def create_timer(
18111827
self,
18121828
timer_period_sec: float,
1813-
callback: Union[Callable[[], None], Callable[[TimerInfo], None], None],
1829+
callback: TimerCallbackType,
18141830
callback_group: Optional[CallbackGroup] = None,
18151831
clock: Optional[Clock] = None,
18161832
autostart: bool = True,
@@ -1847,7 +1863,7 @@ def create_timer(
18471863

18481864
def create_guard_condition(
18491865
self,
1850-
callback: Callable[[], None],
1866+
callback: GuardConditionCallbackType,
18511867
callback_group: Optional[CallbackGroup] = None
18521868
) -> GuardCondition:
18531869
"""

rclpy/rclpy/subscription.py

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,39 +16,100 @@
1616
from enum import Enum
1717
import inspect
1818
from types import TracebackType
19-
from typing import Callable, Generic, Optional, Type, TypedDict, TypeVar, Union
19+
from typing import Callable
20+
from typing import Generic
21+
from typing import Literal
22+
from typing import Optional
23+
from typing import overload
24+
from typing import Type
25+
from typing import TypedDict
26+
from typing import TypeVar
27+
from typing import Union
28+
2029

2130
from rclpy.callback_groups import CallbackGroup
2231
from rclpy.event_handler import SubscriptionEventCallbacks
2332
from rclpy.impl.implementation_singleton import rclpy_implementation as _rclpy
2433
from rclpy.qos import QoSProfile
2534
from rclpy.type_support import MsgT
35+
from typing_extensions import TypeAlias
36+
37+
38+
class PublisherGID(TypedDict):
39+
implementation_identifier: str
40+
data: bytes
2641

2742

2843
class MessageInfo(TypedDict):
2944
source_timestamp: int
3045
received_timestamp: int
3146
publication_sequence_number: Optional[int]
3247
reception_sequence_number: Optional[int]
33-
publisher_gid: Optional[dict]
48+
publisher_gid: Optional[PublisherGID]
3449

3550

3651
# Left to support Legacy TypeVars.
3752
MsgType = TypeVar('MsgType')
3853

54+
# Can be redone with TypeVar(default=MsgT) when either typing-extensions4.11.0+ or python3.13+
55+
T = TypeVar('T')
56+
GenericSubscriptionCallback: TypeAlias = Union[Callable[[T], None],
57+
Callable[[T, MessageInfo], None]]
58+
SubscriptionCallbackUnion: TypeAlias = Union[GenericSubscriptionCallback[MsgT],
59+
GenericSubscriptionCallback[bytes]]
60+
3961

4062
class Subscription(Generic[MsgT]):
4163

4264
class CallbackType(Enum):
4365
MessageOnly = 0
4466
WithMessageInfo = 1
4567

68+
@overload
69+
def __init__(
70+
self,
71+
subscription_impl: '_rclpy.Subscription[MsgT]',
72+
msg_type: Type[MsgT],
73+
topic: str,
74+
callback: GenericSubscriptionCallback[bytes],
75+
callback_group: CallbackGroup,
76+
qos_profile: QoSProfile,
77+
raw: Literal[True],
78+
event_callbacks: SubscriptionEventCallbacks,
79+
) -> None: ...
80+
81+
@overload
82+
def __init__(
83+
self,
84+
subscription_impl: '_rclpy.Subscription[MsgT]',
85+
msg_type: Type[MsgT],
86+
topic: str,
87+
callback: GenericSubscriptionCallback[MsgT],
88+
callback_group: CallbackGroup,
89+
qos_profile: QoSProfile,
90+
raw: Literal[False],
91+
event_callbacks: SubscriptionEventCallbacks,
92+
) -> None: ...
93+
94+
@overload
95+
def __init__(
96+
self,
97+
subscription_impl: '_rclpy.Subscription[MsgT]',
98+
msg_type: Type[MsgT],
99+
topic: str,
100+
callback: SubscriptionCallbackUnion[MsgT],
101+
callback_group: CallbackGroup,
102+
qos_profile: QoSProfile,
103+
raw: bool,
104+
event_callbacks: SubscriptionEventCallbacks,
105+
) -> None: ...
106+
46107
def __init__(
47108
self,
48109
subscription_impl: '_rclpy.Subscription[MsgT]',
49110
msg_type: Type[MsgT],
50111
topic: str,
51-
callback: Union[Callable[[MsgT], None], Callable[[MsgT, MessageInfo], None]],
112+
callback: SubscriptionCallbackUnion[MsgT],
52113
callback_group: CallbackGroup,
53114
qos_profile: QoSProfile,
54115
raw: bool,
@@ -111,12 +172,11 @@ def topic_name(self) -> str:
111172
return self.__subscription.get_topic_name()
112173

113174
@property
114-
def callback(self) -> Union[Callable[[MsgT], None], Callable[[MsgT, MessageInfo], None]]:
175+
def callback(self) -> SubscriptionCallbackUnion[MsgT]:
115176
return self._callback
116177

117178
@callback.setter
118-
def callback(self, value: Union[Callable[[MsgT], None],
119-
Callable[[MsgT, MessageInfo], None]]) -> None:
179+
def callback(self, value: SubscriptionCallbackUnion[MsgT]) -> None:
120180
self._callback = value
121181
self._callback_type = Subscription.CallbackType.MessageOnly
122182
try:

rclpy/rclpy/timer.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from types import TracebackType
1818
from typing import Callable
19+
from typing import Coroutine
1920
from typing import Optional
2021
from typing import Type
2122
from typing import Union
@@ -28,6 +29,7 @@
2829
from rclpy.impl.implementation_singleton import rclpy_implementation as _rclpy
2930
from rclpy.time import Time
3031
from rclpy.utilities import get_default_context
32+
from typing_extensions import TypeAlias
3133

3234

3335
class TimerInfo:
@@ -63,11 +65,17 @@ def actual_call_time(self) -> Time:
6365
return self._actual_call_time
6466

6567

68+
TimerCallbackType: TypeAlias = Union[Callable[[], None],
69+
Callable[[TimerInfo], None],
70+
Callable[[], Coroutine[None, None, None]],
71+
None]
72+
73+
6674
class Timer:
6775

6876
def __init__(
6977
self,
70-
callback: Union[Callable[[], None], Callable[[TimerInfo], None], None],
78+
callback: TimerCallbackType,
7179
callback_group: Optional[CallbackGroup],
7280
timer_period_ns: int,
7381
clock: Clock,

rclpy/test/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
import test_rclpy # noqa
2727

2828

29-
def _custom_import(name: str, package: Optional[str]) -> ModuleType:
29+
def _custom_import(name: str, package: Optional[str] = None) -> ModuleType:
3030
# Since Python 3.8, on Windows we should ensure DLL directories are explicitly added
3131
# to the search path.
3232
# See https://docs.python.org/3/whatsnew/3.8.html#bpo-36085-whatsnew

0 commit comments

Comments
 (0)