test_typestubs.py (1700B)
1 import ast 2 import re 3 4 5 def read_stubfile(): 6 with open("adblock/adblock.pyi", encoding="utf-8") as file: 7 node = ast.parse(file.read()) 8 return node 9 10 11 def get_functions_and_methods(node): 12 functions = [n for n in node.body if isinstance(n, ast.FunctionDef)] 13 classes = [n for n in node.body if isinstance(n, ast.ClassDef)] 14 15 methods = {} 16 for c in classes: 17 methods[c.name] = [n for n in c.body if isinstance(n, ast.FunctionDef)] 18 19 return functions, methods 20 21 22 def pattern_exists_in_file(filename, regex): 23 """ 24 Checks if the given regex is present in the given file 25 """ 26 with open(filename, "r", encoding="utf-8") as f: 27 for line in f: 28 if re.search(regex, line): 29 return True 30 return False 31 32 33 def test_functions_and_methods_exist_in_rust(): 34 """ 35 Check that for each of the functions and methods present in the Python 36 typestub file, there is a line in `src/lib.rs` containing a matching 37 definition. Since we're doing a naive grep search, without access to the 38 Rust AST, there may be false negatives. 39 """ 40 stubfile_node = read_stubfile() 41 functions, methods = get_functions_and_methods(stubfile_node) 42 43 methods_flattened = [] 44 for class_methods in methods.values(): 45 methods_flattened += class_methods 46 47 for f in functions + methods_flattened: 48 if f.name.startswith("__"): 49 # Skip dunder methods since their names are the same for every 50 # class, making the test not particularly useful. They are also not 51 # marked `pub` in Rust. 52 continue 53 assert pattern_exists_in_file("src/lib.rs", r"pub fn {}".format(f.name))