@@ -123,6 +123,8 @@ just raise a custom exception indicating which extra would be required:
123
123
124
124
.. code-block :: python
125
125
126
+ from dataclasses import dataclass
127
+
126
128
@dataclass
127
129
class MissingExtra (Exception ):
128
130
name: str
@@ -196,29 +198,59 @@ import when the functionality requiring it is actually used. E.g.:
196
198
197
199
.. code-block :: python
198
200
199
- def import_extra_func_if_avail ():
201
+ def import_extra_module_if_avail ():
200
202
# surround this with the appropriate checks / error handling:
201
203
...
202
- from your_optional_dependency import extra_func
204
+ import your_optional_dependency
203
205
...
204
206
205
- return extra_func
207
+ return your_optional_dependency
206
208
207
209
...
208
210
209
211
def some_func_requiring_your_extra ():
210
212
try :
211
- some_function = import_extra_func_if_avail ()
213
+ optional_module = import_extra_module_if_avail ()
212
214
except MissingExtra:
213
215
... # handle missing extra
214
216
217
+ # now you can use functionality from the optional dependency, e.g.:
218
+ optional_module.extra_func(... )
219
+
215
220
While this solution is more robust than the one from the preceding subsection,
216
- it can take more effort to make it work with static type checking.
221
+ it can take more effort to make it work with
222
+ :term: `static type checking <static type checker> `:
223
+ To correctly statically type a function returning a module, you'd have to
224
+ introduce an "artificial" type representing the latter, e.g.
225
+
226
+ .. code-block :: python
227
+
228
+ from typing import cast, Protocol
229
+
230
+ class YourOptionalModuleType (Protocol ):
231
+ extra_func: Callable[... ]
232
+ ... # other objects you want to use
233
+
234
+ def some_func_requiring_your_extra () -> YourOptionalModuleType:
235
+ ...
236
+
237
+ return cast(YourOptionalModuleType, optional_module)
238
+
239
+ An alternative would be to instead have functions that import and return only
240
+ the objects you actually need:
241
+
242
+ .. code-block :: python
243
+
244
+ def import_extra_func_if_avail () -> Callable[... ]:
245
+ # surround this with the appropriate checks / error handling:
246
+ ...
247
+ from your_optional_dependency import extra_func
248
+ ...
249
+
250
+ return extra_func
217
251
218
- Interaction with static type checking
219
- =====================================
252
+ But this can become verbose when you import a lot of names.
220
253
221
- TODO either put here or directly in previous sections... not sure
222
254
223
255
Other considerations
224
256
====================
0 commit comments