Go the other way around, and build VALID_ARGUMENTS from Argument:
Argument = typing.Literal['foo', 'bar']
VALID_ARGUMENTS: typing.Tuple[Argument, ...] = typing.get_args(Argument)
I've used a tuple for VALID_ARGUMENTS here, but if for some reason you really prefer a list, you can get one:
VALID_ARGUMENTS: typing.List[Argument] = list(typing.get_args(Argument))
It's possible at runtime to build Argument from VALID_ARGUMENTS, but doing so is incompatible with static analysis, which is the primary use case of type annotations.
Doing so is also considered semantically invalid - the spec forbids parameterizing Literal with dynamically computed parameters. The runtime implementation simply doesn't have the information it would need to validate this. Building VALID_ARGUMENTS from Argument is the way to go.
Go the other way around, and build VALID_ARGUMENTS from Argument:
Argument = typing.Literal['foo', 'bar']
VALID_ARGUMENTS: typing.Tuple[Argument, ...] = typing.get_args(Argument)
I've used a tuple for VALID_ARGUMENTS here, but if for some reason you really prefer a list, you can get one:
VALID_ARGUMENTS: typing.List[Argument] = list(typing.get_args(Argument))
It's possible at runtime to build Argument from VALID_ARGUMENTS, but doing so is incompatible with static analysis, which is the primary use case of type annotations.
Doing so is also considered semantically invalid - the spec forbids parameterizing Literal with dynamically computed parameters. The runtime implementation simply doesn't have the information it would need to validate this. Building VALID_ARGUMENTS from Argument is the way to go.
If anyone's still looking for a workaround for this:
typing.Literal[tuple(VALID_ARGUMENTS)]
Is using list() preferred over []?
Introduce a "bareword" list/dict literal - Ideas - Discussions on Python.org
python - Why do the list function and list literals act differently? - Stack Overflow
coding style - Literals versus instantiating by name lists and dicts in Python? - Software Engineering Stack Exchange
Videos
I've been using PyCharm as my IDE, and it always asks me to switch over all my []s and {}s to list() and dict() respectively. So is using list() and dict() preferred over using [] and {}?
Also, I always thought that [] was the literal notation, but PyCharm says that list() is. I got that idea from JSON, btw. So is list() the literal notation? If yes, what is [] called?
The difference between
my_list = list()
and
my_list = []
is that list requires a namespace lookup, first in the module level globals, then in the builtins.
On the other hand, [] is a list literal and is parsed as creating a new list from the language, which doesn't require any name lookups. So the literal is faster on object creation.
Otherwise, they are both the same, for empty lists.
The same analogously applies to dict() and {}.
(Slightly beyond the scope of the question, but the difference, as constructors of non-empty lists, is that list() takes an iterable to construct the list, and [] constructs the list with only the objects with which you create it, usually literals.)
I almost never use the collection literals for empty collections in my Python code and prefer the named list, set, dict and tuple constructors instead.
The reason for this is that the literals can be quite confusing. For example, {} is not the empty set but an empty dictionary which is contrary to what anybody with a background in mathematics would intuitively expect. Also, the empty tuple () looks really awkward. Once I'm using the named constructors for sets, dictionaries and tuples, it's only a matter of consistency to use them for lists as well, even though the empty list literal [] looks decently and I'm not aware of any bad surprises that its usage might cause.
I want to create a type alias for a Literal type from the values of a container (list, tuple, members of an Enum, whatever). This would be nice and DRY as the type could inherit the values of the container as my developing API evolves.
My only issue is that MyPy doesn't appreciate it (Invalid type alias: expression is not a valid type [valid-type]). But I'm inclined to say yeet and go with it. Thoughts?
from typing import Literal
modes = ("r", "w", "a")
# The WET (write everything twice) way
type ModeVals1 = Literal["r", "w", "a"]
# The DRY (don't repeat yourself) way
type ModeVals2 = Literal[*modes]
# functionally equivalent right?
# In use
def my_func(mode: ModeVals2, ...):
...