Skip to content

Commit e791229

Browse files
committed
Add type checking considerations
1 parent c8d32d9 commit e791229

File tree

1 file changed

+40
-8
lines changed

1 file changed

+40
-8
lines changed

source/guides/handling-missing-extras-at-runtime.rst

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ just raise a custom exception indicating which extra would be required:
123123

124124
.. code-block:: python
125125
126+
from dataclasses import dataclass
127+
126128
@dataclass
127129
class MissingExtra(Exception):
128130
name: str
@@ -196,29 +198,59 @@ import when the functionality requiring it is actually used. E.g.:
196198

197199
.. code-block:: python
198200
199-
def import_extra_func_if_avail():
201+
def import_extra_module_if_avail():
200202
# surround this with the appropriate checks / error handling:
201203
...
202-
from your_optional_dependency import extra_func
204+
import your_optional_dependency
203205
...
204206
205-
return extra_func
207+
return your_optional_dependency
206208
207209
...
208210
209211
def some_func_requiring_your_extra():
210212
try:
211-
some_function = import_extra_func_if_avail()
213+
optional_module = import_extra_module_if_avail()
212214
except MissingExtra:
213215
... # handle missing extra
214216
217+
# now you can use functionality from the optional dependency, e.g.:
218+
optional_module.extra_func(...)
219+
215220
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
217251
218-
Interaction with static type checking
219-
=====================================
252+
But this can become verbose when you import a lot of names.
220253

221-
TODO either put here or directly in previous sections... not sure
222254

223255
Other considerations
224256
====================

0 commit comments

Comments
 (0)