Skip to content

Commit

Permalink
fixup! squash! Implement Enums for Role and State constants in contro…
Browse files Browse the repository at this point in the history
…lTypes (#12510)
  • Loading branch information
seanbudd committed Jun 29, 2021
1 parent e47d53e commit ed7650b
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 90 deletions.
17 changes: 10 additions & 7 deletions source/controlTypes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@

from buildVersion import version_year

# imports used in __all__, _ prefixed imports are marked for deprecation
from .isCurrent import IsCurrent
from .outputReason import OutputReason
from .processAndLabelStates import processAndLabelStates, _processNegativeStates, _processPositiveStates
from .role import Role, silentRolesOnFocus, silentValuesForRoles, _roleLabels
from .state import State, STATES_SORTED, _negativeStateLabels, _stateLabels
from .processAndLabelStates import processAndLabelStates
from .role import Role, silentRolesOnFocus, silentValuesForRoles
from .state import State, STATES_SORTED


# After 2022, this will specify what is exported when performing a star import (from controlTypes import *).
# Will break backwards compatibility.
# To maintain backwards compatibility, all symbols are exported from the package until 2022.1
if version_year >= 2022:
# Override (and limit) the symbols exported by the controlTypes package
# These are the symbols available when `from controlTypes import *` is used.
__all__ = [
"IsCurrent",
"OutputReason",
Expand All @@ -29,15 +29,18 @@


# Added to maintain backwards compatibility, marked for deprecation to be removed in 2022.1
# usages to be replaced by .processAndLabelStates.[_processNegativeStates|_processPositiveStates]
# usages to be avoided or replaced by .processAndLabelStates.[_processNegativeStates|_processPositiveStates]
if version_year < 2022:
from .processAndLabelStates import _processNegativeStates, _processPositiveStates
processNegativeStates = _processNegativeStates
processPositiveStates = _processPositiveStates


# Added to maintain backwards compatibility, marked for deprecation to be removed in 2022.1
# usages to be replaced by Role.*.displayString and State.*.displayString
if version_year < 2022:
from .role import _roleLabels
from .state import _stateLabels, _negativeStateLabels
roleLabels = _roleLabels
stateLabels = _stateLabels
negativeStateLabels = _negativeStateLabels
Expand Down
12 changes: 7 additions & 5 deletions source/controlTypes/isCurrent.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
# See the file COPYING for more details.
# Copyright (C) 2007-2021 NV Access Limited, Babbage B.V.

from enum import Enum
from typing import Dict

from utils.displayString import DisplayStringEnumMixin, DisplayStringEnumMixinMeta
from utils.displayString import DisplayStringStrEnum


class IsCurrent(DisplayStringEnumMixin, str, Enum, metaclass=DisplayStringEnumMixinMeta):
class IsCurrent(DisplayStringStrEnum):
"""Values to use within NVDA to denote 'current' values.
These describe if an item is the current item within a particular kind of selection.
EG aria-current
Expand All @@ -27,8 +26,11 @@ def _displayStringLabels(self):
return _isCurrentLabels

@property
def defaultValue(self):
return self.YES
def displayString(self):
try:
return super().displayString
except KeyError:
return self.YES.displayString


#: Text to use for 'current' values. These describe if an item is the current item
Expand Down
9 changes: 2 additions & 7 deletions source/controlTypes/role.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,16 @@
# See the file COPYING for more details.
# Copyright (C) 2007-2021 NV Access Limited, Babbage B.V.

from enum import IntEnum
from typing import Dict, Set

from utils.displayString import DisplayStringEnumMixin, DisplayStringEnumMixinMeta
from utils.displayString import DisplayStringIntEnum


class Role(DisplayStringEnumMixin, IntEnum, metaclass=DisplayStringEnumMixinMeta):
class Role(DisplayStringIntEnum):
@property
def _displayStringLabels(self):
return _roleLabels

@property
def defaultValue(self):
return self.UNKNOWN

UNKNOWN = 0
WINDOW = 1
TITLEBAR = 2
Expand Down
9 changes: 2 additions & 7 deletions source/controlTypes/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,16 @@
# See the file COPYING for more details.
# Copyright (C) 2007-2021 NV Access Limited, Babbage B.V.

from enum import IntEnum
from typing import Dict

from utils.displayString import DisplayStringEnumMixin, DisplayStringEnumMixinMeta
from utils.displayString import DisplayStringIntEnum


class State(DisplayStringEnumMixin, IntEnum, metaclass=DisplayStringEnumMixinMeta):
class State(DisplayStringIntEnum):
@property
def _displayStringLabels(self):
return _stateLabels

@property
def defaultValue(self):
return self.DEFUNCT

@property
def negativeDisplayString(self) -> str:
"""
Expand Down
135 changes: 71 additions & 64 deletions source/utils/displayString.py
Original file line number Diff line number Diff line change
@@ -1,64 +1,71 @@
# A part of NonVisual Desktop Access (NVDA)
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.
# Copyright (C) 2021 NV Access Limited.

from abc import ABC, ABCMeta, abstractproperty
from enum import Enum, EnumMeta
from typing import Dict

from logHandler import log


class DisplayStringEnumMixinMeta(ABCMeta, EnumMeta):
"""
This helps correct the Method Resolution Order (MRO) when using the `DisplayStringEnumMixin`.
When creating an Enum with a Mixin, Python suggest an ordering of
`class EnumWithMixin(Mixin, type, EnumClass):`.
This creates a metaclass conflict as both DisplayStringEnumMixin and Enum both have metaclasses,
ABCMeta and EnumMeta. This requires a new MetaClass which subclasses both of these. This follows the
same ordering of the EnumWithMixin usage.
See `DisplayStringEnumMixin`.
"""
pass


class DisplayStringEnumMixin(ABC):
"""
This mixin can be used with a class which subclasses Enum to provided translated display strings for
members of the enum. The abstract properties must be overridden.
To be used with `DisplayStringEnumMixinMeta`.
Usage for python 3.7 is as follows:
```
class ExampleEnum(DisplayStringEnumMixin, str, Enum, metaclass=DisplayStringEnumMixinMeta):
pass
class ExampleIntEnum(DisplayStringEnumMixin, IntEnum, metaclass=DisplayStringEnumMixinMeta):
pass
```
"""
@abstractproperty
def _displayStringLabels(self) -> Dict[Enum, str]:
"""
Specify a dictionary which takes members of the Enum and returns the translated display string.
"""
pass

@abstractproperty
def defaultValue(self) -> Enum:
"""
Specify an Enum member with a known translated display string to use as a default if there is no known
display string for a given member in _displayStringLabels.
"""
pass

@property
def displayString(self) -> str:
"""
@return: The translated UI display string that should be used for this value of the enum.
"""
try:
return self._displayStringLabels[self]
except KeyError:
log.error(f"No translation mapping for: {self}")
return self._displayStringLabels[self.defaultValue]
# A part of NonVisual Desktop Access (NVDA)
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.
# Copyright (C) 2021 NV Access Limited.

from abc import ABC, ABCMeta, abstractproperty
from enum import Enum, EnumMeta, IntEnum
from typing import Dict

from logHandler import log


class _DisplayStringEnumMixinMeta(ABCMeta, EnumMeta):
"""
This helps correct the Method Resolution Order (MRO) when using the `_DisplayStringEnumMixin`.
When creating an Enum with a Mixin, Python suggest an ordering of
`class EnumWithMixin(Mixin, type, EnumClass):`.
This creates a metaclass conflict as both _DisplayStringEnumMixin and Enum both have metaclasses,
ABCMeta and EnumMeta. This requires a new MetaClass which subclasses both of these. This follows the
same ordering of the EnumWithMixin usage.
See `_DisplayStringEnumMixin`.
"""
pass


class _DisplayStringEnumMixin(ABC):
"""
This mixin can be used with a class which subclasses Enum to provided translated display strings for
members of the enum. The abstract properties must be overridden.
To be used with `_DisplayStringEnumMixinMeta`.
Usage for python 3.7 is as follows:
```
class ExampleEnum(_DisplayStringEnumMixin, str, Enum, metaclass=_DisplayStringEnumMixinMeta):
pass
class ExampleIntEnum(_DisplayStringEnumMixin, IntEnum, metaclass=_DisplayStringEnumMixinMeta):
pass
```
"""
@abstractproperty
def _displayStringLabels(self) -> Dict[Enum, str]:
"""
Specify a dictionary which takes members of the Enum and returns the translated display string.
"""
pass

@property
def displayString(self) -> str:
"""
@return: The translated UI display string that should be used for this value of the enum.
"""
try:
return self._displayStringLabels[self]
except KeyError as e:
log.error(f"No translation mapping for: {self}")
raise e


class DisplayStringEnum(_DisplayStringEnumMixin, Enum, metaclass=_DisplayStringEnumMixinMeta):
"""An Enum class that adds a displayString property defined by _displayStringLabels"""
pass


class DisplayStringStrEnum(_DisplayStringEnumMixin, str, Enum, metaclass=_DisplayStringEnumMixinMeta):
"""A str Enum class that adds a displayString property defined by _displayStringLabels"""
pass


class DisplayStringIntEnum(_DisplayStringEnumMixin, IntEnum, metaclass=_DisplayStringEnumMixinMeta):
"""An IntEnum class that adds a displayString property defined by _displayStringLabels"""
pass

0 comments on commit ed7650b

Please sign in to comment.