How to bind "typing_extensions.Literal" into another module so that it can be imported from that module?

Viewed 349

To reduce my imports count, I'm trying to bind some typing aliases in a dedicated module, e.g. colour.utilities.hints.

In that module, for compatibility reasons and because I'm still running Python 3.7, I try to bind typing_extensions.Literal to a new Literal attribute:

colour/utilities/hints.py

import typing_extensions

Literal = typing_extensions.Literal

Then I used the bound attribute as follows:

colour/utilities/array.py

from typing import Optional, Union

from colour.utilities.hints import ArrayLike, NDArray, Literal

# ...

def orient(a: ArrayLike,
           orientation: Literal['Flip', 'Flop', '90 CW', '90 CCW', '180']
           ) -> Union[NDArray, None]:
    orientation = validate_method(orientation,
                                  ['Flip', 'Flop', '90 CW', '90 CCW', '180'])

    if orientation == 'flip':
        return np.fliplr(a)
    elif orientation == 'flop':
        return np.flipud(a)
    elif orientation == '90 cw':
        return np.rot90(a, 3)
    elif orientation == '90 ccw':
        return np.rot90(a)
    elif orientation == '180':
        return np.rot90(a, 2)
    else:
        return None

When I type check the module though:

colour/utilities/array.py:1077: error: Variable "colour.utilities.hints.Literal" is not valid as a type
colour/utilities/array.py:1077: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases
colour/utilities/array.py:1077: error: Name "Flip" is not defined
colour/utilities/array.py:1077: error: Name "Flop" is not defined
colour/utilities/array.py:1077: error: Invalid type comment or annotation

Importing typing_extensions.Literal in colour/utilities/array.py and using it directly is fine though.

2 Answers

Modifying the binding from

import typing_extensions

Literal = typing_extensions.Literal

to

from typing_extensions import Literal

Literal = Literal

fixes the issue, I'm not entirely sure as to why though.

Just a suggestion for a slight improvement, but you don't need to explicitly define a new Literal variable. For example, you could also define your hints.py module as follows:

__all__ = [
    'Literal',
    # ...
]

try:
    from typing_extensions import Literal
except ImportError:
    from typing import Literal

Then in another module:

from hints import Literal
Related