From 9d95d9774188ba0d075025c63a3d14cc541e781b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Tue, 26 Aug 2025 21:53:40 +0200 Subject: [PATCH 01/61] Add changelog --- _tests/testData/addons/fake/13.0.0.json | 3 ++- _tests/testData/fake.nvda-addon | Bin 351 -> 408 bytes _tests/testData/manifest.ini | 1 + _tests/test_validate.py | 32 +++++++++++++++++++++++- _validate/addonManifest.py | 5 +++- _validate/addonVersion_schema.json | 29 +++++++++++++++------ _validate/createJson.py | 2 ++ _validate/regenerateTranslations.py | 3 ++- _validate/validate.py | 10 ++++++++ 9 files changed, 73 insertions(+), 12 deletions(-) diff --git a/_tests/testData/addons/fake/13.0.0.json b/_tests/testData/addons/fake/13.0.0.json index 9c275cd..87bed67 100644 --- a/_tests/testData/addons/fake/13.0.0.json +++ b/_tests/testData/addons/fake/13.0.0.json @@ -8,6 +8,7 @@ }, "displayName": "mock addon", "description": "The description for the addon", + "changelog": "Changes for this add-on version", "homepage": "https://nvaccess.org", "publisher": "Name of addon author or organisation", "minNVDAVersion": { @@ -23,7 +24,7 @@ "channel": "stable", "URL": "https://github.com/nvaccess/dont/use/this/address/fake.nvda-addon", "sha256-comment": "SHA for the fake.nvda-addon file", - "sha256": "e27fa778cb99f83ececeb0bc089033929eab5a2fa475ce63e68f50b03b6ab585", + "sha256": "50a8011a807665bcb8fdd177c276fef3b3f7f754796c5990ebe14e80c28b14ef", "sourceURL": "https://github.com/nvaccess/dont/use/this/address", "license": "GPL v2", "licenseURL": "https://www.gnu.org/licenses/gpl-2.0.html", diff --git a/_tests/testData/fake.nvda-addon b/_tests/testData/fake.nvda-addon index fe805d5b3570ced0ae8ad3f67c0ac9e3ba2cc88c..9b9a07718f187028c2cb15f023591af4b7387141 100644 GIT binary patch literal 408 zcmWIWW@Zs#-~d9IRZ`ImNPveyfgv|BFEcH*xI`~AFSE3Qn}Lx9qyS8WhVU}5YjUj1 zFaY92?%0gf3A?kH4Fz1Q8~-`3IDadyyir6^@oCtxzY1s9wS0{*nRKxJ{ls$4#)ert zzt5}GaCG^)Fm1;|kt<0ppB_XV&&lIjbJo*4aiY)1?5~!k{;#{8zlP5#4xGA`_d<^Z zd*;Cj(|LbXP2Iw7`}K)*bGgowa+avloZ`Ay-cKvDmzVwhD&{e7!TFR0Qx9Z@zxI0H z?!2qn(8Hv_t81^}@8zEho(OOH`H^w?+dEAO%6#jNDY$+)d0cGy>+jFMPM7L`Y%ymE zhr`#VkcGy0z=?o|f9#n(F^fs0VnnbNq5*h`$E(cNilBLx49UlL#{+#E|89 l7$o4~x2+Mx#2bFB42+=g3-D%T1F2;M!XO}R0JMdH0RZ-!k&^%b literal 351 zcmWIWW@Zs#U|`^2nCzS!7W&j7@gR_=%*epN1Eg~k^D@&?i%aw}^D$@nRIg91=q}%MPZ87iP>3`H`+!NE!f^ahf`7Dg4_GW-vioOo?Sju;J9|hQkJjr zWwX0>OMKXuvU;j}k?A@a?{{;yE^l}yI>*~o=SJFwq{d^84uSr*3(rWW%l)YRr{LaH z=fJa8ZxP=a?b None: "language": langCode, "displayName": manifest["summary"], "description": manifest["description"], + "changelog": manifest["changelog"], } ) - + with open(filePath, "wt", encoding="utf-8") as f: json.dump(addonData, f, indent="\t", ensure_ascii=False) print(f"Wrote json file: {filePath}") diff --git a/_validate/validate.py b/_validate/validate.py index 17cd2d7..8338110 100644 --- a/_validate/validate.py +++ b/_validate/validate.py @@ -148,6 +148,15 @@ def checkDescriptionMatches(manifest: AddonManifest, submission: JsonObjT) -> Va f" Instead got: '{submission['description']}'" ) +def checkChangelogMatches(manifest: AddonManifest, submission: JsonObjT) -> ValidationErrorGenerator: + """ The submission changelog must match the *.nvda-addon manifest changelog field.""" + changelog = manifest["changelog"] + if changelog != submission["changelog"]: + yield ( + f"Submission 'changelog' must be set to '{changelog}' in json file." + f" Instead got: '{submission['changelog']}'" + ) + def checkUrlMatchesHomepage(manifest: AddonManifest, submission: JsonObjT) -> ValidationErrorGenerator: """ The submission homepage must match the *.nvda-addon manifest url field. @@ -362,6 +371,7 @@ def validateSubmission(submissionFilePath: str, verFilename: str) -> ValidationE manifest = getAddonManifest(addonDestPath) yield from checkSummaryMatchesDisplayName(manifest, submissionData) yield from checkDescriptionMatches(manifest, submissionData) + yield from checkChangelogMatches(manifest, submissionData) yield from checkUrlMatchesHomepage(manifest, submissionData) yield from checkAddonId(manifest, submissionFilePath, submissionData) yield from checkMinNVDAVersionMatches(manifest, submissionData) From 4a7f9b41af96ef2a45aa51becf9f17ee14536b83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 25 Sep 2025 04:41:50 +0200 Subject: [PATCH 02/61] Add changelog to json schema --- _validate/addonVersion_schema.json | 34 ++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/_validate/addonVersion_schema.json b/_validate/addonVersion_schema.json index 784cca7..8e75028 100644 --- a/_validate/addonVersion_schema.json +++ b/_validate/addonVersion_schema.json @@ -28,12 +28,13 @@ "sourceURL": "https://github.com/nvaccess/addon-datastore/", "license": "GPL v2", "licenseURL": "https://github.com/nvaccess/addon-datastore/license.MD", + "changelog": "New features", "translations": [ { "language": "de", "displayName": "Mein Addon", "description": "erleichtert das Durchführen von xyz", - "changelog": "Eine nette Funktion hinzugefügt" + "changelog": "Neue Funktionen" } ], "reviewUrl": "https://github.com/nvaccess/addon-datastore/discussions/1942#discussioncomment-7453248", @@ -52,7 +53,6 @@ "displayName", "publisher", "description", - "changelog", "minNVDAVersion", "lastTestedVersion", "channel", @@ -118,14 +118,14 @@ "title": "The publisher name for the addon", "type": "string" }, - "changelog": { - "$id": "#/properties/changelog", + "description": { + "$id": "#/properties/description", "default": "", - "description": "The English list of changes for this add-on version.", + "description": "The English description of the addon that will be displayed for the addon.", "examples": [ - "Added a nice feature" + "Makes doing XYZ easier" ], - "title": "The changes for this add-on version (en)", + "title": "The description (en) of the addon", "type": "string" }, "homepage": { @@ -230,6 +230,16 @@ "title": "The URL of the license", "type": "string" }, + "changelog": { + "$id": "#/properties/changelog", + "default": "", + "description": "Changes between the previous and the current version", + "examples": [ + "New feature" + ], + "title": "Add-on changelog (en)", + "type": "string" + }, "legacy": { "$id": "#/properties/legacy", "default": false, @@ -249,7 +259,8 @@ { "language": "de", "displayName": "Mein Addon", - "description": "erleichtert das Durchführen von xyz" + "description": "erleichtert das Durchführen von xyz", + "changelog": "Neue Funktionen" } ] ], @@ -360,7 +371,7 @@ "language": "de", "displayName": "Mein Addon", "description": "erleichtert das Durchführen von xyz", - "changelog": "Eine nette Funktion hinzugefügt" + "changelog": "Neue Funktionen" } ], "required": [ @@ -397,12 +408,13 @@ ], "title": "The translated description", "type": "string" + }, "changelog": { "default": "", - "description": "Translated list of changes for this add-on version.", + "description": "Translated description of changes between the previous and this add-on version", "examples": [ - "Eine nette Funktion hinzugefügt" + "Neue Funktionen" ], "title": "The translated changelog", "type": "string" From 23e4bb46b1fb6fabca973523b5314e2a53472a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 25 Sep 2025 05:35:53 +0200 Subject: [PATCH 03/61] Address code review --- _validate/addonVersion_schema.json | 4 +--- _validate/createJson.py | 6 +++++- _validate/regenerateTranslations.py | 6 +++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/_validate/addonVersion_schema.json b/_validate/addonVersion_schema.json index 8e75028..65abe11 100644 --- a/_validate/addonVersion_schema.json +++ b/_validate/addonVersion_schema.json @@ -28,13 +28,11 @@ "sourceURL": "https://github.com/nvaccess/addon-datastore/", "license": "GPL v2", "licenseURL": "https://github.com/nvaccess/addon-datastore/license.MD", - "changelog": "New features", "translations": [ { "language": "de", "displayName": "Mein Addon", - "description": "erleichtert das Durchführen von xyz", - "changelog": "Neue Funktionen" + "description": "erleichtert das Durchführen von xyz" } ], "reviewUrl": "https://github.com/nvaccess/addon-datastore/discussions/1942#discussioncomment-7453248", diff --git a/_validate/createJson.py b/_validate/createJson.py index 3a328e5..c61d677 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -100,7 +100,6 @@ def _createDictMatchingJsonSchema( "displayName": manifest["summary"], "URL": url, "description": manifest["description"], - "changelog": manifest["changelog"], "sha256": sha, "addonVersionName": manifest["version"], "addonVersionNumber": dataclasses.asdict(addonVersionNumber), @@ -124,6 +123,11 @@ def _createDictMatchingJsonSchema( # The config default is None # which is parsed by configobj as a string not a NoneType addonData["homepage"] = homepage + changelog = manifest.get("changelog") + if changelog and changelog != 'None': + # The config default is None + # which is parsed by configobj as a string not a NoneType + addonData["changelog"] = changelog if licenseUrl: addonData["licenseURL"] = licenseUrl addonData["submissionTime"] = getCurrentTime() diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index 8cb5fcc..2fae71a 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -34,7 +34,11 @@ def regenerateJsonFile(filePath: str, errorFilePath: Optional[str]) -> None: with open(errorFilePath, "w") as errorFile: errorFile.write(f"Validation Errors:\n{manifest.errors}") return - + changelog = manifest["changelog"] + if changelog == 'None': + # The config default is None + # which is parsed by configobj as a string not a NoneType + changelog = '' for langCode, manifest in getAddonManifestLocalizations(manifest): addonData["translations"].append( { From 3ece59fe257ce8a3a02c7f440f2874e81ec1650b Mon Sep 17 00:00:00 2001 From: Sean Budd Date: Thu, 25 Sep 2025 15:19:21 +1000 Subject: [PATCH 04/61] Update _validate/addonVersion_schema.json Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- _validate/addonVersion_schema.json | 1 - 1 file changed, 1 deletion(-) diff --git a/_validate/addonVersion_schema.json b/_validate/addonVersion_schema.json index 65abe11..db14aaf 100644 --- a/_validate/addonVersion_schema.json +++ b/_validate/addonVersion_schema.json @@ -406,7 +406,6 @@ ], "title": "The translated description", "type": "string" - }, "changelog": { "default": "", From 1f5dc75155b4e8f5bcd8659e1d0f166a822fc70a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 25 Sep 2025 07:31:59 +0200 Subject: [PATCH 05/61] Apply suggestions from code review Co-authored-by: Sean Budd --- _validate/addonVersion_schema.json | 3 +-- _validate/regenerateTranslations.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/_validate/addonVersion_schema.json b/_validate/addonVersion_schema.json index db14aaf..c632897 100644 --- a/_validate/addonVersion_schema.json +++ b/_validate/addonVersion_schema.json @@ -375,8 +375,7 @@ "required": [ "language", "displayName", - "description", - "changelog" + "description" ], "properties": { "language": { diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index 2fae71a..cbf096b 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -45,7 +45,7 @@ def regenerateJsonFile(filePath: str, errorFilePath: Optional[str]) -> None: "language": langCode, "displayName": manifest["summary"], "description": manifest["description"], - "changelog": manifest["changelog"], + "changelog": changelog, } ) From d9f3f496463db3c797c9229f1b4df9c76da4d529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 25 Sep 2025 07:39:40 +0200 Subject: [PATCH 06/61] Address review --- _validate/addonVersion_schema.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/_validate/addonVersion_schema.json b/_validate/addonVersion_schema.json index c632897..4e18495 100644 --- a/_validate/addonVersion_schema.json +++ b/_validate/addonVersion_schema.json @@ -28,11 +28,13 @@ "sourceURL": "https://github.com/nvaccess/addon-datastore/", "license": "GPL v2", "licenseURL": "https://github.com/nvaccess/addon-datastore/license.MD", + "changelog": "New features", "translations": [ { "language": "de", "displayName": "Mein Addon", - "description": "erleichtert das Durchführen von xyz" + "description": "erleichtert das Durchführen von xyz", + "changelog": "Neue Funktionen" } ], "reviewUrl": "https://github.com/nvaccess/addon-datastore/discussions/1942#discussioncomment-7453248", From f2efd3054be8a6876361fed86394d7cc0a8326da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 25 Sep 2025 07:53:20 +0200 Subject: [PATCH 07/61] Address review --- _validate/validate.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/_validate/validate.py b/_validate/validate.py index 8338110..c3511e4 100644 --- a/_validate/validate.py +++ b/_validate/validate.py @@ -150,12 +150,13 @@ def checkDescriptionMatches(manifest: AddonManifest, submission: JsonObjT) -> Va def checkChangelogMatches(manifest: AddonManifest, submission: JsonObjT) -> ValidationErrorGenerator: """ The submission changelog must match the *.nvda-addon manifest changelog field.""" - changelog = manifest["changelog"] - if changelog != submission["changelog"]: - yield ( - f"Submission 'changelog' must be set to '{changelog}' in json file." - f" Instead got: '{submission['changelog']}'" - ) + changelog = manifest.get("changelog") + if changelog == 'None': + # The config default is None which is parsed by configobj as a string not a NoneType + changelog = None + if changelog != submission.get("changelog"): + yield f"Submission 'changelog' must be set to '{manifest.get('changelog')}' " \ + f"in json file instead of {submission.get('changelog')}" def checkUrlMatchesHomepage(manifest: AddonManifest, submission: JsonObjT) -> ValidationErrorGenerator: From b0754e6a6c5ef006f18b0868c9542e4ad4bb4cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 25 Sep 2025 07:58:17 +0200 Subject: [PATCH 08/61] Assign None to changelog when appropriate --- _validate/regenerateTranslations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index cbf096b..326e09f 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -34,11 +34,11 @@ def regenerateJsonFile(filePath: str, errorFilePath: Optional[str]) -> None: with open(errorFilePath, "w") as errorFile: errorFile.write(f"Validation Errors:\n{manifest.errors}") return - changelog = manifest["changelog"] + changelog = manifest.get("changelog") if changelog == 'None': # The config default is None # which is parsed by configobj as a string not a NoneType - changelog = '' + changelog = None for langCode, manifest in getAddonManifestLocalizations(manifest): addonData["translations"].append( { From 07d493f3dec2744b479fadce5eacc4284424a6fc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 1 Oct 2025 06:54:53 +0000 Subject: [PATCH 09/61] Pre-commit auto-fix --- _validate/addonManifest.py | 4 ++-- _validate/createJson.py | 6 +++--- _validate/regenerateTranslations.py | 4 ++-- _validate/validate.py | 11 +++++++---- tests/test_validate.py | 12 ++++++------ 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/_validate/addonManifest.py b/_validate/addonManifest.py index 727a008..bc6035c 100644 --- a/_validate/addonManifest.py +++ b/_validate/addonManifest.py @@ -91,8 +91,8 @@ def __init__(self, input: str | TextIOBase, translatedInput: str | None = None): ) self._translatedConfig = None if translatedInput is not None: - self._translatedConfig = ConfigObj(translatedInput, encoding='utf-8', default_encoding='utf-8') - for key in ('summary', 'description', 'changelog'): + self._translatedConfig = ConfigObj(translatedInput, encoding="utf-8", default_encoding="utf-8") + for key in ("summary", "description", "changelog"): val = self._translatedConfig.get(key) if val: self[key] = val diff --git a/_validate/createJson.py b/_validate/createJson.py index ce98013..9762751 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -108,12 +108,12 @@ def _createDataclassMatchingJsonSchema( # Add optional fields homepage = manifest.get("url") - if homepage and homepage != 'None': + if homepage and homepage != "None": # The config default is None # which is parsed by configobj as a string not a NoneType addonData["homepage"] = homepage changelog = manifest.get("changelog") - if changelog and changelog != 'None': + if changelog and changelog != "None": # The config default is None # which is parsed by configobj as a string not a NoneType addonData["changelog"] = changelog @@ -130,7 +130,7 @@ def _createDataclassMatchingJsonSchema( "displayName": manifest["summary"], "description": manifest["description"], "changelog": manifest["changelog"], - } + }, ) except KeyError as e: raise KeyError(f"Translation for {langCode} missing required key '{e.args[0]}'.") from e diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index 9332888..17c28a7 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -24,7 +24,7 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: errorFile.write(f"Validation Errors:\n{manifest.errors}") return changelog = manifest.get("changelog") - if changelog == 'None': + if changelog == "None": # The config default is None # which is parsed by configobj as a string not a NoneType changelog = None @@ -35,7 +35,7 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: "displayName": manifest["summary"], "description": manifest["description"], "changelog": changelog, - } + }, ) with open(filePath, "wt", encoding="utf-8") as f: diff --git a/_validate/validate.py b/_validate/validate.py index 488e46b..3b3c6f4 100644 --- a/_validate/validate.py +++ b/_validate/validate.py @@ -133,15 +133,18 @@ def checkDescriptionMatches(manifest: AddonManifest, submission: JsonObjT) -> Va f" Instead got: '{submission['description']}'" ) + def checkChangelogMatches(manifest: AddonManifest, submission: JsonObjT) -> ValidationErrorGenerator: - """ The submission changelog must match the *.nvda-addon manifest changelog field.""" + """The submission changelog must match the *.nvda-addon manifest changelog field.""" changelog = manifest.get("changelog") - if changelog == 'None': + if changelog == "None": # The config default is None which is parsed by configobj as a string not a NoneType changelog = None if changelog != submission.get("changelog"): - yield f"Submission 'changelog' must be set to '{manifest.get('changelog')}' " \ - f"in json file instead of {submission.get('changelog')}" + yield ( + f"Submission 'changelog' must be set to '{manifest.get('changelog')}' " + f"in json file instead of {submission.get('changelog')}" + ) def checkUrlMatchesHomepage(manifest: AddonManifest, submission: JsonObjT) -> ValidationErrorGenerator: diff --git a/tests/test_validate.py b/tests/test_validate.py index 4744572..4311534 100644 --- a/tests/test_validate.py +++ b/tests/test_validate.py @@ -87,8 +87,8 @@ def test_missingHTTPsAndExt(self): class Validate_checkSha256(unittest.TestCase): - """Tests for the checkSha256 function - """ + """Tests for the checkSha256 function""" + validSha = "50a8011a807665bcb8fdd177c276fef3b3f7f754796c5990ebe14e80c28b14ef" def test_valid(self): @@ -163,7 +163,7 @@ def tearDown(self): def test_valid(self): errors = list( - validate.checkChangelogMatches(self.manifest, self.submissionData) + validate.checkChangelogMatches(self.manifest, self.submissionData), ) self.assertEqual(errors, []) @@ -171,14 +171,14 @@ def test_invalid(self): badChangelog = "bad changelog" self.submissionData["changelog"] = badChangelog errors = list( - validate.checkChangelogMatches(self.manifest, self.submissionData) + validate.checkChangelogMatches(self.manifest, self.submissionData), ) self.assertEqual( errors, [ f"Submission 'changelog' must be set to '{self.manifest['changelog']}' in json file." - f" Instead got: '{badChangelog}'" - ] + f" Instead got: '{badChangelog}'", + ], ) From b921d6f4637399ac7c99fd38beb740e2f16831ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 2 Oct 2025 06:15:46 +0200 Subject: [PATCH 10/61] Fix --- _validate/createJson.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index c6616dc..6d8e5e3 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -127,7 +127,6 @@ def _createDataclassMatchingJsonSchema( translations.append( { "language": langCode, - "changelog": manifest["changelog"], "displayName": cast(str, translatedManifest["summary"]), "description": cast(str, translatedManifest["description"]), "changelog": cast(str, translatedManifest["changelog"]), @@ -153,6 +152,7 @@ def _createDataclassMatchingJsonSchema( sourceURL=sourceUrl, license=licenseName, homepage=homepage, + changelog=changelog, licenseURL=licenseUrl, submissionTime=getCurrentTime(), translations=translations, From ff43517318f1ac6df7bcb22bd865f81eda96a293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 2 Oct 2025 06:26:15 +0200 Subject: [PATCH 11/61] Fix --- _validate/createJson.py | 1 + 1 file changed, 1 insertion(+) diff --git a/_validate/createJson.py b/_validate/createJson.py index 6d8e5e3..79f3df0 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -32,6 +32,7 @@ class AddonData: sourceURL: str license: str homepage: str | None + changelog: str | None licenseURL: str | None submissionTime: int translations: list[dict[str, str]] From aaf2b8541957929411bd07911d0e970e67da29ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 2 Oct 2025 06:32:46 +0200 Subject: [PATCH 12/61] Remove unassigned addonData --- _validate/createJson.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index 79f3df0..6a9089c 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -106,22 +106,9 @@ def _createDataclassMatchingJsonSchema( for key in ("name", "summary", "description", "minimumNVDAVersion", "lastTestedNVDAVersion", "version"): if key not in manifest: raise KeyError(f"Manifest missing required key '{key}'.") - # Add optional fields homepage = manifest.get("url") - if homepage and homepage != "None": - # The config default is None - # which is parsed by configobj as a string not a NoneType - addonData["homepage"] = homepage changelog = manifest.get("changelog") - if changelog and changelog != "None": - # The config default is None - # which is parsed by configobj as a string not a NoneType - addonData["changelog"] = changelog - if licenseUrl: - addonData["licenseURL"] = licenseUrl - addonData["submissionTime"] = getCurrentTime() - translations: list[dict[str, str]] = [] for langCode, translatedManifest in getAddonManifestLocalizations(manifest): try: From 8b1ed2a0f485c63dd81e5d9b0aeb5f8a90d1ca12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 2 Oct 2025 06:41:58 +0200 Subject: [PATCH 13/61] Fix test --- tests/test_createJson.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_createJson.py b/tests/test_createJson.py index 6241bd7..a42f15f 100644 --- a/tests/test_createJson.py +++ b/tests/test_createJson.py @@ -99,6 +99,7 @@ def test_validVersion(self): sourceURL="https://example.com", license="GPL v2", homepage="https://example.com", + changelog="""Changes for this add-on version""", licenseURL="https://www.gnu.org/licenses/gpl-2.0.html", submissionTime=createJson.getCurrentTime(), translations=[], From 38da96d139c8ea6afcc64cc1c03d94147f25d800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 2 Oct 2025 07:01:07 +0200 Subject: [PATCH 14/61] Fix error message --- _validate/validate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_validate/validate.py b/_validate/validate.py index 3b3c6f4..793d7f0 100644 --- a/_validate/validate.py +++ b/_validate/validate.py @@ -142,8 +142,8 @@ def checkChangelogMatches(manifest: AddonManifest, submission: JsonObjT) -> Vali changelog = None if changelog != submission.get("changelog"): yield ( - f"Submission 'changelog' must be set to '{manifest.get('changelog')}' " - f"in json file instead of {submission.get('changelog')}" + f"Submission 'changelog' must be set to '{manifest.get('changelog')}' in json file." + f" Instead got: {submission.get('changelog')}" ) From ecb895730965100042f7d4ae80f02870edd3a50b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 2 Oct 2025 07:09:45 +0200 Subject: [PATCH 15/61] harmonize test for changelog with homepage --- _validate/validate.py | 4 ++-- tests/test_validate.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/_validate/validate.py b/_validate/validate.py index 793d7f0..ca56aa8 100644 --- a/_validate/validate.py +++ b/_validate/validate.py @@ -142,8 +142,8 @@ def checkChangelogMatches(manifest: AddonManifest, submission: JsonObjT) -> Vali changelog = None if changelog != submission.get("changelog"): yield ( - f"Submission 'changelog' must be set to '{manifest.get('changelog')}' in json file." - f" Instead got: {submission.get('changelog')}" + f"Submission 'changelog' must be set to '{manifest.get('changelog')}' " # type: ignore[reportUnknownMemberType] + f"in json file instead of {submission.get('changelog')}" ) diff --git a/tests/test_validate.py b/tests/test_validate.py index 4311534..b7671a9 100644 --- a/tests/test_validate.py +++ b/tests/test_validate.py @@ -176,8 +176,8 @@ def test_invalid(self): self.assertEqual( errors, [ - f"Submission 'changelog' must be set to '{self.manifest['changelog']}' in json file." - f" Instead got: '{badChangelog}'", + f"Submission 'changelog' must be set to '{self.manifest['changelog']}' in json file" + f" instead of '{badChangelog}'", ], ) From 098a48060576b8befbaf358f0265bb8ca7e23233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 2 Oct 2025 07:14:28 +0200 Subject: [PATCH 16/61] Fix test --- tests/test_validate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_validate.py b/tests/test_validate.py index b7671a9..9686c94 100644 --- a/tests/test_validate.py +++ b/tests/test_validate.py @@ -177,7 +177,7 @@ def test_invalid(self): errors, [ f"Submission 'changelog' must be set to '{self.manifest['changelog']}' in json file" - f" instead of '{badChangelog}'", + f" instead of {badChangelog}", ], ) From cbe5d180d7f9a9edb30fc859c8b6c1d3f2223b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 2 Oct 2025 16:18:19 +0200 Subject: [PATCH 17/61] Remove function --- tests/test_validate.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test_validate.py b/tests/test_validate.py index 9686c94..fcab869 100644 --- a/tests/test_validate.py +++ b/tests/test_validate.py @@ -157,10 +157,6 @@ def setUp(self): self.submissionData = getValidAddonSubmission() self.manifest = getAddonManifest() - def tearDown(self): - self.submissionData = None - self.manifest = None - def test_valid(self): errors = list( validate.checkChangelogMatches(self.manifest, self.submissionData), From c93e4a5dfc6aedf5018c3ef8bc1ed22a54c850a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 2 Oct 2025 16:19:03 +0200 Subject: [PATCH 18/61] Commend python preference to test locally --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 5b548ff..d294358 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,7 +67,7 @@ reportMissingTypeStubs = false [tool.uv] default-groups = "all" -python-preference = "only-system" +#python-preference = "only-system" environments = ["sys_platform == 'win32'"] required-version = ">=0.8" From a0b53f8dd187091742fe7a5cb080ad085a03a02b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Thu, 2 Oct 2025 16:31:43 +0200 Subject: [PATCH 19/61] Lint fixes --- _validate/createJson.py | 4 ++-- pyproject.toml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index 6a9089c..a2e87bb 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -109,7 +109,7 @@ def _createDataclassMatchingJsonSchema( # Add optional fields homepage = manifest.get("url") changelog = manifest.get("changelog") - translations: list[dict[str, str]] = [] + translations: list[dict[str, str | None]] = [] for langCode, translatedManifest in getAddonManifestLocalizations(manifest): try: translations.append( @@ -117,7 +117,7 @@ def _createDataclassMatchingJsonSchema( "language": langCode, "displayName": cast(str, translatedManifest["summary"]), "description": cast(str, translatedManifest["description"]), - "changelog": cast(str, translatedManifest["changelog"]), + "changelog": translatedManifest["changelog"], }, ) except KeyError as e: diff --git a/pyproject.toml b/pyproject.toml index d294358..3226f4b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,6 +64,8 @@ strictSetInference = true # ignore configobj reportMissingTypeStubs = false +reportUnknownVariableType = false +reportUnknownMemberType = false [tool.uv] default-groups = "all" From a35e5db93263a59bd9adbec4d31eeebffaf3ddfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Fri, 3 Oct 2025 05:28:17 +0200 Subject: [PATCH 20/61] Add translated changelog optional and fix linting errors by casting to str --- _validate/createJson.py | 16 ++++++++++++---- _validate/regenerateTranslations.py | 9 ++++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index a2e87bb..21e0568 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -109,7 +109,7 @@ def _createDataclassMatchingJsonSchema( # Add optional fields homepage = manifest.get("url") changelog = manifest.get("changelog") - translations: list[dict[str, str | None]] = [] + translations: list[dict[str, str]] = [] for langCode, translatedManifest in getAddonManifestLocalizations(manifest): try: translations.append( @@ -117,12 +117,20 @@ def _createDataclassMatchingJsonSchema( "language": langCode, "displayName": cast(str, translatedManifest["summary"]), "description": cast(str, translatedManifest["description"]), - "changelog": translatedManifest["changelog"], }, ) except KeyError as e: raise KeyError(f"Translation for {langCode} missing required key '{e.args[0]}'.") from e + # Add optional translated changelog. + translatedChangelog = translatedManifest.get("changelog") + if translatedChangelog: + translations.append( + { + "changelog": cast(str, translatedChangelog), + }, + ) + addonData = AddonData( addonId=cast(str, manifest["name"]), displayName=cast(str, manifest["summary"]), @@ -139,8 +147,8 @@ def _createDataclassMatchingJsonSchema( publisher=publisher, sourceURL=sourceUrl, license=licenseName, - homepage=homepage, - changelog=changelog, + homepage=cast(str, homepage), + changelog=cast(str, changelog), licenseURL=licenseUrl, submissionTime=getCurrentTime(), translations=translations, diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index 17c28a7..9ad7792 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -34,10 +34,17 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: "language": langCode, "displayName": manifest["summary"], "description": manifest["description"], - "changelog": changelog, }, ) + translatedChangelog = manifest.get("changelog") + if translatedChangelog: + addonData["translations"].append( + { + "changelog": translatedChangelog, + }, + ) + with open(filePath, "wt", encoding="utf-8") as f: json.dump(addonData, f, indent="\t", ensure_ascii=False) print(f"Wrote json file: {filePath}") From 35298589a28a9502264c3194412b2eb76f2d7871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 4 Oct 2025 12:49:53 +0200 Subject: [PATCH 21/61] Fix pyproject --- pyproject.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3226f4b..f86ccfb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -64,12 +64,9 @@ strictSetInference = true # ignore configobj reportMissingTypeStubs = false -reportUnknownVariableType = false -reportUnknownMemberType = false [tool.uv] default-groups = "all" -#python-preference = "only-system" environments = ["sys_platform == 'win32'"] required-version = ">=0.8" From c816603f72c1d0122afe06e60b405c52c88087d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 4 Oct 2025 13:05:52 +0200 Subject: [PATCH 22/61] Add ignore type comments --- _validate/addonManifest.py | 2 +- _validate/createJson.py | 6 +++--- _validate/regenerateTranslations.py | 4 ++-- _validate/validate.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/_validate/addonManifest.py b/_validate/addonManifest.py index bc6035c..a619e10 100644 --- a/_validate/addonManifest.py +++ b/_validate/addonManifest.py @@ -93,7 +93,7 @@ def __init__(self, input: str | TextIOBase, translatedInput: str | None = None): if translatedInput is not None: self._translatedConfig = ConfigObj(translatedInput, encoding="utf-8", default_encoding="utf-8") for key in ("summary", "description", "changelog"): - val = self._translatedConfig.get(key) + val = self._translatedConfig.get(key) # type: ignore[reportUnknownMemberType] if val: self[key] = val diff --git a/_validate/createJson.py b/_validate/createJson.py index 21e0568..0063237 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -107,8 +107,8 @@ def _createDataclassMatchingJsonSchema( if key not in manifest: raise KeyError(f"Manifest missing required key '{key}'.") # Add optional fields - homepage = manifest.get("url") - changelog = manifest.get("changelog") + homepage = manifest.get("url") # type: ignore[reportUnknownMemberType] + changelog = manifest.get("changelog") # type: ignore[reportUnknownMemberType] translations: list[dict[str, str]] = [] for langCode, translatedManifest in getAddonManifestLocalizations(manifest): try: @@ -123,7 +123,7 @@ def _createDataclassMatchingJsonSchema( raise KeyError(f"Translation for {langCode} missing required key '{e.args[0]}'.") from e # Add optional translated changelog. - translatedChangelog = translatedManifest.get("changelog") + translatedChangelog = translatedManifest.get("changelog") # type: ignore[reportUnknownMemberType] if translatedChangelog: translations.append( { diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index 9ad7792..9ab300c 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -23,7 +23,7 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: with open(errorFilePath, "w") as errorFile: errorFile.write(f"Validation Errors:\n{manifest.errors}") return - changelog = manifest.get("changelog") + changelog = manifest.get("changelog") # type: ignore[reportUnknownMemberType] if changelog == "None": # The config default is None # which is parsed by configobj as a string not a NoneType @@ -37,7 +37,7 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: }, ) - translatedChangelog = manifest.get("changelog") + translatedChangelog = manifest.get("changelog") # type: ignore[reportUnknownMemberType] if translatedChangelog: addonData["translations"].append( { diff --git a/_validate/validate.py b/_validate/validate.py index ca56aa8..18912a7 100644 --- a/_validate/validate.py +++ b/_validate/validate.py @@ -135,7 +135,7 @@ def checkDescriptionMatches(manifest: AddonManifest, submission: JsonObjT) -> Va def checkChangelogMatches(manifest: AddonManifest, submission: JsonObjT) -> ValidationErrorGenerator: - """The submission changelog must match the *.nvda-addon manifest changelog field.""" + """The submission changelog must match the *.nvda-addon manifest changelog field.""" # type: ignore[reportUnknownMemberType] changelog = manifest.get("changelog") if changelog == "None": # The config default is None which is parsed by configobj as a string not a NoneType From 288ea2f7fc3c696e783ddd90fa2cba391ad64f4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 4 Oct 2025 13:08:58 +0200 Subject: [PATCH 23/61] Add ignore type comment --- _validate/validate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_validate/validate.py b/_validate/validate.py index 18912a7..fe301f8 100644 --- a/_validate/validate.py +++ b/_validate/validate.py @@ -135,8 +135,8 @@ def checkDescriptionMatches(manifest: AddonManifest, submission: JsonObjT) -> Va def checkChangelogMatches(manifest: AddonManifest, submission: JsonObjT) -> ValidationErrorGenerator: - """The submission changelog must match the *.nvda-addon manifest changelog field.""" # type: ignore[reportUnknownMemberType] - changelog = manifest.get("changelog") + """The submission changelog must match the *.nvda-addon manifest changelog field.""" + changelog = manifest.get("changelog") # type: ignore[reportUnknownMemberType] if changelog == "None": # The config default is None which is parsed by configobj as a string not a NoneType changelog = None From 40274ddf925a629ba4957ee5266bff623b26a1c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Tue, 7 Oct 2025 03:52:46 +0200 Subject: [PATCH 24/61] Address review --- _validate/createJson.py | 4 +- addons/testChangelog/13.0.0.json | 38 ++ nvdaAPIVersions.json | 640 +++++++++++++++++++++++++++++++ 3 files changed, 680 insertions(+), 2 deletions(-) create mode 100644 addons/testChangelog/13.0.0.json create mode 100644 nvdaAPIVersions.json diff --git a/_validate/createJson.py b/_validate/createJson.py index 0063237..2527fdb 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -147,8 +147,8 @@ def _createDataclassMatchingJsonSchema( publisher=publisher, sourceURL=sourceUrl, license=licenseName, - homepage=cast(str, homepage), - changelog=cast(str, changelog), + homepage=homepage, + changelog=changelog, licenseURL=licenseUrl, submissionTime=getCurrentTime(), translations=translations, diff --git a/addons/testChangelog/13.0.0.json b/addons/testChangelog/13.0.0.json new file mode 100644 index 0000000..1c7b3ed --- /dev/null +++ b/addons/testChangelog/13.0.0.json @@ -0,0 +1,38 @@ +{ + "addonId": "testChangelog", + "displayName": "Test Changelog", + "URL": "https://github.com/nvdaes/testing/releases/download/v0.0.0/testChangelog.nvda-addon", + "description": "The description for the addon", + "sha256": "34470a290ab89c2994aef2e45a5aa6989b6fb5b95d3bb1071eacc963d0d88b83", + "addonVersionName": "13.0", + "addonVersionNumber": { + "major": 13, + "minor": 0, + "patch": 0 + }, + "minNVDAVersion": { + "major": 2022, + "minor": 1, + "patch": 0 + }, + "lastTestedVersion": { + "major": 2026, + "minor": 1, + "patch": 0 + }, + "channel": "dev", + "publisher": "nvdaes", + "sourceURL": "https://github.com/nvdaes", + "license": "GPL v2", + "homepage": "https://github.com/nvdaes", + "changelog": "* Some changes for this add-on version.\n* More changes.", + "licenseURL": "https://www.gnu.org/licenses/gpl-2.0.html", + "submissionTime": 1759463377000, + "translations": [ + { + "language": "es", + "displayName": "Probar Registro de cambios", + "description": "La descripción para el complemento" + } + ] +} \ No newline at end of file diff --git a/nvdaAPIVersions.json b/nvdaAPIVersions.json new file mode 100644 index 0000000..214241f --- /dev/null +++ b/nvdaAPIVersions.json @@ -0,0 +1,640 @@ +[ + { + "description": "NVDA 2018.4.1 and earlier", + "apiVer": { + "major": 0, + "minor": 0, + "patch": 0 + }, + "backCompatTo": { + "major": 0, + "minor": 0, + "patch": 0 + } + }, + { + "description": "NVDA 2019.1", + "apiVer": { + "major": 2019, + "minor": 1, + "patch": 0 + }, + "backCompatTo": { + "major": 0, + "minor": 0, + "patch": 0 + } + }, + { + "description": "NVDA 2019.1.1", + "apiVer": { + "major": 2019, + "minor": 1, + "patch": 1 + }, + "backCompatTo": { + "major": 0, + "minor": 0, + "patch": 0 + } + }, + { + "description": "NVDA 2019.2", + "apiVer": { + "major": 2019, + "minor": 2, + "patch": 0 + }, + "backCompatTo": { + "major": 0, + "minor": 0, + "patch": 0 + } + }, + { + "description": "NVDA 2019.2.1", + "apiVer": { + "major": 2019, + "minor": 2, + "patch": 1 + }, + "backCompatTo": { + "major": 0, + "minor": 0, + "patch": 0 + } + }, + { + "description": "NVDA 2019.3 and NVDA 2019.3.1", + "apiVer": { + "major": 2019, + "minor": 3, + "patch": 0 + }, + "backCompatTo": { + "major": 2019, + "minor": 3, + "patch": 0 + } + }, + { + "description": "NVDA 2020.1", + "apiVer": { + "major": 2020, + "minor": 1, + "patch": 0 + }, + "backCompatTo": { + "major": 2019, + "minor": 3, + "patch": 0 + } + }, + { + "description": "NVDA 2020.2", + "apiVer": { + "major": 2020, + "minor": 2, + "patch": 0 + }, + "backCompatTo": { + "major": 2019, + "minor": 3, + "patch": 0 + } + }, + { + "description": "NVDA 2020.3", + "apiVer": { + "major": 2020, + "minor": 3, + "patch": 0 + }, + "backCompatTo": { + "major": 2019, + "minor": 3, + "patch": 0 + } + }, + { + "description": "NVDA 2020.4", + "apiVer": { + "major": 2020, + "minor": 4, + "patch": 0 + }, + "backCompatTo": { + "major": 2019, + "minor": 3, + "patch": 0 + } + }, + { + "description": "NVDA 2021.1", + "apiVer": { + "major": 2021, + "minor": 1, + "patch": 0 + }, + "backCompatTo": { + "major": 2021, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2021.2", + "apiVer": { + "major": 2021, + "minor": 2, + "patch": 0 + }, + "backCompatTo": { + "major": 2021, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2021.3", + "apiVer": { + "major": 2021, + "minor": 3, + "patch": 0 + }, + "backCompatTo": { + "major": 2021, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2021.3.1", + "apiVer": { + "major": 2021, + "minor": 3, + "patch": 1 + }, + "backCompatTo": { + "major": 2021, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2021.3.2", + "apiVer": { + "major": 2021, + "minor": 3, + "patch": 2 + }, + "backCompatTo": { + "major": 2021, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2021.3.3", + "apiVer": { + "major": 2021, + "minor": 3, + "patch": 3 + }, + "backCompatTo": { + "major": 2021, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2021.3.4", + "apiVer": { + "major": 2021, + "minor": 3, + "patch": 4 + }, + "backCompatTo": { + "major": 2021, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2021.3.5", + "apiVer": { + "major": 2021, + "minor": 3, + "patch": 5 + }, + "backCompatTo": { + "major": 2021, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2022.1", + "apiVer": { + "major": 2022, + "minor": 1, + "patch": 0 + }, + "backCompatTo": { + "major": 2022, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2022.2", + "apiVer": { + "major": 2022, + "minor": 2, + "patch": 0 + }, + "backCompatTo": { + "major": 2022, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2022.2.1", + "apiVer": { + "major": 2022, + "minor": 2, + "patch": 1 + }, + "backCompatTo": { + "major": 2022, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2022.2.2", + "apiVer": { + "major": 2022, + "minor": 2, + "patch": 2 + }, + "backCompatTo": { + "major": 2022, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2022.2.3", + "apiVer": { + "major": 2022, + "minor": 2, + "patch": 3 + }, + "backCompatTo": { + "major": 2022, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2022.2.4", + "apiVer": { + "major": 2022, + "minor": 2, + "patch": 4 + }, + "backCompatTo": { + "major": 2022, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2022.3", + "apiVer": { + "major": 2022, + "minor": 3, + "patch": 0 + }, + "backCompatTo": { + "major": 2022, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2022.3.1", + "apiVer": { + "major": 2022, + "minor": 3, + "patch": 1 + }, + "backCompatTo": { + "major": 2022, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2022.3.2", + "apiVer": { + "major": 2022, + "minor": 3, + "patch": 2 + }, + "backCompatTo": { + "major": 2022, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2022.3.3", + "apiVer": { + "major": 2022, + "minor": 3, + "patch": 3 + }, + "backCompatTo": { + "major": 2022, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2022.4", + "apiVer": { + "major": 2022, + "minor": 4, + "patch": 0 + }, + "backCompatTo": { + "major": 2022, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2023.1", + "apiVer": { + "major": 2023, + "minor": 1, + "patch": 0 + }, + "backCompatTo": { + "major": 2023, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2023.2", + "apiVer": { + "major": 2023, + "minor": 2, + "patch": 0 + }, + "backCompatTo": { + "major": 2023, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2023.3", + "apiVer": { + "major": 2023, + "minor": 3, + "patch": 0 + }, + "backCompatTo": { + "major": 2023, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2023.3.1", + "apiVer": { + "major": 2023, + "minor": 3, + "patch": 1 + }, + "backCompatTo": { + "major": 2023, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2023.3.2", + "apiVer": { + "major": 2023, + "minor": 3, + "patch": 2 + }, + "backCompatTo": { + "major": 2023, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2023.3.3", + "apiVer": { + "major": 2023, + "minor": 3, + "patch": 3 + }, + "backCompatTo": { + "major": 2023, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2023.3.4", + "apiVer": { + "major": 2023, + "minor": 3, + "patch": 4 + }, + "backCompatTo": { + "major": 2023, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2024.1", + "apiVer": { + "major": 2024, + "minor": 1, + "patch": 0 + }, + "backCompatTo": { + "major": 2024, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2024.2", + "apiVer": { + "major": 2024, + "minor": 2, + "patch": 0 + }, + "backCompatTo": { + "major": 2024, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2024.3", + "apiVer": { + "major": 2024, + "minor": 3, + "patch": 0 + }, + "backCompatTo": { + "major": 2024, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2024.3.1", + "apiVer": { + "major": 2024, + "minor": 3, + "patch": 1 + }, + "backCompatTo": { + "major": 2024, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2024.4", + "apiVer": { + "major": 2024, + "minor": 4, + "patch": 0 + }, + "backCompatTo": { + "major": 2024, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2024.4.1", + "apiVer": { + "major": 2024, + "minor": 4, + "patch": 1 + }, + "backCompatTo": { + "major": 2024, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2024.4.2", + "apiVer": { + "major": 2024, + "minor": 4, + "patch": 2 + }, + "backCompatTo": { + "major": 2024, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2025.1", + "apiVer": { + "major": 2025, + "minor": 1, + "patch": 0 + }, + "backCompatTo": { + "major": 2025, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2025.1.1", + "apiVer": { + "major": 2025, + "minor": 1, + "patch": 1 + }, + "backCompatTo": { + "major": 2025, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2025.1.2", + "apiVer": { + "major": 2025, + "minor": 1, + "patch": 2 + }, + "backCompatTo": { + "major": 2025, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2025.2", + "apiVer": { + "major": 2025, + "minor": 2, + "patch": 0 + }, + "backCompatTo": { + "major": 2025, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2025.3", + "apiVer": { + "major": 2025, + "minor": 3, + "patch": 0 + }, + "backCompatTo": { + "major": 2025, + "minor": 1, + "patch": 0 + } + }, + { + "description": "NVDA 2026.1", + "apiVer": { + "major": 2026, + "minor": 1, + "patch": 0 + }, + "backCompatTo": { + "major": 2026, + "minor": 1, + "patch": 0 + }, + "experimental": true + } +] From f7765457c83ac6a9de98b4b074fa12583258749a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Tue, 7 Oct 2025 03:55:32 +0200 Subject: [PATCH 25/61] Address review --- _validate/createJson.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index 2527fdb..a89fd92 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -147,8 +147,8 @@ def _createDataclassMatchingJsonSchema( publisher=publisher, sourceURL=sourceUrl, license=licenseName, - homepage=homepage, - changelog=changelog, + homepage=homepage, # type: ignore[reportUnknownMemberType] + changelog=changelog, # type: ignore[reportUnknownMemberType] licenseURL=licenseUrl, submissionTime=getCurrentTime(), translations=translations, From ebe905af1df8542b9d4bf82cc9c22c9deff2b459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Tue, 7 Oct 2025 04:50:52 +0200 Subject: [PATCH 26/61] Remove accidentally committed files --- addons/testChangelog/13.0.0.json | 38 -- nvdaAPIVersions.json | 640 ------------------------------- 2 files changed, 678 deletions(-) delete mode 100644 addons/testChangelog/13.0.0.json delete mode 100644 nvdaAPIVersions.json diff --git a/addons/testChangelog/13.0.0.json b/addons/testChangelog/13.0.0.json deleted file mode 100644 index 1c7b3ed..0000000 --- a/addons/testChangelog/13.0.0.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "addonId": "testChangelog", - "displayName": "Test Changelog", - "URL": "https://github.com/nvdaes/testing/releases/download/v0.0.0/testChangelog.nvda-addon", - "description": "The description for the addon", - "sha256": "34470a290ab89c2994aef2e45a5aa6989b6fb5b95d3bb1071eacc963d0d88b83", - "addonVersionName": "13.0", - "addonVersionNumber": { - "major": 13, - "minor": 0, - "patch": 0 - }, - "minNVDAVersion": { - "major": 2022, - "minor": 1, - "patch": 0 - }, - "lastTestedVersion": { - "major": 2026, - "minor": 1, - "patch": 0 - }, - "channel": "dev", - "publisher": "nvdaes", - "sourceURL": "https://github.com/nvdaes", - "license": "GPL v2", - "homepage": "https://github.com/nvdaes", - "changelog": "* Some changes for this add-on version.\n* More changes.", - "licenseURL": "https://www.gnu.org/licenses/gpl-2.0.html", - "submissionTime": 1759463377000, - "translations": [ - { - "language": "es", - "displayName": "Probar Registro de cambios", - "description": "La descripción para el complemento" - } - ] -} \ No newline at end of file diff --git a/nvdaAPIVersions.json b/nvdaAPIVersions.json deleted file mode 100644 index 214241f..0000000 --- a/nvdaAPIVersions.json +++ /dev/null @@ -1,640 +0,0 @@ -[ - { - "description": "NVDA 2018.4.1 and earlier", - "apiVer": { - "major": 0, - "minor": 0, - "patch": 0 - }, - "backCompatTo": { - "major": 0, - "minor": 0, - "patch": 0 - } - }, - { - "description": "NVDA 2019.1", - "apiVer": { - "major": 2019, - "minor": 1, - "patch": 0 - }, - "backCompatTo": { - "major": 0, - "minor": 0, - "patch": 0 - } - }, - { - "description": "NVDA 2019.1.1", - "apiVer": { - "major": 2019, - "minor": 1, - "patch": 1 - }, - "backCompatTo": { - "major": 0, - "minor": 0, - "patch": 0 - } - }, - { - "description": "NVDA 2019.2", - "apiVer": { - "major": 2019, - "minor": 2, - "patch": 0 - }, - "backCompatTo": { - "major": 0, - "minor": 0, - "patch": 0 - } - }, - { - "description": "NVDA 2019.2.1", - "apiVer": { - "major": 2019, - "minor": 2, - "patch": 1 - }, - "backCompatTo": { - "major": 0, - "minor": 0, - "patch": 0 - } - }, - { - "description": "NVDA 2019.3 and NVDA 2019.3.1", - "apiVer": { - "major": 2019, - "minor": 3, - "patch": 0 - }, - "backCompatTo": { - "major": 2019, - "minor": 3, - "patch": 0 - } - }, - { - "description": "NVDA 2020.1", - "apiVer": { - "major": 2020, - "minor": 1, - "patch": 0 - }, - "backCompatTo": { - "major": 2019, - "minor": 3, - "patch": 0 - } - }, - { - "description": "NVDA 2020.2", - "apiVer": { - "major": 2020, - "minor": 2, - "patch": 0 - }, - "backCompatTo": { - "major": 2019, - "minor": 3, - "patch": 0 - } - }, - { - "description": "NVDA 2020.3", - "apiVer": { - "major": 2020, - "minor": 3, - "patch": 0 - }, - "backCompatTo": { - "major": 2019, - "minor": 3, - "patch": 0 - } - }, - { - "description": "NVDA 2020.4", - "apiVer": { - "major": 2020, - "minor": 4, - "patch": 0 - }, - "backCompatTo": { - "major": 2019, - "minor": 3, - "patch": 0 - } - }, - { - "description": "NVDA 2021.1", - "apiVer": { - "major": 2021, - "minor": 1, - "patch": 0 - }, - "backCompatTo": { - "major": 2021, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2021.2", - "apiVer": { - "major": 2021, - "minor": 2, - "patch": 0 - }, - "backCompatTo": { - "major": 2021, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2021.3", - "apiVer": { - "major": 2021, - "minor": 3, - "patch": 0 - }, - "backCompatTo": { - "major": 2021, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2021.3.1", - "apiVer": { - "major": 2021, - "minor": 3, - "patch": 1 - }, - "backCompatTo": { - "major": 2021, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2021.3.2", - "apiVer": { - "major": 2021, - "minor": 3, - "patch": 2 - }, - "backCompatTo": { - "major": 2021, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2021.3.3", - "apiVer": { - "major": 2021, - "minor": 3, - "patch": 3 - }, - "backCompatTo": { - "major": 2021, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2021.3.4", - "apiVer": { - "major": 2021, - "minor": 3, - "patch": 4 - }, - "backCompatTo": { - "major": 2021, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2021.3.5", - "apiVer": { - "major": 2021, - "minor": 3, - "patch": 5 - }, - "backCompatTo": { - "major": 2021, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2022.1", - "apiVer": { - "major": 2022, - "minor": 1, - "patch": 0 - }, - "backCompatTo": { - "major": 2022, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2022.2", - "apiVer": { - "major": 2022, - "minor": 2, - "patch": 0 - }, - "backCompatTo": { - "major": 2022, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2022.2.1", - "apiVer": { - "major": 2022, - "minor": 2, - "patch": 1 - }, - "backCompatTo": { - "major": 2022, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2022.2.2", - "apiVer": { - "major": 2022, - "minor": 2, - "patch": 2 - }, - "backCompatTo": { - "major": 2022, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2022.2.3", - "apiVer": { - "major": 2022, - "minor": 2, - "patch": 3 - }, - "backCompatTo": { - "major": 2022, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2022.2.4", - "apiVer": { - "major": 2022, - "minor": 2, - "patch": 4 - }, - "backCompatTo": { - "major": 2022, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2022.3", - "apiVer": { - "major": 2022, - "minor": 3, - "patch": 0 - }, - "backCompatTo": { - "major": 2022, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2022.3.1", - "apiVer": { - "major": 2022, - "minor": 3, - "patch": 1 - }, - "backCompatTo": { - "major": 2022, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2022.3.2", - "apiVer": { - "major": 2022, - "minor": 3, - "patch": 2 - }, - "backCompatTo": { - "major": 2022, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2022.3.3", - "apiVer": { - "major": 2022, - "minor": 3, - "patch": 3 - }, - "backCompatTo": { - "major": 2022, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2022.4", - "apiVer": { - "major": 2022, - "minor": 4, - "patch": 0 - }, - "backCompatTo": { - "major": 2022, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2023.1", - "apiVer": { - "major": 2023, - "minor": 1, - "patch": 0 - }, - "backCompatTo": { - "major": 2023, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2023.2", - "apiVer": { - "major": 2023, - "minor": 2, - "patch": 0 - }, - "backCompatTo": { - "major": 2023, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2023.3", - "apiVer": { - "major": 2023, - "minor": 3, - "patch": 0 - }, - "backCompatTo": { - "major": 2023, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2023.3.1", - "apiVer": { - "major": 2023, - "minor": 3, - "patch": 1 - }, - "backCompatTo": { - "major": 2023, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2023.3.2", - "apiVer": { - "major": 2023, - "minor": 3, - "patch": 2 - }, - "backCompatTo": { - "major": 2023, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2023.3.3", - "apiVer": { - "major": 2023, - "minor": 3, - "patch": 3 - }, - "backCompatTo": { - "major": 2023, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2023.3.4", - "apiVer": { - "major": 2023, - "minor": 3, - "patch": 4 - }, - "backCompatTo": { - "major": 2023, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2024.1", - "apiVer": { - "major": 2024, - "minor": 1, - "patch": 0 - }, - "backCompatTo": { - "major": 2024, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2024.2", - "apiVer": { - "major": 2024, - "minor": 2, - "patch": 0 - }, - "backCompatTo": { - "major": 2024, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2024.3", - "apiVer": { - "major": 2024, - "minor": 3, - "patch": 0 - }, - "backCompatTo": { - "major": 2024, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2024.3.1", - "apiVer": { - "major": 2024, - "minor": 3, - "patch": 1 - }, - "backCompatTo": { - "major": 2024, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2024.4", - "apiVer": { - "major": 2024, - "minor": 4, - "patch": 0 - }, - "backCompatTo": { - "major": 2024, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2024.4.1", - "apiVer": { - "major": 2024, - "minor": 4, - "patch": 1 - }, - "backCompatTo": { - "major": 2024, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2024.4.2", - "apiVer": { - "major": 2024, - "minor": 4, - "patch": 2 - }, - "backCompatTo": { - "major": 2024, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2025.1", - "apiVer": { - "major": 2025, - "minor": 1, - "patch": 0 - }, - "backCompatTo": { - "major": 2025, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2025.1.1", - "apiVer": { - "major": 2025, - "minor": 1, - "patch": 1 - }, - "backCompatTo": { - "major": 2025, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2025.1.2", - "apiVer": { - "major": 2025, - "minor": 1, - "patch": 2 - }, - "backCompatTo": { - "major": 2025, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2025.2", - "apiVer": { - "major": 2025, - "minor": 2, - "patch": 0 - }, - "backCompatTo": { - "major": 2025, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2025.3", - "apiVer": { - "major": 2025, - "minor": 3, - "patch": 0 - }, - "backCompatTo": { - "major": 2025, - "minor": 1, - "patch": 0 - } - }, - { - "description": "NVDA 2026.1", - "apiVer": { - "major": 2026, - "minor": 1, - "patch": 0 - }, - "backCompatTo": { - "major": 2026, - "minor": 1, - "patch": 0 - }, - "experimental": true - } -] From 75d6e0d6d1a8bcf9c7e0138d6ec0ef1dae463859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Tue, 7 Oct 2025 05:07:24 +0200 Subject: [PATCH 27/61] Try to ensure that homepage and changelog are str or None --- _validate/createJson.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index a89fd92..ec218bb 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -108,7 +108,15 @@ def _createDataclassMatchingJsonSchema( raise KeyError(f"Manifest missing required key '{key}'.") # Add optional fields homepage = manifest.get("url") # type: ignore[reportUnknownMemberType] + if homepage == "None": + # The config default is None + # which is parsed by configobj as a string not a NoneType + homepage = None changelog = manifest.get("changelog") # type: ignore[reportUnknownMemberType] + if changelog == "None": + # The config default is None + # which is parsed by configobj as a string not a NoneType + changelog = None translations: list[dict[str, str]] = [] for langCode, translatedManifest in getAddonManifestLocalizations(manifest): try: @@ -147,8 +155,8 @@ def _createDataclassMatchingJsonSchema( publisher=publisher, sourceURL=sourceUrl, license=licenseName, - homepage=homepage, # type: ignore[reportUnknownMemberType] - changelog=changelog, # type: ignore[reportUnknownMemberType] + homepage=homepage, + changelog=changelog, licenseURL=licenseUrl, submissionTime=getCurrentTime(), translations=translations, From bb03c8316ecbc0d412fa72d50558015d4f90e533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Tue, 7 Oct 2025 21:39:56 +0200 Subject: [PATCH 28/61] Address feedback --- _validate/createJson.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index ec218bb..0d06f2b 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -132,10 +132,14 @@ def _createDataclassMatchingJsonSchema( # Add optional translated changelog. translatedChangelog = translatedManifest.get("changelog") # type: ignore[reportUnknownMemberType] + if translatedChangelog == "None": + # The config default is None + # which is parsed by configobj as a string not a NoneType + translatedChangelog = None if translatedChangelog: translations.append( { - "changelog": cast(str, translatedChangelog), + "changelog": translatedChangelog, }, ) From cd3e0a43bb7f07c3043424ba084c5a678a60b591 Mon Sep 17 00:00:00 2001 From: Sean Budd Date: Fri, 10 Oct 2025 13:26:46 +1100 Subject: [PATCH 29/61] Apply suggestions from code review --- _validate/addonManifest.py | 2 +- _validate/createJson.py | 1 + _validate/regenerateTranslations.py | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/_validate/addonManifest.py b/_validate/addonManifest.py index a619e10..27ab13f 100644 --- a/_validate/addonManifest.py +++ b/_validate/addonManifest.py @@ -93,7 +93,7 @@ def __init__(self, input: str | TextIOBase, translatedInput: str | None = None): if translatedInput is not None: self._translatedConfig = ConfigObj(translatedInput, encoding="utf-8", default_encoding="utf-8") for key in ("summary", "description", "changelog"): - val = self._translatedConfig.get(key) # type: ignore[reportUnknownMemberType] + val: str | None = self._translatedConfig.get(key) # type: ignore[reportUnknownMemberType] if val: self[key] = val diff --git a/_validate/createJson.py b/_validate/createJson.py index 0d06f2b..f4b666d 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -106,6 +106,7 @@ def _createDataclassMatchingJsonSchema( for key in ("name", "summary", "description", "minimumNVDAVersion", "lastTestedNVDAVersion", "version"): if key not in manifest: raise KeyError(f"Manifest missing required key '{key}'.") + # Add optional fields homepage = manifest.get("url") # type: ignore[reportUnknownMemberType] if homepage == "None": diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index 9ab300c..566f538 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -38,6 +38,10 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: ) translatedChangelog = manifest.get("changelog") # type: ignore[reportUnknownMemberType] + if translatedChangelog == "None": + # The config default is None + # which is parsed by configobj as a string not a NoneType + translatedChangelog = None if translatedChangelog: addonData["translations"].append( { From 006412032ddc2ed00bb9cee0b7c83014ab39b75f Mon Sep 17 00:00:00 2001 From: Sean Budd Date: Fri, 10 Oct 2025 13:32:41 +1100 Subject: [PATCH 30/61] Apply suggestions from code review --- _validate/createJson.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index f4b666d..65b9d96 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -118,7 +118,7 @@ def _createDataclassMatchingJsonSchema( # The config default is None # which is parsed by configobj as a string not a NoneType changelog = None - translations: list[dict[str, str]] = [] + translations: list[dict[str, str | None]] = [] for langCode, translatedManifest in getAddonManifestLocalizations(manifest): try: translations.append( @@ -132,7 +132,7 @@ def _createDataclassMatchingJsonSchema( raise KeyError(f"Translation for {langCode} missing required key '{e.args[0]}'.") from e # Add optional translated changelog. - translatedChangelog = translatedManifest.get("changelog") # type: ignore[reportUnknownMemberType] + translatedChangelog: str | None = translatedManifest.get("changelog") # type: ignore[reportUnknownMemberType] if translatedChangelog == "None": # The config default is None # which is parsed by configobj as a string not a NoneType From d0af4bd2070d512160766bc3811f1f9fef7b12d6 Mon Sep 17 00:00:00 2001 From: Sean Budd Date: Fri, 10 Oct 2025 13:35:49 +1100 Subject: [PATCH 31/61] Apply suggestions from code review --- _validate/createJson.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index 65b9d96..d042a98 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -35,7 +35,7 @@ class AddonData: changelog: str | None licenseURL: str | None submissionTime: int - translations: list[dict[str, str]] + translations: list[dict[str, str | None]] def getSha256(addonPath: str) -> str: @@ -108,12 +108,12 @@ def _createDataclassMatchingJsonSchema( raise KeyError(f"Manifest missing required key '{key}'.") # Add optional fields - homepage = manifest.get("url") # type: ignore[reportUnknownMemberType] + homepage | None = manifest.get("url") # type: ignore[reportUnknownMemberType] if homepage == "None": # The config default is None # which is parsed by configobj as a string not a NoneType homepage = None - changelog = manifest.get("changelog") # type: ignore[reportUnknownMemberType] + changelog: str | None = manifest.get("changelog") # type: ignore[reportUnknownMemberType] if changelog == "None": # The config default is None # which is parsed by configobj as a string not a NoneType From 438f4275dea7ca2035d66325b326a3a7d7e61fbe Mon Sep 17 00:00:00 2001 From: Sean Budd Date: Fri, 10 Oct 2025 13:39:52 +1100 Subject: [PATCH 32/61] Update _validate/createJson.py --- _validate/createJson.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index d042a98..b5c7be9 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -108,7 +108,7 @@ def _createDataclassMatchingJsonSchema( raise KeyError(f"Manifest missing required key '{key}'.") # Add optional fields - homepage | None = manifest.get("url") # type: ignore[reportUnknownMemberType] + homepage: str | None = manifest.get("url") # type: ignore[reportUnknownMemberType] if homepage == "None": # The config default is None # which is parsed by configobj as a string not a NoneType From ffbfe0ab37e0fa112c6c238cd8f4e0e18c2edd34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Fri, 10 Oct 2025 05:36:41 +0200 Subject: [PATCH 33/61] Apply review suggestions --- _validate/createJson.py | 19 +++++++------------ _validate/regenerateTranslations.py | 18 ++++++------------ 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index b5c7be9..d56882e 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -120,29 +120,24 @@ def _createDataclassMatchingJsonSchema( changelog = None translations: list[dict[str, str | None]] = [] for langCode, translatedManifest in getAddonManifestLocalizations(manifest): - try: - translations.append( - { - "language": langCode, - "displayName": cast(str, translatedManifest["summary"]), - "description": cast(str, translatedManifest["description"]), - }, - ) - except KeyError as e: - raise KeyError(f"Translation for {langCode} missing required key '{e.args[0]}'.") from e - # Add optional translated changelog. translatedChangelog: str | None = translatedManifest.get("changelog") # type: ignore[reportUnknownMemberType] if translatedChangelog == "None": # The config default is None # which is parsed by configobj as a string not a NoneType translatedChangelog = None - if translatedChangelog: + + try: translations.append( { + "language": langCode, + "displayName": cast(str, translatedManifest["summary"]), + "description": cast(str, translatedManifest["description"]), "changelog": translatedChangelog, }, ) + except KeyError as e: + raise KeyError(f"Translation for {langCode} missing required key '{e.args[0]}'.") from e addonData = AddonData( addonId=cast(str, manifest["name"]), diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index 566f538..d590279 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -29,26 +29,20 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: # which is parsed by configobj as a string not a NoneType changelog = None for langCode, manifest in getAddonManifestLocalizations(manifest): + translatedChangelog = manifest.get("changelog") # type: ignore[reportUnknownMemberType] + if translatedChangelog == "None": + # The config default is None + # which is parsed by configobj as a string not a NoneType + translatedChangelog = None addonData["translations"].append( { "language": langCode, "displayName": manifest["summary"], "description": manifest["description"], + "changelog": translatedChangelog, }, ) - translatedChangelog = manifest.get("changelog") # type: ignore[reportUnknownMemberType] - if translatedChangelog == "None": - # The config default is None - # which is parsed by configobj as a string not a NoneType - translatedChangelog = None - if translatedChangelog: - addonData["translations"].append( - { - "changelog": translatedChangelog, - }, - ) - with open(filePath, "wt", encoding="utf-8") as f: json.dump(addonData, f, indent="\t", ensure_ascii=False) print(f"Wrote json file: {filePath}") From 7fd4b0cd55f04114622d9e7779f690de9531c22b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Mon, 13 Oct 2025 11:00:21 +0200 Subject: [PATCH 34/61] Update createJson casting fields to str according to schema --- _validate/createJson.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index d56882e..b86c97a 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -133,7 +133,7 @@ def _createDataclassMatchingJsonSchema( "language": langCode, "displayName": cast(str, translatedManifest["summary"]), "description": cast(str, translatedManifest["description"]), - "changelog": translatedChangelog, + "changelog": cast(str, translatedChangelog), }, ) except KeyError as e: @@ -155,9 +155,9 @@ def _createDataclassMatchingJsonSchema( publisher=publisher, sourceURL=sourceUrl, license=licenseName, - homepage=homepage, - changelog=changelog, - licenseURL=licenseUrl, + homepage=cast(str, homepage), + changelog=cast(str, changelog), + licenseURL=cast(str, licenseUrl), submissionTime=getCurrentTime(), translations=translations, ) From 3385e8f0f5eb734d0880fca4cbb8bd27480305b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Mon, 13 Oct 2025 11:28:00 +0200 Subject: [PATCH 35/61] Cast optionals in validate --- _validate/validate.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_validate/validate.py b/_validate/validate.py index fe3554f..172fdf1 100644 --- a/_validate/validate.py +++ b/_validate/validate.py @@ -140,7 +140,7 @@ def checkChangelogMatches(manifest: AddonManifest, submission: JsonObjT) -> Vali if changelog == "None": # The config default is None which is parsed by configobj as a string not a NoneType changelog = None - if changelog != submission.get("changelog"): + if cast(str, changelog) != submission.get("changelog"): yield ( f"Submission 'changelog' must be set to '{manifest.get('changelog')}' " # type: ignore[reportUnknownMemberType] f"in json file instead of {submission.get('changelog')}" @@ -153,7 +153,7 @@ def checkUrlMatchesHomepage(manifest: AddonManifest, submission: JsonObjT) -> Va if manifestUrl == "None": # The config default is None which is parsed by configobj as a string not a NoneType manifestUrl = None - if manifestUrl != submission.get("homepage"): + if cast(str, manifestUrl) != submission.get("homepage"): yield ( f"Submission 'homepage' must be set to '{manifest.get('url')}' " # type: ignore[reportUnknownMemberType] f"in json file instead of {submission.get('homepage')}" From 98f27039d565b07c8f38872b16b36112566ca34f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Mon, 13 Oct 2025 11:34:40 +0200 Subject: [PATCH 36/61] Cast translated changelog in regenerate translations to ensure that it would be str, according to json schema --- _validate/regenerateTranslations.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index d590279..38b65f6 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -6,6 +6,7 @@ import glob import json from urllib.request import urlretrieve +from typing import cast from .manifestLoader import getAddonManifest, getAddonManifestLocalizations @@ -39,7 +40,7 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: "language": langCode, "displayName": manifest["summary"], "description": manifest["description"], - "changelog": translatedChangelog, + "changelog": cast(str, translatedChangelog), }, ) From 92b193f75bbd3a274f85a23f42b6f77bd38e40c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Tue, 14 Oct 2025 19:55:48 +0200 Subject: [PATCH 37/61] Add null type to json schema --- _validate/addonVersion_schema.json | 12 ++++++------ _validate/createJson.py | 10 +++++----- _validate/validate.py | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/_validate/addonVersion_schema.json b/_validate/addonVersion_schema.json index 4e18495..7fdf70b 100644 --- a/_validate/addonVersion_schema.json +++ b/_validate/addonVersion_schema.json @@ -126,7 +126,7 @@ "Makes doing XYZ easier" ], "title": "The description (en) of the addon", - "type": "string" + "type": ["string", "null"] }, "homepage": { "$id": "#/properties/homepage", @@ -137,7 +137,7 @@ ], "pattern": "^https:.*", "title": "The homepage URL for the addon.", - "type": "string" + "type": ["string", "null"] }, "minNVDAVersion": { "$ref": "#/$defs/canonicalVersion", @@ -228,7 +228,7 @@ "https://github.com/nvaccess/addon-datastore/license.MD" ], "title": "The URL of the license", - "type": "string" + "type": ["string", "null"] }, "changelog": { "$id": "#/properties/changelog", @@ -238,7 +238,7 @@ "New feature" ], "title": "Add-on changelog (en)", - "type": "string" + "type": ["string", "null"] }, "legacy": { "$id": "#/properties/legacy", @@ -406,7 +406,7 @@ "erleichtert das Durchführen von xyz" ], "title": "The translated description", - "type": "string" + "type": ["string", "null"] }, "changelog": { "default": "", @@ -415,7 +415,7 @@ "Neue Funktionen" ], "title": "The translated changelog", - "type": "string" + "type": ["string", "null"] } } } diff --git a/_validate/createJson.py b/_validate/createJson.py index b86c97a..27fce46 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -21,7 +21,7 @@ class AddonData: addonId: str displayName: str URL: str - description: str + description: str | None sha256: str addonVersionName: str addonVersionNumber: dict[str, int] @@ -133,7 +133,7 @@ def _createDataclassMatchingJsonSchema( "language": langCode, "displayName": cast(str, translatedManifest["summary"]), "description": cast(str, translatedManifest["description"]), - "changelog": cast(str, translatedChangelog), + "changelog": translatedChangelog, }, ) except KeyError as e: @@ -155,9 +155,9 @@ def _createDataclassMatchingJsonSchema( publisher=publisher, sourceURL=sourceUrl, license=licenseName, - homepage=cast(str, homepage), - changelog=cast(str, changelog), - licenseURL=cast(str, licenseUrl), + homepage=homepage, + changelog=changelog, + licenseURL=licenseUrl, submissionTime=getCurrentTime(), translations=translations, ) diff --git a/_validate/validate.py b/_validate/validate.py index 172fdf1..fe3554f 100644 --- a/_validate/validate.py +++ b/_validate/validate.py @@ -140,7 +140,7 @@ def checkChangelogMatches(manifest: AddonManifest, submission: JsonObjT) -> Vali if changelog == "None": # The config default is None which is parsed by configobj as a string not a NoneType changelog = None - if cast(str, changelog) != submission.get("changelog"): + if changelog != submission.get("changelog"): yield ( f"Submission 'changelog' must be set to '{manifest.get('changelog')}' " # type: ignore[reportUnknownMemberType] f"in json file instead of {submission.get('changelog')}" @@ -153,7 +153,7 @@ def checkUrlMatchesHomepage(manifest: AddonManifest, submission: JsonObjT) -> Va if manifestUrl == "None": # The config default is None which is parsed by configobj as a string not a NoneType manifestUrl = None - if cast(str, manifestUrl) != submission.get("homepage"): + if manifestUrl != submission.get("homepage"): yield ( f"Submission 'homepage' must be set to '{manifest.get('url')}' " # type: ignore[reportUnknownMemberType] f"in json file instead of {submission.get('homepage')}" From 2d838ae2595f97405144e2d3601ef087f8bc7263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Wed, 15 Oct 2025 19:51:56 +0200 Subject: [PATCH 38/61] Update _validate/validate.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- _validate/validate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_validate/validate.py b/_validate/validate.py index fe3554f..113aae4 100644 --- a/_validate/validate.py +++ b/_validate/validate.py @@ -142,7 +142,7 @@ def checkChangelogMatches(manifest: AddonManifest, submission: JsonObjT) -> Vali changelog = None if changelog != submission.get("changelog"): yield ( - f"Submission 'changelog' must be set to '{manifest.get('changelog')}' " # type: ignore[reportUnknownMemberType] + f"Submission 'changelog' must be set to '{changelog}' " f"in json file instead of {submission.get('changelog')}" ) From c000bff3aa57696647ae7ee07cc68ef0926b10ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Wed, 15 Oct 2025 19:59:54 +0200 Subject: [PATCH 39/61] Update regenerateTranslations --- _validate/regenerateTranslations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index 38b65f6..fce2087 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -40,7 +40,7 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: "language": langCode, "displayName": manifest["summary"], "description": manifest["description"], - "changelog": cast(str, translatedChangelog), + "changelog": translatedChangelog, }, ) From 89e3ba785c6279060304a21961c9786d707e67fc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 15 Oct 2025 18:00:25 +0000 Subject: [PATCH 40/61] Pre-commit auto-fix --- _validate/regenerateTranslations.py | 1 - 1 file changed, 1 deletion(-) diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index fce2087..d590279 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -6,7 +6,6 @@ import glob import json from urllib.request import urlretrieve -from typing import cast from .manifestLoader import getAddonManifest, getAddonManifestLocalizations From 9e24496239720af25362702f710e0bd8e1bc2d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Mon, 3 Nov 2025 06:16:16 +0100 Subject: [PATCH 41/61] Apply suggestions from code review Co-authored-by: Sean Budd --- _validate/addonVersion_schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_validate/addonVersion_schema.json b/_validate/addonVersion_schema.json index 7fdf70b..c14111a 100644 --- a/_validate/addonVersion_schema.json +++ b/_validate/addonVersion_schema.json @@ -126,7 +126,7 @@ "Makes doing XYZ easier" ], "title": "The description (en) of the addon", - "type": ["string", "null"] + "type": "string" }, "homepage": { "$id": "#/properties/homepage", From 0fbfa69dfe0056be59caaa6f113aabe0c8fa87d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Mon, 3 Nov 2025 06:20:48 +0100 Subject: [PATCH 42/61] Don't accept null values in the json spec --- _validate/addonVersion_schema.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/_validate/addonVersion_schema.json b/_validate/addonVersion_schema.json index c14111a..4e18495 100644 --- a/_validate/addonVersion_schema.json +++ b/_validate/addonVersion_schema.json @@ -137,7 +137,7 @@ ], "pattern": "^https:.*", "title": "The homepage URL for the addon.", - "type": ["string", "null"] + "type": "string" }, "minNVDAVersion": { "$ref": "#/$defs/canonicalVersion", @@ -228,7 +228,7 @@ "https://github.com/nvaccess/addon-datastore/license.MD" ], "title": "The URL of the license", - "type": ["string", "null"] + "type": "string" }, "changelog": { "$id": "#/properties/changelog", @@ -238,7 +238,7 @@ "New feature" ], "title": "Add-on changelog (en)", - "type": ["string", "null"] + "type": "string" }, "legacy": { "$id": "#/properties/legacy", @@ -406,7 +406,7 @@ "erleichtert das Durchführen von xyz" ], "title": "The translated description", - "type": ["string", "null"] + "type": "string" }, "changelog": { "default": "", @@ -415,7 +415,7 @@ "Neue Funktionen" ], "title": "The translated changelog", - "type": ["string", "null"] + "type": "string" } } } From 815226c6d328fc61c0b97af2985bff81847f2272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Mon, 3 Nov 2025 06:25:10 +0100 Subject: [PATCH 43/61] Address review --- _validate/createJson.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index ab09927..bd40f4e 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -120,7 +120,7 @@ def _createDataclassMatchingJsonSchema( # Add optional fields homepage: str | None = manifest.get("url") # type: ignore[reportUnknownMemberType] - if homepage == "None": + if not homepage or homepage == "None": # The config default is None # which is parsed by configobj as a string not a NoneType homepage = None From e91541111d87e1f7f67e68b5535fca255d9ffe3b Mon Sep 17 00:00:00 2001 From: Sean Budd Date: Mon, 3 Nov 2025 16:30:02 +1100 Subject: [PATCH 44/61] Update _validate/createJson.py --- _validate/createJson.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index bd40f4e..eb61545 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -21,7 +21,7 @@ class AddonData: addonId: str displayName: str URL: str - description: str | None + description: str sha256: str addonVersionName: str addonVersionNumber: dict[str, int] From 879e61bfeb3a32b6f56de4a393d885b059a57b30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 8 Nov 2025 10:44:05 +0100 Subject: [PATCH 45/61] Strip None changelogs from translations --- _validate/createJson.py | 18 +++++++++++++++++- _validate/regenerateTranslations.py | 4 ++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index eb61545..6d70a9a 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -72,6 +72,10 @@ def generateJsonFile( filePath = buildOutputFilePath(data, parentDir) + translations = data.get("translations") + if translations is not None: + data["translations"] = stripEmptyChangelog(translations) + with open(filePath, "wt", encoding="utf-8") as f: json.dump( dataclasses.asdict( @@ -144,7 +148,6 @@ def _createDataclassMatchingJsonSchema( "language": langCode, "displayName": cast(str, translatedManifest["summary"]), "description": cast(str, translatedManifest["description"]), - "changelog": translatedChangelog, }, ) except KeyError as e: @@ -176,6 +179,19 @@ def _createDataclassMatchingJsonSchema( return addonData +def stripEmptyChangelog(translations: list[dict[str: str | None]]) -> list[dict[str: str]]: + """Remove None changelogs from a list of translations. + return: A list of translations without None changelogs. + """ + + cleanTranslations = [] + for translation in translations: + if translation.get("changelog") is not None: + del translation["changelog"] + cleanTranslations.append(translation) + return cleanTranslations + + def main(): parser = argparse.ArgumentParser() parser.add_argument( diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index d590279..695a875 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -8,6 +8,7 @@ from urllib.request import urlretrieve from .manifestLoader import getAddonManifest, getAddonManifestLocalizations +from .createJson import stripEmptyChangelog def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: @@ -42,6 +43,9 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: "changelog": translatedChangelog, }, ) + if len(addonData["translations"]) > 0: + translations = stripEmptyChangelog(addonData["translations"]) + addonData["translations"] = translations with open(filePath, "wt", encoding="utf-8") as f: json.dump(addonData, f, indent="\t", ensure_ascii=False) From efc4fc2438fcb0730fd51e83df83185182352a58 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 8 Nov 2025 09:44:21 +0000 Subject: [PATCH 46/61] Pre-commit auto-fix --- _validate/createJson.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index 6d70a9a..6e664f6 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -179,7 +179,7 @@ def _createDataclassMatchingJsonSchema( return addonData -def stripEmptyChangelog(translations: list[dict[str: str | None]]) -> list[dict[str: str]]: +def stripEmptyChangelog(translations: list[dict[str : str | None]]) -> list[dict[str:str]]: """Remove None changelogs from a list of translations. return: A list of translations without None changelogs. """ From ba1ea0729d14222c100a462c072c4e0744797fca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 8 Nov 2025 10:59:21 +0100 Subject: [PATCH 47/61] Fix --- _validate/createJson.py | 7 ++----- _validate/regenerateTranslations.py | 5 ++--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index 6d70a9a..eef9045 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -71,10 +71,7 @@ def generateJsonFile( ) filePath = buildOutputFilePath(data, parentDir) - - translations = data.get("translations") - if translations is not None: - data["translations"] = stripEmptyChangelog(translations) + data.translations = stripEmptyChangelog(data.translations) with open(filePath, "wt", encoding="utf-8") as f: json.dump( @@ -179,7 +176,7 @@ def _createDataclassMatchingJsonSchema( return addonData -def stripEmptyChangelog(translations: list[dict[str: str | None]]) -> list[dict[str: str]]: +def stripEmptyChangelog(translations: list[dict[str, str | None]]) -> list[dict[str, str]]: """Remove None changelogs from a list of translations. return: A list of translations without None changelogs. """ diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index 695a875..6dcf597 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -43,9 +43,8 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: "changelog": translatedChangelog, }, ) - if len(addonData["translations"]) > 0: - translations = stripEmptyChangelog(addonData["translations"]) - addonData["translations"] = translations + translations = stripEmptyChangelog(addonData["translations"]) + addonData["translations"] = translations with open(filePath, "wt", encoding="utf-8") as f: json.dump(addonData, f, indent="\t", ensure_ascii=False) From 93188844c802f915b46a853bf1ec670347fe1a4d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 8 Nov 2025 10:03:44 +0000 Subject: [PATCH 48/61] Pre-commit auto-fix --- _validate/createJson.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index bd4d1ee..eef9045 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -178,7 +178,7 @@ def _createDataclassMatchingJsonSchema( def stripEmptyChangelog(translations: list[dict[str, str | None]]) -> list[dict[str, str]]: """Remove None changelogs from a list of translations. - return: A list of translations without None changelogs. + return: A list of translations without None changelogs. """ cleanTranslations = [] From 6b7789cfcaced1f5d6fd34ceb2fca7b12bac431e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 8 Nov 2025 11:07:20 +0100 Subject: [PATCH 49/61] Fix translations type --- _validate/createJson.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index bd4d1ee..69d6c8d 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -35,7 +35,7 @@ class AddonData: changelog: str | None licenseURL: str | None submissionTime: int - translations: list[dict[str, str | None]] + translations: list[dict[str, str]] def getSha256(addonPath: str) -> str: From 18cc72cea5e9d165e8b21878cb24e0e450714419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 8 Nov 2025 11:35:30 +0100 Subject: [PATCH 50/61] Ignore unknown type --- _validate/createJson.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index 3abb01c..407435c 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -176,7 +176,7 @@ def _createDataclassMatchingJsonSchema( return addonData -def stripEmptyChangelog(translations: list[dict[str, str | None]]) -> list[dict[str, str]]: +def stripEmptyChangelog(translations: list[dict[str, str | None]]) -> list[dict[str, str]]: # type: ignore[reportUnknownMemberType] """Remove None changelogs from a list of translations. return: A list of translations without None changelogs. """ From caf598d66ba1c6e573e26a33b0e8fdcf03278e12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 8 Nov 2025 11:39:25 +0100 Subject: [PATCH 51/61] Fix type for translation --- _validate/createJson.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index 407435c..b7df2a8 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -176,7 +176,7 @@ def _createDataclassMatchingJsonSchema( return addonData -def stripEmptyChangelog(translations: list[dict[str, str | None]]) -> list[dict[str, str]]: # type: ignore[reportUnknownMemberType] +def stripEmptyChangelog(translations: list[dict[str, str | None]]) -> list[dict[str, str]]: """Remove None changelogs from a list of translations. return: A list of translations without None changelogs. """ @@ -185,7 +185,7 @@ def stripEmptyChangelog(translations: list[dict[str, str | None]]) -> list[dict[ for translation in translations: if translation.get("changelog") is not None: del translation["changelog"] - cleanTranslations.append(translation) + cleanTranslations.append(translation) # type: ignore[reportUnknownMemberType] return cleanTranslations From 58a6fc4ed61df6ddb10677a02ee277f09dd8de23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 8 Nov 2025 11:44:49 +0100 Subject: [PATCH 52/61] Add missing key --- _validate/createJson.py | 1 + 1 file changed, 1 insertion(+) diff --git a/_validate/createJson.py b/_validate/createJson.py index b7df2a8..2a013fb 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -145,6 +145,7 @@ def _createDataclassMatchingJsonSchema( "language": langCode, "displayName": cast(str, translatedManifest["summary"]), "description": cast(str, translatedManifest["description"]), + "changelog": translatedChangelog, }, ) except KeyError as e: From 9566693f3038e2a46c09c934b1f1ebec31d7b639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 8 Nov 2025 12:02:32 +0100 Subject: [PATCH 53/61] Don't add translated changelog if it's None --- _validate/createJson.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index 2a013fb..dbd1667 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -130,7 +130,7 @@ def _createDataclassMatchingJsonSchema( # The config default is None # which is parsed by configobj as a string not a NoneType changelog = None - translations: list[dict[str, str | None]] = [] + translations: list[dict[str, str]] = [] for langCode, translatedManifest in getAddonManifestLocalizations(manifest): # Add optional translated changelog. translatedChangelog: str | None = translatedManifest.get("changelog") # type: ignore[reportUnknownMemberType] @@ -140,14 +140,14 @@ def _createDataclassMatchingJsonSchema( translatedChangelog = None try: - translations.append( - { - "language": langCode, - "displayName": cast(str, translatedManifest["summary"]), - "description": cast(str, translatedManifest["description"]), - "changelog": translatedChangelog, - }, - ) + translation: dict[str, str] = { + "language": langCode, + "displayName": cast(str, translatedManifest["summary"]), + "description": cast(str, translatedManifest["description"]), + } + if translatedChangelog is not None: + translation["changelog"] = translatedChangelog + translations.append(translation) except KeyError as e: raise KeyError(f"Translation for {langCode} missing required key '{e.args[0]}'.") from e From e7f9414542d011b789e78dcb206fb19ff45a6313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 8 Nov 2025 12:07:02 +0100 Subject: [PATCH 54/61] Revert changes in regenerateTranslations --- _validate/regenerateTranslations.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index 6dcf597..d590279 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -8,7 +8,6 @@ from urllib.request import urlretrieve from .manifestLoader import getAddonManifest, getAddonManifestLocalizations -from .createJson import stripEmptyChangelog def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: @@ -43,8 +42,6 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: "changelog": translatedChangelog, }, ) - translations = stripEmptyChangelog(addonData["translations"]) - addonData["translations"] = translations with open(filePath, "wt", encoding="utf-8") as f: json.dump(addonData, f, indent="\t", ensure_ascii=False) From ed2f0ed0b4e813def636adda3ee1dc473338dd0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 8 Nov 2025 12:14:54 +0100 Subject: [PATCH 55/61] Update regenerateTranslations --- _validate/regenerateTranslations.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index d590279..f75a3bb 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -34,14 +34,14 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: # The config default is None # which is parsed by configobj as a string not a NoneType translatedChangelog = None - addonData["translations"].append( - { - "language": langCode, - "displayName": manifest["summary"], - "description": manifest["description"], - "changelog": translatedChangelog, - }, - ) + translation: list[dict[str, str]] = { + "language": langCode, + "displayName": manifest["summary"], + "description": manifest["description"], + } + if translatedChangelog is not None: + translation["changelog"] = translatedChangelog + addonData["translations"].append(translation) with open(filePath, "wt", encoding="utf-8") as f: json.dump(addonData, f, indent="\t", ensure_ascii=False) From 8cc1dcd35677c7c2fad4c4a01612f94418441a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 8 Nov 2025 12:17:55 +0100 Subject: [PATCH 56/61] Remove not used function --- _validate/createJson.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index dbd1667..f218146 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -177,19 +177,6 @@ def _createDataclassMatchingJsonSchema( return addonData -def stripEmptyChangelog(translations: list[dict[str, str | None]]) -> list[dict[str, str]]: - """Remove None changelogs from a list of translations. - return: A list of translations without None changelogs. - """ - - cleanTranslations = [] - for translation in translations: - if translation.get("changelog") is not None: - del translation["changelog"] - cleanTranslations.append(translation) # type: ignore[reportUnknownMemberType] - return cleanTranslations - - def main(): parser = argparse.ArgumentParser() parser.add_argument( From 639d09531746685388f370364b3a00d49dedc8e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 8 Nov 2025 12:24:18 +0100 Subject: [PATCH 57/61] Remove not used assignment --- _validate/createJson.py | 1 - 1 file changed, 1 deletion(-) diff --git a/_validate/createJson.py b/_validate/createJson.py index f218146..155f00a 100644 --- a/_validate/createJson.py +++ b/_validate/createJson.py @@ -71,7 +71,6 @@ def generateJsonFile( ) filePath = buildOutputFilePath(data, parentDir) - data.translations = stripEmptyChangelog(data.translations) with open(filePath, "wt", encoding="utf-8") as f: json.dump( From 58a88be4267a95d791d29584b79812f6e8bc6641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 8 Nov 2025 12:36:01 +0100 Subject: [PATCH 58/61] Fix type for translation --- _validate/regenerateTranslations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index f75a3bb..4179999 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -34,7 +34,7 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: # The config default is None # which is parsed by configobj as a string not a NoneType translatedChangelog = None - translation: list[dict[str, str]] = { + translation: dict[str, str] = { "language": langCode, "displayName": manifest["summary"], "description": manifest["description"], From 75eb537ee919f2907281425e3ce40ce0730184fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 8 Nov 2025 12:44:06 +0100 Subject: [PATCH 59/61] Try to fix type --- _validate/regenerateTranslations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index 4179999..05bd012 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -29,7 +29,7 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: # which is parsed by configobj as a string not a NoneType changelog = None for langCode, manifest in getAddonManifestLocalizations(manifest): - translatedChangelog = manifest.get("changelog") # type: ignore[reportUnknownMemberType] + translatedChangelog: str | None = translatedManifest.get("changelog") # type: ignore[reportUnknownMemberType] if translatedChangelog == "None": # The config default is None # which is parsed by configobj as a string not a NoneType From b1d3fe0ee4dbac5e828cb4283ef8fd156a33d479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 8 Nov 2025 12:48:16 +0100 Subject: [PATCH 60/61] Fix assignment --- _validate/regenerateTranslations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index 05bd012..b4f047a 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -29,7 +29,7 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: # which is parsed by configobj as a string not a NoneType changelog = None for langCode, manifest in getAddonManifestLocalizations(manifest): - translatedChangelog: str | None = translatedManifest.get("changelog") # type: ignore[reportUnknownMemberType] + translatedChangelog: str | None = manifest.get("changelog") # type: ignore[reportUnknownMemberType] if translatedChangelog == "None": # The config default is None # which is parsed by configobj as a string not a NoneType From d65f79fc2189d8e6b0f567c09c21be6ff76783ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noelia=20Ruiz=20Mart=C3=ADnez?= Date: Sat, 8 Nov 2025 12:56:12 +0100 Subject: [PATCH 61/61] Cast summary and description for translations, similar to createjson --- _validate/regenerateTranslations.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/_validate/regenerateTranslations.py b/_validate/regenerateTranslations.py index b4f047a..0a4f0bc 100644 --- a/_validate/regenerateTranslations.py +++ b/_validate/regenerateTranslations.py @@ -6,6 +6,7 @@ import glob import json from urllib.request import urlretrieve +from typing import cast from .manifestLoader import getAddonManifest, getAddonManifestLocalizations @@ -36,8 +37,8 @@ def regenerateJsonFile(filePath: str, errorFilePath: str | None) -> None: translatedChangelog = None translation: dict[str, str] = { "language": langCode, - "displayName": manifest["summary"], - "description": manifest["description"], + "displayName": cast(str, manifest["summary"]), + "description": cast(str, manifest["description"]), } if translatedChangelog is not None: translation["changelog"] = translatedChangelog