DurandA
DurandA

Reputation: 1559

How to handle extra requirements when also used as type hints?

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

Answers (2)

Eirik Lid
Eirik Lid

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

Ben
Ben

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

Related Questions