Reputation: 1559
I want to update a library so that a requirement is optional (using extras_require
).
Unfortunately, imported classes from the optional requirement are used everywhere in the lib as type hints. Here is an example:
from typing import List
try:
from extra.sub import ExtraFoo, ExtraBar
except ImportError:
pass
def optional(foo: ExtraFoo) -> List[ExtraBar]:
pass
def greeting(name: str) -> str:
return 'Hello ' + name
if __name__ == '__main__':
greeting('John Smith')
In this example, we won't use optional()
if extra
was not installed. Indeed, such code will raise a NameError
since ExtraFoo
and ExtraBar
are used as a type hint.
A possible fix is to declare class ExtraFoo: pass
and class ExtraBar: pass
in the except
block. However, there are situations like that everywhere in the code with multiple types from the same module.
I'd like to avoid polluting the code with declaration of dummy imports. Is there a common way to deal with this situation (e.g. a proxy module)?
Upvotes: 5
Views: 372
Reputation: 111
You can import it with typing.TYPE_CHECKING
if TYPE_CHECKING:
from extra.sub import ExtraFoo, ExtraBar
If you need the imports for something else than type hints you need to import them in a regular way, either in the function that need them.
try:
from extra.sub import ExtraFoo, ExtraBar
except ImportError:
ExtraFoo = None
ExtraBar = None
def function_that_need_extra_foo():
if ExtraFoo is None:
raise ... # Error that states ExtraFoo is not available
Upvotes: 2
Reputation: 193
I believe the answer to the original question is included in the comments, however it's a bit confusing as the question has been edited. For the current version of the question, I believe the solution is to use forward references, i.e. put your type hints in quotes as follows:
def optional(foo: "ExtraFoo") -> List["ExtraBar"]:
pass
Upvotes: 1