From ebd86be7b9191056005c1b3a49d6fdff2c639704 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 6 Sep 2026 13:01:15 +0000 Subject: [PATCH 1/4] Initial plan From e0d40cce7e9b36905e1e03748f07eb594240f59b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 6 Sep 2026 13:05:04 +0000 Subject: [PATCH 2/4] Initial plan Co-authored-by: zstanecic <11149715+zstanecic@users.noreply.github.com> --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index dcfc8a7..473c681 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,6 +95,7 @@ logger-objects = ["logHandler.log"] [tool.pyright] venvPath = ".venv" venv = "." +stubPath = ".vscode/typings" pythonPlatform = "Windows" typeCheckingMode = "strict" From e1f48a872c45504b7d5a6409044492a3600f5b98 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 6 Sep 2026 13:09:23 +0000 Subject: [PATCH 3/4] Fix translation initialization and format code Co-authored-by: zstanecic <11149715+zstanecic@users.noreply.github.com> --- addon/globalPlugins/clock/clockHandler.py | 17 +++-- addon/globalPlugins/clock/skipTranslation.py | 7 ++ addon/installTasks.py | 3 + sconstruct | 13 ++-- site_scons/site_tools/NVDATool/__init__.py | 74 +++++++++++--------- 5 files changed, 70 insertions(+), 44 deletions(-) diff --git a/addon/globalPlugins/clock/clockHandler.py b/addon/globalPlugins/clock/clockHandler.py index 80f3e24..fea24fa 100644 --- a/addon/globalPlugins/clock/clockHandler.py +++ b/addon/globalPlugins/clock/clockHandler.py @@ -151,7 +151,10 @@ def _getWaveFile(self, now, interval): if target_minute == 0: return os.path.join(paths.SOUNDS_DIR, config.conf["clockAndCalendar"]["timeReportSound"]) else: - return os.path.join(paths.SOUNDS_DIR, config.conf["clockAndCalendar"]["timeIntermediateReportSound"]) + return os.path.join( + paths.SOUNDS_DIR, + config.conf["clockAndCalendar"]["timeIntermediateReportSound"], + ) return os.path.join(paths.SOUNDS_DIR, config.conf["clockAndCalendar"]["timeReportSound"]) def _getBoundaryTime(self, now, secs_to_boundary): @@ -183,10 +186,14 @@ def _speakCurrentTime(self) -> None: now = datetime.now() ui.message( safeGetTimeFormatEx( - None, None, now, formats.rgx.sub( - formats.repl, formats.timeFormats[config.conf['clockAndCalendar']['timeDisplayFormat']] - ) - ) + None, + None, + now, + formats.rgx.sub( + formats.repl, + formats.timeFormats[config.conf["clockAndCalendar"]["timeDisplayFormat"]], + ), + ), ) def reportClock(self) -> None: diff --git a/addon/globalPlugins/clock/skipTranslation.py b/addon/globalPlugins/clock/skipTranslation.py index 17624c7..3ef22b3 100644 --- a/addon/globalPlugins/clock/skipTranslation.py +++ b/addon/globalPlugins/clock/skipTranslation.py @@ -7,6 +7,13 @@ # Based on implementation made by Alberto Buffolino # https://github.com/nvaccess/nvda/issues/4652 +from typing import Callable + +import addonHandler + +addonHandler.initTranslation() +_: Callable[[str], str] + def translate(text): return _(text) diff --git a/addon/installTasks.py b/addon/installTasks.py index a2d565e..e45710d 100644 --- a/addon/installTasks.py +++ b/addon/installTasks.py @@ -3,11 +3,14 @@ # Author: Hrvoje Katich and contributors # Copyright 2013-2021, released under GPL. +from typing import Callable + import config from configobj.validate import VdtTypeError import addonHandler addonHandler.initTranslation() +_: Callable[[str], str] def onInstall(): diff --git a/sconstruct b/sconstruct index cdbad3f..4cfef8c 100644 --- a/sconstruct +++ b/sconstruct @@ -42,7 +42,7 @@ def validateVersionNumber(key: str, val: str, _): def expandGlobs(patterns: Iterable[str], rootdir: Path = Path(".")) -> list[FS.Entry]: - return [env.Entry(e) for pattern in patterns for e in rootdir.glob(pattern.lstrip('/'))] + return [env.Entry(e) for pattern in patterns for e in rootdir.glob(pattern.lstrip("/"))] addonDir: Final = Path("addon/") @@ -67,7 +67,7 @@ env.Append( if env["dev"]: from datetime import date - versionTimestamp = date.today().strftime('%Y%m%d') + versionTimestamp = date.today().strftime("%Y%m%d") version = f"{versionTimestamp}.0.0" env["addon_info"]["addon_version"] = version env["versionNumber"] = version @@ -84,7 +84,7 @@ env.Append(**env["addon_info"]) addonFile = env.File("${addon_name}-${addon_version}.nvda-addon") addon = env.NVDAAddon(addonFile, env.Dir(addonDir), excludePatterns=buildVars.excludedFiles) -langDirs: list[FS.Dir] = [env.Dir(d) for d in env.Glob(localeDir/"*/") if d.isdir()] +langDirs: list[FS.Dir] = [env.Dir(d) for d in env.Glob(localeDir / "*/") if d.isdir()] # Allow all NVDA's gettext po files to be compiled in source/locale, and manifest files to be generated moByLang: dict[str, FS.File] = {} @@ -95,7 +95,8 @@ for dir in langDirs: moByLang[dir.name] = moFile env.Depends(moTarget, poFile) translatedManifest = env.NVDATranslatedManifest( - dir.File("manifest.ini"), [moFile, "manifest-translated.ini.tpl"] + dir.File("manifest.ini"), + [moFile, "manifest-translated.ini.tpl"], ) env.Depends(translatedManifest, ["buildVars.py"]) env.Depends(addon, [translatedManifest, moTarget]) @@ -116,7 +117,7 @@ if (readmeFile := Path("readme.md")).is_file(): readmeTarget = env.Command(str(readmePath), str(readmeFile), Copy("$TARGET", "$SOURCE")) env.Depends(addon, readmeTarget) -for mdFile in env.Glob(docsDir/"*/*.md"): +for mdFile in env.Glob(docsDir / "*/*.md"): # the title of the html file is translated based on the contents of something in the moFile for a language. # Thus, we find the moFile for this language and depend on it if it exists. lang = mdFile.dir.name @@ -143,7 +144,7 @@ env.Alias("mergePot", mergePot) env.Depends(mergePot, i18nFiles) # Generate Manifest path -manifest = env.NVDAManifest(env.File(addonDir/"manifest.ini"), "manifest.ini.tpl") +manifest = env.NVDAManifest(env.File(addonDir / "manifest.ini"), "manifest.ini.tpl") # Ensure manifest is rebuilt if buildVars is updated. env.Depends(manifest, "buildVars.py") diff --git a/site_scons/site_tools/NVDATool/__init__.py b/site_scons/site_tools/NVDATool/__init__.py index a71857d..7de9357 100644 --- a/site_scons/site_tools/NVDATool/__init__.py +++ b/site_scons/site_tools/NVDATool/__init__.py @@ -34,12 +34,14 @@ def generate(env: Environment): env.SetDefault(excludePatterns=tuple()) addonAction = env.Action( - lambda target, source, env: createAddonBundleFromPath( - source[0].abspath, - target[0].abspath, - env["excludePatterns"], - ) - and None, + lambda target, source, env: ( + createAddonBundleFromPath( + source[0].abspath, + target[0].abspath, + env["excludePatterns"], + ) + and None + ), lambda target, source, env: f"Generating Addon {target[0]}", ) env["BUILDERS"]["NVDAAddon"] = Builder( @@ -53,15 +55,17 @@ def generate(env: Environment): env.SetDefault(speechDictionaries={}) manifestAction = env.Action( - lambda target, source, env: generateManifest( - source[0].abspath, - target[0].abspath, - addon_info=env["addon_info"], - brailleTables=env["brailleTables"], - symbolDictionaries=env["symbolDictionaries"], - speechDictionaries=env["speechDictionaries"], - ) - and None, + lambda target, source, env: ( + generateManifest( + source[0].abspath, + target[0].abspath, + addon_info=env["addon_info"], + brailleTables=env["brailleTables"], + symbolDictionaries=env["symbolDictionaries"], + speechDictionaries=env["speechDictionaries"], + ) + and None + ), lambda target, source, env: f"Generating manifest {target[0]}", ) env["BUILDERS"]["NVDAManifest"] = Builder( @@ -71,16 +75,18 @@ def generate(env: Environment): ) translatedManifestAction = env.Action( - lambda target, source, env: generateTranslatedManifest( - source[1].abspath, - target[0].abspath, - mo=source[0].abspath, - addon_info=env["addon_info"], - brailleTables=env["brailleTables"], - symbolDictionaries=env["symbolDictionaries"], - speechDictionaries=env["speechDictionaries"], - ) - and None, + lambda target, source, env: ( + generateTranslatedManifest( + source[1].abspath, + target[0].abspath, + mo=source[0].abspath, + addon_info=env["addon_info"], + brailleTables=env["brailleTables"], + symbolDictionaries=env["symbolDictionaries"], + speechDictionaries=env["speechDictionaries"], + ) + and None + ), lambda target, source, env: f"Generating translated manifest {target[0]}", ) @@ -93,14 +99,16 @@ def generate(env: Environment): env.SetDefault(mdExtensions={}) mdAction = env.Action( - lambda target, source, env: md2html( - source[0].path, - target[0].path, - moFile=env["moFile"].path if env["moFile"] else None, - mdExtensions=env["mdExtensions"], - addon_info=env["addon_info"], - ) - and None, + lambda target, source, env: ( + md2html( + source[0].path, + target[0].path, + moFile=env["moFile"].path if env["moFile"] else None, + mdExtensions=env["mdExtensions"], + addon_info=env["addon_info"], + ) + and None + ), lambda target, source, env: f"Generating {target[0]}", ) env["BUILDERS"]["md2html"] = env.Builder( From 41ea76a217e904b07165641d5cd5440d4164d7c2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 6 Sep 2026 14:40:14 +0000 Subject: [PATCH 4/4] Disable reportMissingImports and reportUntypedFunctionDecorator in pyright config Co-authored-by: zstanecic <11149715+zstanecic@users.noreply.github.com> --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 473c681..d5c46b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -147,7 +147,6 @@ reportInvalidStubStatement = true reportInvalidTypeVarUse = true reportMatchNotExhaustive = true reportMissingModuleSource = true -reportMissingImports = true reportNoOverloadImplementation = true reportOptionalContextManager = true reportOverlappingOverload = true @@ -164,7 +163,6 @@ reportUnnecessaryCast = true reportUnnecessaryContains = true reportUnnecessaryTypeIgnoreComment = true reportUntypedClassDecorator = true -reportUntypedFunctionDecorator = true reportUnusedClass = true reportUnusedCoroutine = true reportUnusedExcept = true @@ -174,6 +172,8 @@ reportDeprecated = false # Can be enabled by generating type stubs for modules via pyright CLI reportMissingTypeStubs = false +reportMissingImports = false +reportUntypedFunctionDecorator = false # Bad rules # These are roughly sorted by compliance to make it easier for devs to focus on enabling them.