Skip to content

Commit

Permalink
Extend the life of deprecated aliases (#13791)
Browse files Browse the repository at this point in the history
Summary of the issue:
For deprecated aliases, there is no need to remove them, as they have a minimum maintenance burden.
Add-on authors and contributors have requested we keep aliases where possible.

However, without marking code for removal, it can be hard to find deprecations.
Core contributors and add-on authors may want to avoid deprecated APIs.
As such, a way to test the deprecated API being removed is needed.

Description of how this pull request fixes the issue:
Extends the life of all currently deprecated aliases.
Warnings will be logged when attempting to use deprecated aliases (except for controlTypes, due to the noise of this).
Adds a global variable to mark code as deprecated, which allows developers to test NVDA with deprecated APIs removed.

As a result, there is currently no API breakages staged for 2023.1
  • Loading branch information
seanbudd authored Jun 14, 2022
1 parent 0eb15c9 commit d3712e5
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 49 deletions.
13 changes: 7 additions & 6 deletions source/appModuleHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def __getattr__(attrName: str) -> Any:
since add-ons are initialized before `appModuleHandler`
and when `appModuleHandler` was not yet initialized the variable was set to `None`.
"""
if attrName == "NVDAProcessID":
if attrName == "NVDAProcessID" and globalVars._allowDeprecatedAPI:
log.warning("appModuleHandler.NVDAProcessID is deprecated, use globalVars.appPid instead.")
if initialize._alreadyInitialized:
return globalVars.appPid
Expand All @@ -112,12 +112,13 @@ def _warnDeprecatedAliasAppModule() -> None:
except KeyError:
raise RuntimeError("This function can be executed only inside an alias App Module.") from None
else:
log.warning(
(
f"Importing from appModules.{currModName} is deprecated,"
f" you should import from appModules.{replacementModName}."
)
deprecatedImportWarning = (
f"Importing appModules.{currModName} is deprecated,"
f" instead import appModules.{replacementModName}."
)
log.warning(deprecatedImportWarning)
if not globalVars._allowDeprecatedAPI:
raise ModuleNotFoundError(deprecatedImportWarning)


def registerExecutableWithAppModule(executableName: str, appModName: str) -> None:
Expand Down
28 changes: 12 additions & 16 deletions source/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
For the latter two actions, one can perform actions prior to and/or after they take place.
"""


from buildVersion import version_year
from enum import Enum
import globalVars
import winreg
Expand Down Expand Up @@ -61,6 +59,18 @@
pre_configReset = extensionPoints.Action()
post_configReset = extensionPoints.Action()


def __getattr__(attrName: str) -> Any:
"""Module level `__getattr__` used to preserve backward compatibility."""
if attrName == "NVDA_REGKEY" and globalVars._allowDeprecatedAPI:
log.warning("NVDA_REGKEY is deprecated, use RegistryKey.NVDA instead.")
return RegistryKey.NVDA.value
if attrName == "RUN_REGKEY" and globalVars._allowDeprecatedAPI:
log.warning("RUN_REGKEY is deprecated, use RegistryKey.RUN instead.")
return RegistryKey.RUN.value
raise AttributeError(f"module {repr(__name__)} has no attribute {repr(attrName)}")


def initialize():
global conf
conf = ConfigManager()
Expand Down Expand Up @@ -88,20 +98,6 @@ class RegistryKey(str, Enum):
"""


if version_year < 2023:
RUN_REGKEY = RegistryKey.RUN.value
"""
Deprecated, for removal in 2023.
Use L{RegistryKey.RUN} instead.
"""

NVDA_REGKEY = RegistryKey.NVDA.value
"""
Deprecated, for removal in 2023.
Use L{RegistryKey.NVDA} instead.
"""


def isInstalledCopy() -> bool:
"""Checks to see if this running copy of NVDA is installed on the system"""
try:
Expand Down
36 changes: 17 additions & 19 deletions source/easeOfAccess.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
"""Utilities for working with the Windows Ease of Access Center.
"""

from buildVersion import version_year
from enum import Enum, IntEnum
from typing import List
from typing import Any, List

import globalVars
from logHandler import log
import winreg
import winUser
Expand All @@ -20,6 +21,20 @@
_APP_KEY_NAME = "nvda_nvda_v1"


def __getattr__(attrName: str) -> Any:
"""Module level `__getattr__` used to preserve backward compatibility."""
if attrName == "ROOT_KEY" and globalVars._allowDeprecatedAPI:
log.warning("ROOT_KEY is deprecated, use RegistryKey.ROOT instead.")
return RegistryKey.ROOT.value
if attrName == "APP_KEY_PATH" and globalVars._allowDeprecatedAPI:
log.warning("APP_KEY_PATH is deprecated, use RegistryKey.APP instead.")
return RegistryKey.APP.value
if attrName == "APP_KEY_NAME" and globalVars._allowDeprecatedAPI:
log.warning("APP_KEY_NAME is deprecated.")
return _APP_KEY_NAME
raise AttributeError(f"module {repr(__name__)} has no attribute {repr(attrName)}")


class RegistryKey(str, Enum):
ROOT = r"Software\Microsoft\Windows NT\CurrentVersion\Accessibility"
TEMP = r"Software\Microsoft\Windows NT\CurrentVersion\AccessibilityTemp"
Expand All @@ -32,23 +47,6 @@ class AutoStartContext(IntEnum):
AFTER_LOGON = winreg.HKEY_CURRENT_USER


if version_year < 2023:
ROOT_KEY = RegistryKey.ROOT.value
"""
Deprecated, for removal in 2023.
Use L{RegistryKey.ROOT} instead.
"""

APP_KEY_NAME = _APP_KEY_NAME
"""Deprecated, for removal in 2023"""

APP_KEY_PATH = RegistryKey.APP.value
"""
Deprecated, for removal in 2023.
Use L{RegistryKey.APP} instead.
"""


def isRegistered() -> bool:
try:
winreg.OpenKey(
Expand Down
10 changes: 10 additions & 0 deletions source/globalVars.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,13 @@ class DefaultAppArgs(argparse.Namespace):
appPid: int = 0
"""The process ID of NVDA itself.
"""

_allowDeprecatedAPI: bool = True
"""
Used for marking code as deprecated.
This should never be False in released code.
Making this False may be useful for testing if code is compliant without using deprecated APIs.
Note that deprecated code may be imported at runtime,
and as such, this value cannot be changed at runtime to test compliance.
"""
6 changes: 2 additions & 4 deletions source/gui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,12 @@
import speechViewer
import winUser
import api
from buildVersion import version_year


if version_year < 2023:
if globalVars._allowDeprecatedAPI:
def quit():
"""
Deprecated, for removal in 2023.1.
Use `wx.CallAfter(mainFrame.onExitCommand, None)` directly instead.
Deprecated, use `wx.CallAfter(mainFrame.onExitCommand, None)` directly instead.
"""
log.debugWarning("Deprecated function called: gui.quit", stack_info=True)
wx.CallAfter(mainFrame.onExitCommand, None)
Expand Down
7 changes: 3 additions & 4 deletions user_docs/en/changes.t2t
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,11 @@ Please test the new API and provide feedback.
For add-on authors, please open a GitHub issue if these changes stop the API from meeting your needs.


- ``appModuleHandler.NVDAProcessID`` is deprecated - use ``globalVars.appPid`` instead. (#13646)
- ``gui.quit`` has been deprecated for removal in 2023.1. (#13498)
- Use ``wx.CallAfter(mainFrame.onExitCommand, None)`` directly instead.
- ``appModuleHandler.NVDAProcessID`` is deprecated, use ``globalVars.appPid`` instead. (#13646)
- ``gui.quit`` is deprecated, use ``wx.CallAfter(mainFrame.onExitCommand, None)`` instead. (#13498)
-
% Insert new list items here as the alias appModule table should be kept at the bottom of this list
- Some alias appModules are marked as deprecated and will be removed in 2023.1.
- Some alias appModules are marked as deprecated.
Code which imports from one of them, should instead import from the replacement module. (#13366)
-

Expand Down

0 comments on commit d3712e5

Please sign in to comment.