Coverage for bilby/core/utils/log.py: 67%

63 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2025-05-06 04:57 +0000

1import json 

2import logging 

3from pathlib import Path 

4import subprocess 

5import sys 

6 

7logger = logging.getLogger('bilby') 

8 

9 

10def setup_logger(outdir='.', label=None, log_level='INFO', print_version=False): 

11 """ Setup logging output: call at the start of the script to use 

12 

13 Parameters 

14 ========== 

15 outdir, label: str 

16 If supplied, write the logging output to outdir/label.log 

17 log_level: str, optional 

18 ['debug', 'info', 'warning'] 

19 Either a string from the list above, or an integer as specified 

20 in https://docs.python.org/2/library/logging.html#logging-levels 

21 print_version: bool 

22 If true, print version information 

23 """ 

24 

25 if isinstance(log_level, str): 

26 try: 

27 level = getattr(logging, log_level.upper()) 

28 except AttributeError: 

29 raise ValueError('log_level {} not understood'.format(log_level)) 

30 else: 

31 level = int(log_level) 

32 

33 logger = logging.getLogger('bilby') 

34 logger.propagate = False 

35 logger.setLevel(level) 

36 

37 if not any([isinstance(h, logging.StreamHandler) for h in logger.handlers]): 

38 stream_handler = logging.StreamHandler() 

39 stream_handler.setFormatter(logging.Formatter( 

40 '%(asctime)s %(name)s %(levelname)-8s: %(message)s', datefmt='%H:%M')) 

41 stream_handler.setLevel(level) 

42 logger.addHandler(stream_handler) 

43 

44 if not any([isinstance(h, logging.FileHandler) for h in logger.handlers]): 

45 if label: 

46 Path(outdir).mkdir(parents=True, exist_ok=True) 

47 log_file = '{}/{}.log'.format(outdir, label) 

48 file_handler = logging.FileHandler(log_file) 

49 file_handler.setFormatter(logging.Formatter( 

50 '%(asctime)s %(levelname)-8s: %(message)s', datefmt='%H:%M')) 

51 

52 file_handler.setLevel(level) 

53 logger.addHandler(file_handler) 

54 

55 for handler in logger.handlers: 

56 handler.setLevel(level) 

57 

58 if print_version: 

59 version = get_version_information() 

60 logger.info('Running bilby version: {}'.format(version)) 

61 

62 

63def get_version_information(): 

64 from bilby import __version__ 

65 return __version__ 

66 

67 

68def loaded_modules_dict(): 

69 module_names = list(sys.modules.keys()) 

70 vdict = {} 

71 for key in module_names: 

72 if "." not in str(key): 

73 vdict[key] = str(getattr(sys.modules[key], "__version__", "N/A")) 

74 return vdict 

75 

76 

77def env_package_list(as_dataframe=False): 

78 """Get the list of packages installed in the system prefix. 

79 

80 If it is detected that the system prefix is part of a Conda environment, 

81 a call to ``conda list --prefix {sys.prefix}`` will be made, otherwise 

82 the call will be to ``{sys.executable} -m pip list installed``. 

83 

84 Parameters 

85 ---------- 

86 as_dataframe: bool 

87 return output as a `pandas.DataFrame` 

88 

89 Returns 

90 ------- 

91 pkgs : `list` of `dict`, or `pandas.DataFrame` 

92 If ``as_dataframe=False`` is given, the output is a `list` of `dict`, 

93 one for each package, at least with ``'name'`` and ``'version'`` keys 

94 (more if `conda` is used). 

95 If ``as_dataframe=True`` is given, the output is a `DataFrame` 

96 created from the `list` of `dicts`. 

97 """ 

98 prefix = sys.prefix 

99 

100 # if a conda-meta directory exists, this is a conda environment, so 

101 # use conda to print the package list 

102 conda_detected = (Path(prefix) / "conda-meta").is_dir() 

103 if conda_detected: 

104 try: 

105 pkgs = json.loads(subprocess.check_output([ 

106 "conda", 

107 "list", 

108 "--prefix", prefix, 

109 "--json" 

110 ])) 

111 except (FileNotFoundError, subprocess.CalledProcessError): 

112 # When a conda env is in use but conda is unavailable 

113 conda_detected = False 

114 

115 # otherwise try and use Pip 

116 if not conda_detected: 

117 try: 

118 import pip # noqa: F401 

119 except ModuleNotFoundError: # no pip? 

120 # not a conda environment, and no pip, so just return 

121 # the list of loaded modules 

122 modules = loaded_modules_dict() 

123 pkgs = [{"name": x, "version": y} for x, y in modules.items()] 

124 else: 

125 pkgs = json.loads(subprocess.check_output([ 

126 sys.executable, 

127 "-m", "pip", 

128 "list", "installed", 

129 "--format", "json", 

130 ])) 

131 

132 # convert to recarray for storage 

133 if as_dataframe: 

134 from pandas import DataFrame 

135 return DataFrame(pkgs) 

136 return pkgs