@@ -141,6 +141,17 @@ def decorator(f: Callable):
141
141
142
142
def _is_valid_samplesheet_parameter_type (parameter : inspect .Parameter ) -> bool :
143
143
"""Check if a workflow parameter is hinted with a valid type for a samplesheet LatchParameter.
144
+
145
+ Currently, a samplesheet LatchParameter must be defined as a list of dataclasses, or as an
146
+ `Optional` list of dataclasses when the parameter is part of a `ForkBranch`.
147
+
148
+ Args:
149
+ parameter: A parameter from the workflow function's signature.
150
+
151
+ Returns:
152
+ True if the parameter is annotated as a list of dataclasses, or as an `Optional` list of
153
+ dataclasses.
154
+ False otherwise.
144
155
"""
145
156
annotation = parameter .annotation
146
157
@@ -165,7 +176,7 @@ def _is_list_of_dataclasses_type(dtype: TypeAnnotation) -> bool:
165
176
False otherwise.
166
177
167
178
Raises:
168
- TypeError: If the input is not a `type` .
179
+ TypeError: If the input is not a valid `TypeAnnotation` type (see above) .
169
180
"""
170
181
if not isinstance (dtype , TYPE_ANNOTATION_TYPES ):
171
182
raise TypeError (f"Expected `type`, got { type (dtype )} : { dtype } " )
@@ -196,7 +207,7 @@ def _is_optional_type(dtype: TypeAnnotation) -> bool:
196
207
False otherwise.
197
208
198
209
Raises:
199
- TypeError: If the input is not a `type` .
210
+ TypeError: If the input is not a valid `TypeAnnotation` type (see above) .
200
211
"""
201
212
if not isinstance (dtype , TYPE_ANNOTATION_TYPES ):
202
213
raise TypeError (f"Expected `type`, got { type (dtype )} : { dtype } " )
@@ -223,7 +234,7 @@ def _unpack_optional_type(dtype: TypeAnnotation) -> type:
223
234
The type `T`.
224
235
225
236
Raises:
226
- TypeError: If the input is not a `type` .
237
+ TypeError: If the input is not a valid `TypeAnnotation` type (see above) .
227
238
ValueError: If the input type is not `Optional[T]`.
228
239
"""
229
240
if not isinstance (dtype , TYPE_ANNOTATION_TYPES ):
@@ -243,25 +254,27 @@ def _unpack_optional_type(dtype: TypeAnnotation) -> type:
243
254
return base_type
244
255
245
256
257
+ # NB: `inspect.Parameter.annotation` is typed as `Any`, so here we narrow the type.
246
258
def _is_type_annotation (annotation : Any ) -> TypeGuard [TypeAnnotation ]:
247
259
"""Check if the annotation on an `inspect.Parameter` instance is a type annotation.
248
260
249
261
If the corresponding parameter **did not** have a type annotation, `annotation` is set to the
250
- special class variable `Parameter.empty`.
251
-
252
- NB: `Parameter.empty` itself is a subclass of `type`
253
- Otherwise, the annotation is assumed to be a type.
262
+ special class variable `inspect.Parameter.empty`. Otherwise, the annotation should be a valid
263
+ type annotation.
254
264
255
265
Args:
256
266
annotation: The annotation on an `inspect.Parameter` instance.
257
267
258
268
Returns:
259
- True if the annotation is not `Parameter.empty`.
269
+ True if the type annotation is not `inspect. Parameter.empty`.
260
270
False otherwise.
261
271
262
272
Raises:
263
- TypeError: If the annotation is neither a type nor `Parameter.empty`.
273
+ TypeError: If the annotation is neither a valid `TypeAnnotation` type (see above) nor
274
+ `inspect.Parameter.empty`.
264
275
"""
276
+ # NB: `inspect.Parameter.empty` is a subclass of `type`, so this check passes for unannotated
277
+ # parameters.
265
278
if not isinstance (annotation , TYPE_ANNOTATION_TYPES ):
266
279
raise TypeError (f"Annotation must be a type, not { type (annotation ).__name__ } " )
267
280
0 commit comments