|
1 | | -#!/usr/bin/env python |
2 | | - |
3 | | -# Copyright (C) 2022-2023 NV Access Limited |
| 1 | +# Copyright (C) 2022-2025 NV Access Limited |
4 | 2 | # This file may be used under the terms of the GNU General Public License, version 2 or later. |
5 | 3 | # For more details see: https://www.gnu.org/licenses/gpl-2.0.html |
6 | 4 |
|
7 | | -import os |
8 | | -import sys |
9 | | -from typing import ( |
10 | | - Optional, |
11 | | - TextIO, |
12 | | - Tuple, |
13 | | -) |
14 | | -from io import StringIO |
| 5 | +from io import StringIO, TextIOBase |
| 6 | +from typing import Any, cast |
15 | 7 |
|
16 | 8 | from configobj import ConfigObj |
17 | 9 | from configobj.validate import Validator, ValidateError |
18 | 10 |
|
19 | | -sys.path.append(os.path.dirname(__file__)) |
20 | | -# E402 module level import not at top of file |
21 | | -from majorMinorPatch import MajorMinorPatch # noqa:E402 |
22 | | -del sys.path[-1] |
| 11 | +from .majorMinorPatch import MajorMinorPatch |
| 12 | + |
| 13 | +ApiVersionT = tuple[int, int, int] # major, minor, patch |
23 | 14 |
|
24 | 15 |
|
25 | 16 | class AddonManifest(ConfigObj): |
26 | 17 | """From the NVDA addonHandler module. Should be kept in sync. |
27 | | - Add-on manifest file. It contains metadata about an NVDA add-on package. """ |
28 | | - configspec = ConfigObj(StringIO( |
29 | | - """ |
| 18 | + Add-on manifest file. It contains metadata about an NVDA add-on package.""" |
| 19 | + |
| 20 | + configspec = ConfigObj( |
| 21 | + StringIO( |
| 22 | + """ |
30 | 23 | # NVDA Add-on Manifest configuration specification |
31 | 24 | # Add-on unique name |
32 | 25 | # Suggested convention is lowerCamelCase. |
@@ -66,56 +59,59 @@ class AddonManifest(ConfigObj): |
66 | 59 | # "0.0.0" is also valid. |
67 | 60 | # The final integer can be left out, and in that case will default to 0. E.g. 2019.1 |
68 | 61 |
|
| 62 | + """, |
| 63 | + ), |
| 64 | + ) |
| 65 | + |
| 66 | + def __init__(self, input: str | TextIOBase, translatedInput: str | None = None): |
69 | 67 | """ |
70 | | - )) |
| 68 | + Constructs an :class:`AddonManifest` instance from manifest string data. |
71 | 69 |
|
72 | | - def __init__(self, input: TextIO, translatedInput: Optional[TextIO] = None): |
73 | | - """ Constructs an L{AddonManifest} instance from manifest string data |
74 | | - @param input: data to read the manifest information |
75 | | - @param translatedInput: translated manifest input |
| 70 | + :param input: data to read the manifest information. Can be a filename or a file-like object. |
| 71 | + :param translatedInput: translated manifest input |
76 | 72 | """ |
77 | | - super().__init__( |
| 73 | + super().__init__( # type: ignore[reportUnknownMemberType] |
78 | 74 | input, |
79 | 75 | configspec=self.configspec, |
80 | | - encoding='utf-8', |
81 | | - default_encoding='utf-8', |
| 76 | + encoding="utf-8", |
| 77 | + default_encoding="utf-8", |
82 | 78 | ) |
83 | | - self._errors: Optional[str] = None |
84 | | - val = Validator({"apiVersion": validate_apiVersionString}) |
85 | | - result = self.validate(val, copy=True, preserve_errors=True) |
| 79 | + self._errors: str | None = None |
| 80 | + validator = Validator({"apiVersion": validate_apiVersionString}) |
| 81 | + result = self.validate(validator, copy=True, preserve_errors=True) # type: ignore[reportUnknownMemberType] |
86 | 82 | if result is not True: |
87 | 83 | self._errors = result |
88 | 84 | elif self._validateApiVersionRange() is not True: |
89 | 85 | self._errors = "Constraint not met: minimumNVDAVersion ({}) <= lastTestedNVDAVersion ({})".format( |
90 | | - self.get("minimumNVDAVersion"), |
91 | | - self.get("lastTestedNVDAVersion") |
| 86 | + cast(ApiVersionT, self.get("minimumNVDAVersion")), # type: ignore[reportUnknownMemberType] |
| 87 | + cast(ApiVersionT, self.get("lastTestedNVDAVersion")), # type: ignore[reportUnknownMemberType] |
92 | 88 | ) |
93 | 89 | self._translatedConfig = None |
94 | 90 | if translatedInput is not None: |
95 | | - self._translatedConfig = ConfigObj(translatedInput, encoding='utf-8', default_encoding='utf-8') |
96 | | - for key in ('summary', 'description'): |
97 | | - val = self._translatedConfig.get(key) |
| 91 | + self._translatedConfig = ConfigObj(translatedInput, encoding="utf-8", default_encoding="utf-8") |
| 92 | + for key in ("summary", "description"): |
| 93 | + val: str = self._translatedConfig.get(key) # type: ignore[reportUnknownMemberType] |
98 | 94 | if val: |
99 | 95 | self[key] = val |
100 | 96 |
|
101 | 97 | @property |
102 | | - def errors(self) -> str: |
| 98 | + def errors(self) -> str | None: |
103 | 99 | return self._errors |
104 | 100 |
|
105 | 101 | def _validateApiVersionRange(self) -> bool: |
106 | | - lastTested = self.get("lastTestedNVDAVersion") |
107 | | - minRequiredVersion = self.get("minimumNVDAVersion") |
| 102 | + lastTested = cast(ApiVersionT, self.get("lastTestedNVDAVersion")) # type: ignore[reportUnknownMemberType] |
| 103 | + minRequiredVersion = cast(ApiVersionT, self.get("minimumNVDAVersion")) # type: ignore[reportUnknownMemberType] |
108 | 104 | return minRequiredVersion <= lastTested |
109 | 105 |
|
110 | 106 |
|
111 | | -def validate_apiVersionString(value: str) -> Tuple[int, int, int]: |
| 107 | +def validate_apiVersionString(value: str | Any) -> ApiVersionT: |
112 | 108 | """From the NVDA addonHandler module. Should be kept in sync.""" |
113 | 109 | if not value or value == "None": |
114 | 110 | return (0, 0, 0) |
115 | 111 | if not isinstance(value, str): |
116 | 112 | raise ValidateError( |
117 | 113 | "Expected an apiVersion in the form of a string. " |
118 | | - f"e.g. '2019.1.0' instead of {value} (type {type(value)})" |
| 114 | + f"e.g. '2019.1.0' instead of {value} (type {type(value)})", |
119 | 115 | ) |
120 | 116 | try: |
121 | 117 | versionParsed = MajorMinorPatch.getFromStr(value) |
|
0 commit comments