Core: typing for `Option.default` and a few other ClassVars (#2899)
* Core: typing for `Option.default` and a few other `Option` class variables This is a replacement for https://github.com/ArchipelagoMW/Archipelago/pull/2173 You can read discussion there for issues we found for why we can't have more specific typing on `default` instead of setting a default in `Option` (where we don't know the type), we check in the metaclass to make sure they have a default. * NumericOption doesn't need the type annotation that brings out the mypy bug * SoE default ClassVar
This commit is contained in:
parent
f8d5fe0e1e
commit
03d403ff51
20
Options.py
20
Options.py
|
@ -41,6 +41,11 @@ class AssembleOptions(abc.ABCMeta):
|
|||
aliases = {name[6:].lower(): option_id for name, option_id in attrs.items() if
|
||||
name.startswith("alias_")}
|
||||
|
||||
assert (
|
||||
name in {"Option", "VerifyKeys"} or # base abstract classes don't need default
|
||||
"default" in attrs or
|
||||
any(hasattr(base, "default") for base in bases)
|
||||
), f"Option class {name} needs default value"
|
||||
assert "random" not in aliases, "Choice option 'random' cannot be manually assigned."
|
||||
|
||||
# auto-alias Off and On being parsed as True and False
|
||||
|
@ -96,7 +101,7 @@ T = typing.TypeVar('T')
|
|||
|
||||
class Option(typing.Generic[T], metaclass=AssembleOptions):
|
||||
value: T
|
||||
default = 0
|
||||
default: typing.ClassVar[typing.Any] # something that __init__ will be able to convert to the correct type
|
||||
|
||||
# convert option_name_long into Name Long as display_name, otherwise name_long is the result.
|
||||
# Handled in get_option_name()
|
||||
|
@ -106,8 +111,9 @@ class Option(typing.Generic[T], metaclass=AssembleOptions):
|
|||
supports_weighting = True
|
||||
|
||||
# filled by AssembleOptions:
|
||||
name_lookup: typing.Dict[T, str]
|
||||
options: typing.Dict[str, int]
|
||||
name_lookup: typing.ClassVar[typing.Dict[T, str]] # type: ignore
|
||||
# https://github.com/python/typing/discussions/1460 the reason for this type: ignore
|
||||
options: typing.ClassVar[typing.Dict[str, int]]
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.__class__.__name__}({self.current_option_name})"
|
||||
|
@ -160,6 +166,8 @@ class FreeText(Option[str]):
|
|||
"""Text option that allows users to enter strings.
|
||||
Needs to be validated by the world or option definition."""
|
||||
|
||||
default = ""
|
||||
|
||||
def __init__(self, value: str):
|
||||
assert isinstance(value, str), "value of FreeText must be a string"
|
||||
self.value = value
|
||||
|
@ -811,7 +819,7 @@ class VerifyKeys(metaclass=FreezeValidKeys):
|
|||
|
||||
|
||||
class OptionDict(Option[typing.Dict[str, typing.Any]], VerifyKeys, typing.Mapping[str, typing.Any]):
|
||||
default: typing.Dict[str, typing.Any] = {}
|
||||
default = {}
|
||||
supports_weighting = False
|
||||
|
||||
def __init__(self, value: typing.Dict[str, typing.Any]):
|
||||
|
@ -852,7 +860,7 @@ class OptionList(Option[typing.List[typing.Any]], VerifyKeys):
|
|||
# If only unique entries are needed and input order of elements does not matter, OptionSet should be used instead.
|
||||
# Not a docstring so it doesn't get grabbed by the options system.
|
||||
|
||||
default: typing.Union[typing.List[typing.Any], typing.Tuple[typing.Any, ...]] = ()
|
||||
default = ()
|
||||
supports_weighting = False
|
||||
|
||||
def __init__(self, value: typing.Iterable[typing.Any]):
|
||||
|
@ -878,7 +886,7 @@ class OptionList(Option[typing.List[typing.Any]], VerifyKeys):
|
|||
|
||||
|
||||
class OptionSet(Option[typing.Set[str]], VerifyKeys):
|
||||
default: typing.Union[typing.Set[str], typing.FrozenSet[str]] = frozenset()
|
||||
default = frozenset()
|
||||
supports_weighting = False
|
||||
|
||||
def __init__(self, value: typing.Iterable[str]):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from dataclasses import dataclass, fields
|
||||
from typing import Any, cast, Dict, Iterator, List, Tuple, Protocol
|
||||
from typing import Any, ClassVar, cast, Dict, Iterator, List, Tuple, Protocol
|
||||
|
||||
from Options import AssembleOptions, Choice, DeathLink, DefaultOnToggle, Option, PerGameCommonOptions, \
|
||||
ProgressionBalancing, Range, Toggle
|
||||
|
@ -8,13 +8,13 @@ from Options import AssembleOptions, Choice, DeathLink, DefaultOnToggle, Option,
|
|||
# typing boilerplate
|
||||
class FlagsProtocol(Protocol):
|
||||
value: int
|
||||
default: int
|
||||
default: ClassVar[int]
|
||||
flags: List[str]
|
||||
|
||||
|
||||
class FlagProtocol(Protocol):
|
||||
value: int
|
||||
default: int
|
||||
default: ClassVar[int]
|
||||
flag: str
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue