Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

"""Logging utilities""" 

from __future__ import unicode_literals, print_function, absolute_import, division 

import os 

import sys 

import logging 

from logging.config import fileConfig 

from tempfile import NamedTemporaryFile 

import warnings 

 

from six import text_type 

 

from .config import Config 

 

 

LOGGING = """ 

[loggers] 

keys = root, lingpy 

 

[handlers] 

keys = console 

 

[formatters] 

keys = generic 

 

[logger_root] 

level = INFO 

handlers = console 

 

[logger_lingpy] 

# a level of WARN is equivalent to lingpy's defaults of verbose=False, debug=False 

level = INFO 

handlers = 

qualname = lingpy 

 

[handler_console] 

class = StreamHandler 

args = (sys.stderr,) 

level = INFO 

formatter = generic 

 

[formatter_generic] 

format = %(asctime)s [%(levelname)s] %(message)s 

""" 

 

_logger = None 

 

 

class CustomFilter(logging.Filter): 

def filter(self, record): 

if getattr(record, 'lines', None): 

for line in record.lines: 

record.msg = record.msg + '\n\t' + '%s' % (line,) 

return super(CustomFilter, self).filter(record) 

 

 

def get_logger(config_dir=None, force_default_config=False, test=False): 

"""Get a logger configured according to the lingpy log config file. 

 

Note: If no logging configuration file exists, it will be created. 

 

:param config_dir: Directory in which to look for/create the log config file. 

:param force_default_config: Configure the logger using the default config. 

:param test: Force reconfiguration of the logger. 

:return: A logger. 

""" 

global _logger 

if _logger is None or force_default_config or test: 

_logger = logging.getLogger('lingpy') 

_logger.addFilter(CustomFilter()) 

testing = len(sys.argv) and sys.argv[0].endswith('nosetests') 

if not (force_default_config or test) and testing: 

_logger.setLevel(logging.CRITICAL) 

else: 

cfg = Config('logging', default=LOGGING, config_dir=config_dir) 

remove = False 

if cfg.path.exists() and not force_default_config: 

fname = text_type(cfg.path) 

else: 

with NamedTemporaryFile(delete=False) as fp: 

fp.write(LOGGING.encode('utf8')) 

fname = fp.name 

remove = True 

fileConfig(fname, disable_existing_loggers=False) 

if remove: 

os.remove(fname) 

return _logger 

 

 

def get_level(): 

return get_logger().getEffectiveLevel() 

 

 

def info(msg, **kw): 

get_logger().info(msg, **kw) 

 

 

def warn(msg): 

get_logger().warn(msg) 

 

 

def debug(msg, **kw): 

get_logger().debug(msg, **kw) 

 

 

def error(msg, **kw): 

get_logger().error(msg, **kw) 

 

 

def file_written(fname, logger=None): 

logger = logger or get_logger() 

logger.info("Data has been written to file <{0}>.".format(fname)) 

 

 

def deprecated(old, new): 

warnings.warn( 

"Use of '{0}' is deprecated, use '{1}' instead.".format(old, new), 

DeprecationWarning) 

 

 

def missing_module(name, logger=None): 

logger = logger or get_logger() 

logger.warn( 

"Module '{0}' could not be loaded. Some methods may not work properly.".format( 

name)) 

 

 

class Logging(object): 

""" 

A context manager to execute a block of code at a specific logging level. 

""" 

def __init__(self, level=logging.DEBUG, logger=None): 

self.level = level 

self.logger = logger or get_logger() 

self.linpy_logger_level = self.logger.getEffectiveLevel() 

root = logging.getLogger() 

self.root_logger_level = root.getEffectiveLevel() 

self.root_handler_level = root.handlers[0].level 

 

def __enter__(self): 

self.logger.setLevel(self.level) 

root = logging.getLogger() 

root.setLevel(self.level) 

root.handlers[0].setLevel(self.level) 

return self.logger 

 

def __exit__(self, exc_type, exc_val, exc_tb): 

self.logger.setLevel(self.linpy_logger_level) 

root = logging.getLogger() 

root.setLevel(self.root_logger_level) 

root.handlers[0].setLevel(self.root_handler_level)