Coverage for pycommons/dev/tests/examples_in_dir.py: 100%

32 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-07 11:10 +0000

1"""Test all the example code in a directory.""" 

2from random import randint 

3from typing import Final 

4 

5from pycommons.dev.tests.compile_and_run import compile_and_run 

6from pycommons.io.console import logger 

7from pycommons.io.path import Path, directory_path 

8from pycommons.types import type_error 

9 

10 

11def check_examples_in_dir(directory: str, recurse: bool = True) -> int: 

12 """ 

13 Test all the examples in a directory. 

14 

15 :param directory: the directory 

16 :param recurse: should we recurse into sub-directories (if any)? 

17 :returns: the total number of examples executed 

18 :raises TypeError: if `directory` is not a string or `recurse` is not a 

19 Boolean 

20 :raises ValueError: if executing the examples fails or if no examples were 

21 found 

22 

23 >>> from contextlib import redirect_stdout 

24 >>> from io import StringIO 

25 >>> ex_dir = Path(__file__).up(4).resolve_inside("examples") 

26 >>> with redirect_stdout(StringIO()): 

27 ... check_examples_in_dir(ex_dir) 

28 

29 >>> from pycommons.io.temp import temp_dir 

30 >>> with temp_dir() as td: 

31 ... f = td.resolve_inside("test.py") 

32 ... f.write_all_str(ex_dir.resolve_inside( 

33 ... "compile_and_run_dummy.py").read_all_str()) 

34 ... print(check_examples_in_dir(td)) 

35 test.py 

36 1 

37 

38 >>> try: 

39 ... check_examples_in_dir(None, True) 

40 ... except TypeError as te: 

41 ... print(te) 

42 descriptor '__len__' requires a 'str' object but received a 'NoneType' 

43 

44 >>> try: 

45 ... check_examples_in_dir(1, True) 

46 ... except TypeError as te: 

47 ... print(te) 

48 descriptor '__len__' requires a 'str' object but received a 'int' 

49 

50 >>> try: 

51 ... check_examples_in_dir("x", None) 

52 ... except TypeError as te: 

53 ... print(te) 

54 recurse should be an instance of bool but is None. 

55 

56 >>> try: 

57 ... check_examples_in_dir("y", 1) 

58 ... except TypeError as te: 

59 ... print(te) 

60 recurse should be an instance of bool but is int, namely 1. 

61 

62 >>> from pycommons.io.temp import temp_dir 

63 >>> from contextlib import redirect_stdout 

64 >>> with temp_dir() as td, redirect_stdout(None) as rd: 

65 ... try: 

66 ... check_examples_in_dir(td, True) 

67 ... except ValueError as ve: 

68 ... s = str(ve) 

69 >>> print(s[:30]) 

70 No examples found in directory 

71 

72 >>> with temp_dir() as td, redirect_stdout(None) as rd: 

73 ... pystring = "print('hello world!')" 

74 ... td.resolve_inside("1.py").write_all_str(pystring) 

75 ... td.resolve_inside("2.py").write_all_str(pystring) 

76 ... tdx = td.resolve_inside("second") 

77 ... tdx.ensure_dir_exists() 

78 ... tdx.resolve_inside("1.py").write_all_str(pystring) 

79 ... tdx.resolve_inside("2.py").write_all_str(pystring) 

80 ... r1 = check_examples_in_dir(td, True) 

81 ... r2 = check_examples_in_dir(td, False) 

82 >>> print(r1) 

83 4 

84 >>> print(r2) 

85 2 

86 

87 >>> with temp_dir() as td, redirect_stdout(None) as rd: 

88 ... pystring = "print('hello world!')" 

89 ... td.resolve_inside("1.py").write_all_str(pystring) 

90 ... pyerrstring = "1 / 0" 

91 ... td.resolve_inside("2.py").write_all_str(pyerrstring) 

92 ... tdx = td.resolve_inside("second") 

93 ... res = "" 

94 ... try: 

95 ... check_examples_in_dir(td, True) 

96 ... except ValueError as ve: 

97 ... res = str(ve) 

98 >>> print(res[:20]) 

99 Error when executing 

100 """ 

101 # First, we resolve the directories 

102 if not isinstance(recurse, bool): 

103 raise type_error(recurse, "recurse", bool) 

104 examples_dir: Final[Path] = directory_path(directory) 

105 logger(f"Executing all examples in directory {examples_dir!r}.") 

106 

107 files: Final[list[str]] = list(examples_dir.list_dir()) 

108 count: int = list.__len__(files) 

109 total: int = 0 

110 logger(f"Got {count} potential files.") 

111 

112 while count > 0: 

113 choice: int = randint(0, count - 1) # noqa: S311 

114 current: Path = examples_dir.resolve_inside(files[choice]) 

115 del files[choice] 

116 count -= 1 

117 

118 if current.is_file(): 

119 if current.endswith(".py"): # if it is a python file 

120 chars: str = current.read_all_str() 

121 logger(f"Read {str.__len__(chars)} from file {files!r}.") 

122 compile_and_run(chars, current) 

123 total += 1 

124 elif recurse and current.is_dir() and ( 

125 "pycache" not in current.lower()): 

126 total += check_examples_in_dir(current, True) 

127 

128 if total <= 0: 

129 raise ValueError(f"No examples found in directory {directory!r}!") 

130 logger(f"Finished executing {total} examples in directory {directory!r}.") 

131 return total