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

32 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2025-12-11 03:04 +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 >>> try: 

24 ... check_examples_in_dir(None, True) 

25 ... except TypeError as te: 

26 ... print(te) 

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

28 

29 >>> try: 

30 ... check_examples_in_dir(1, True) 

31 ... except TypeError as te: 

32 ... print(te) 

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

34 

35 >>> try: 

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

37 ... except TypeError as te: 

38 ... print(te) 

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

40 

41 >>> try: 

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

43 ... except TypeError as te: 

44 ... print(te) 

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

46 

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

48 >>> from contextlib import redirect_stdout 

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

50 ... try: 

51 ... check_examples_in_dir(td, True) 

52 ... except ValueError as ve: 

53 ... s = str(ve) 

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

55 No examples found in directory 

56 

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

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

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

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

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

62 ... tdx.ensure_dir_exists() 

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

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

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

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

67 >>> print(r1) 

68 4 

69 >>> print(r2) 

70 2 

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 ... pyerrstring = "1 / 0" 

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

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

78 ... res = "" 

79 ... try: 

80 ... check_examples_in_dir(td, True) 

81 ... except ValueError as ve: 

82 ... res = str(ve) 

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

84 Error when executing 

85 """ 

86 # First, we resolve the directories 

87 if not isinstance(recurse, bool): 

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

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

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

91 

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

93 count: int = list.__len__(files) 

94 total: int = 0 

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

96 

97 while count > 0: 

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

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

100 del files[choice] 

101 count -= 1 

102 

103 if current.is_file(): 

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

105 chars: str = current.read_all_str() 

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

107 compile_and_run(chars, current) 

108 total += 1 

109 elif recurse and current.is_dir() and ( 

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

111 total += check_examples_in_dir(current, True) 

112 

113 if total <= 0: 

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

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

116 return total