2
2
3
3
import os
4
4
import time
5
- import urllib
5
+ import urllib .request
6
+ from typing import Any , Callable , Generator , TypeVar
7
+
6
8
import jsonschema
7
9
8
10
from lib .print import _print
@@ -25,10 +27,13 @@ class c:
25
27
26
28
27
29
class TestReport :
28
- def __init__ (self , message ):
30
+ style : str
31
+ test_name : str
32
+
33
+ def __init__ (self , message : str ) -> None :
29
34
self .message = message
30
35
31
- def display (self , prefix = "" ):
36
+ def display (self , prefix : str = "" ) -> None :
32
37
_print (prefix + self .style % self .message )
33
38
34
39
@@ -52,38 +57,38 @@ class Critical(TestReport):
52
57
style = c .FAIL + " ✘✘✘ %s" + c .END
53
58
54
59
55
- def report_warning_not_reliable (str ):
56
- _print (c .MAYBE_FAIL + "?" , str , c .END )
60
+ def report_warning_not_reliable (message : str ) -> None :
61
+ _print (c .MAYBE_FAIL + "?" , message , c .END )
57
62
58
63
59
- def print_happy (str ):
60
- _print (c .OKGREEN + " ☺ " , str , "♥" )
64
+ def print_happy (message : str ) -> None :
65
+ _print (c .OKGREEN + " ☺ " , message , "♥" )
61
66
62
67
63
- def urlopen (url ) :
68
+ def urlopen (url : str ) -> tuple [ int , str ] :
64
69
try :
65
70
conn = urllib .request .urlopen (url )
66
71
except urllib .error .HTTPError as e :
67
- return { "content" : "" , "code" : e . code }
72
+ return e . code , ""
68
73
except urllib .error .URLError as e :
69
74
_print ("Could not fetch %s : %s" % (url , e ))
70
- return { "content" : "" , "code" : 0 }
71
- return { "content" : conn .read ().decode ("UTF8" ), "code" : 200 }
75
+ return 0 , ""
76
+ return 200 , conn .read ().decode ("UTF8" )
72
77
73
78
74
- def file_exists (file_path ) :
79
+ def file_exists (file_path : str ) -> bool :
75
80
return os .path .isfile (file_path ) and os .stat (file_path ).st_size > 0
76
81
77
82
78
- def cache_file (cachefile : str , ttl_s : int ):
79
- def cache_is_fresh ():
83
+ def cache_file (cachefile : str , ttl_s : int ) -> Callable [[ Callable [..., str ]], Callable [..., str ]] :
84
+ def cache_is_fresh () -> bool :
80
85
return (
81
86
os .path .exists (cachefile )
82
87
and time .time () - os .path .getmtime (cachefile ) < ttl_s
83
88
)
84
89
85
- def decorator (function ) :
86
- def wrapper (* args , ** kwargs ) :
90
+ def decorator (function : Callable [..., str ]) -> Callable [..., str ] :
91
+ def wrapper (* args : Any , ** kwargs : Any ) -> str :
87
92
if not cache_is_fresh ():
88
93
with open (cachefile , "w+" ) as outfile :
89
94
outfile .write (function (* args , ** kwargs ))
@@ -95,47 +100,47 @@ def wrapper(*args, **kwargs):
95
100
96
101
97
102
@cache_file (".spdx_licenses" , 3600 )
98
- def spdx_licenses ():
99
- return urlopen ("https://spdx.org/licenses/" )["content" ]
103
+ def spdx_licenses () -> str :
104
+ return urlopen ("https://spdx.org/licenses/" )[1 ]
100
105
101
106
102
107
@cache_file (".manifest.v2.schema.json" , 3600 )
103
- def manifest_v2_schema ():
104
- return urlopen (
105
- "https://raw.githubusercontent.com/YunoHost/apps/master/schemas/manifest.v2.schema.json"
106
- )["content" ]
108
+ def manifest_v2_schema () -> str :
109
+ url = "https://raw.githubusercontent.com/YunoHost/apps/master/schemas/manifest.v2.schema.json"
110
+ return urlopen (url )[1 ]
107
111
108
112
109
113
@cache_file (".tests.v1.schema.json" , 3600 )
110
- def tests_v1_schema ():
111
- return urlopen (
112
- "https://raw.githubusercontent.com/YunoHost/apps/master/schemas/tests.v1.schema.json"
113
- )["content" ]
114
+ def tests_v1_schema () -> str :
115
+ url = "https://raw.githubusercontent.com/YunoHost/apps/master/schemas/tests.v1.schema.json"
116
+ return urlopen (url )[1 ]
114
117
115
118
116
119
@cache_file (".config_panel.v1.schema.json" , 3600 )
117
- def config_panel_v1_schema ():
118
- return urlopen (
119
- "https://raw.githubusercontent.com/YunoHost/apps/master/schemas/config_panel.v1.schema.json"
120
- )["content" ]
120
+ def config_panel_v1_schema () -> str :
121
+ url = "https://raw.githubusercontent.com/YunoHost/apps/master/schemas/config_panel.v1.schema.json"
122
+ return urlopen (url )[1 ]
121
123
122
124
123
- def validate_schema (name : str , schema , data ) :
125
+ def validate_schema (name : str , schema : dict [ str , Any ], data : dict [ str , Any ]) -> Generator [ Info , None , None ] :
124
126
v = jsonschema .Draft7Validator (schema )
125
127
126
128
for error in v .iter_errors (data ):
127
129
try :
128
130
error_path = " > " .join (error .path )
129
- except :
131
+ except TypeError :
130
132
error_path = str (error .path )
131
133
132
134
yield Info (
133
135
f"Error validating { name } using schema: in key { error_path } \n { error .message } "
134
136
)
135
137
136
138
137
- tests = {}
138
- tests_reports = {
139
+ TestResult = Generator [TestReport , None , None ]
140
+ TestFn = Callable [[Any ], TestResult ]
141
+
142
+ tests : dict [str , list [tuple [TestFn , Any ]]] = {}
143
+ tests_reports : dict [str , list [Any ]] = {
139
144
"success" : [],
140
145
"info" : [],
141
146
"warning" : [],
@@ -144,8 +149,9 @@ def validate_schema(name: str, schema, data):
144
149
}
145
150
146
151
147
- def test (** kwargs ):
148
- def decorator (f ):
152
+
153
+ def test (** kwargs : Any ) -> Callable [[TestFn ], TestFn ]:
154
+ def decorator (f : TestFn ) -> TestFn :
149
155
clsname = f .__qualname__ .split ("." )[0 ]
150
156
if clsname not in tests :
151
157
tests [clsname ] = []
@@ -155,8 +161,11 @@ def decorator(f):
155
161
return decorator
156
162
157
163
158
- class TestSuite :
159
- def run_tests (self ):
164
+ class TestSuite ():
165
+ name : str
166
+ test_suite_name : str
167
+
168
+ def run_tests (self ) -> None :
160
169
161
170
reports = []
162
171
@@ -174,7 +183,7 @@ def run_tests(self):
174
183
175
184
# Display part
176
185
177
- def report_type (report ) :
186
+ def report_type (report : TestReport ) -> str :
178
187
return report .__class__ .__name__ .lower ()
179
188
180
189
if any (report_type (r ) in ["warning" , "error" , "critical" ] for r in reports ):
@@ -198,11 +207,11 @@ def report_type(report):
198
207
for report in reports :
199
208
tests_reports [report_type (report )].append ((report .test_name , report ))
200
209
201
- def run_single_test (self , test ) :
210
+ def run_single_test (self , test : TestFn ) -> None :
202
211
203
212
reports = list (test (self ))
204
213
205
- def report_type (report ) :
214
+ def report_type (report : TestReport ) -> str :
206
215
return report .__class__ .__name__ .lower ()
207
216
208
217
for report in reports :
0 commit comments