1818import sys
1919import traceback
2020import warnings
21- from logging import PercentStyle
2221from logging .handlers import TimedRotatingFileHandler
2322
2423from pygments import highlight
2524from pygments .formatters import TerminalFormatter
2625from pygments .lexers import get_lexer_by_name
2726
28- from ..core import exceptions
2927from .color_print import color_text
3028
3129
32- # from textwrap import TextWrapper
33-
34-
3530# Adds custom log level for print and twisted messages
3631PRINT = 15
3732logging .addLevelName (PRINT , 'PRINT' )
@@ -56,13 +51,11 @@ def print_exception_formatted(type, value, tb):
5651def colored_formatter (record ):
5752 """Prints log messages with colours."""
5853
59- colours = {
60- 'info' : ('blue' , 'normal' ),
61- 'debug' : ('magenta' , 'normal' ),
62- 'warning' : ('yellow' , 'normal' ),
63- 'print' : ('green' , 'normal' ),
64- 'error' : ('red' , 'bold' )
65- }
54+ colours = {'info' : ('blue' , 'normal' ),
55+ 'debug' : ('magenta' , 'normal' ),
56+ 'warning' : ('yellow' , 'normal' ),
57+ 'print' : ('green' , 'normal' ),
58+ 'error' : ('red' , 'bold' )}
6659
6760 levelname = record .levelname .lower ()
6861
@@ -74,27 +67,15 @@ def colored_formatter(record):
7467 header = color_text ('[{}]: ' .format (levelname .upper ()),
7568 levelname_color )
7669
77- message = '{0}' . format ( record .msg )
70+ message = record .getMessage ( )
7871
79- warning_category = re .match ('^(\w+Warning\:).*' , message )
80- if warning_category is not None :
81- warning_category_colour = color_text (warning_category .groups ()[0 ],
82- 'cyan' )
83- message = message .replace (warning_category .groups ()[0 ],
84- warning_category_colour )
72+ if levelname == 'warning' :
73+ warning_category_groups = re .match (r'^\w*?(.+?Warning) (.*)' , message )
74+ if warning_category_groups is not None :
75+ warning_category , warning_text = warning_category_groups .groups ()
8576
86- sub_level = re .match ('(\[.+\]:)(.*)' , message )
87- if sub_level is not None :
88- sub_level_name = color_text (sub_level .groups ()[0 ], 'red' )
89- message = '{}{}' .format (sub_level_name , '' .join (
90- sub_level .groups ()[1 :]))
91-
92- # if len(message) > 79:
93- # tw = TextWrapper()
94- # tw.width = 79
95- # tw.subsequent_indent = ' ' * (len(record.levelname) + 2)
96- # tw.break_on_hyphens = False
97- # message = '\n'.join(tw.wrap(message))
77+ warning_category_colour = color_text ('({})' .format (warning_category ), 'cyan' )
78+ message = '{} {}' .format (color_text (warning_text , '' ), warning_category_colour )
9879
9980 sys .__stdout__ .write ('{}{}\n ' .format (header , message ))
10081 sys .__stdout__ .flush ()
@@ -104,42 +85,42 @@ def colored_formatter(record):
10485
10586class MyFormatter (logging .Formatter ):
10687
107- warning_fmt = '%(asctime)s - %(levelname)s: %(message)s [%(origin)s]'
108- info_fmt = '%(asctime)s - %(levelname)s - %(message)s [%(funcName)s @ ' + \
109- '%(filename)s]'
88+ base_fmt = '%(asctime)s - %(levelname)s - %(message)s [%(funcName)s @ %(filename)s]'
11089
11190 ansi_escape = re .compile (r'\x1b[^m]*m' )
11291
92+ def __init__ (self , fmt = '%(levelname)s - %(message)s [%(funcName)s @ %(filename)s]' ):
93+ logging .Formatter .__init__ (self , fmt , datefmt = '%Y-%m-%d %H:%M:%S' )
94+
11395 def format (self , record ):
11496
11597 # Save the original format configured by the user
11698 # when the logger formatter was instantiated
117- # format_orig = self._fmt
99+ format_orig = self ._fmt
118100
119101 # Replace the original format with one customized by logging level
120-
121102 if record .levelno == logging .DEBUG :
122- self ._style = PercentStyle ( MyFormatter .info_fmt )
103+ self ._fmt = MyFormatter .base_fmt
123104
124105 elif record .levelno == logging .getLevelName ('PRINT' ):
125- self ._style = PercentStyle ( MyFormatter .info_fmt )
106+ self ._fmt = MyFormatter .base_fmt
126107
127108 elif record .levelno == logging .INFO :
128- self ._style = PercentStyle ( MyFormatter .info_fmt )
109+ self ._fmt = MyFormatter .base_fmt
129110
130111 elif record .levelno == logging .ERROR :
131- self ._style = PercentStyle ( MyFormatter .info_fmt )
112+ self ._fmt = MyFormatter .base_fmt
132113
133114 elif record .levelno == logging .WARNING :
134- self ._style = PercentStyle ( MyFormatter .warning_fmt )
115+ self ._fmt = MyFormatter .base_fmt
135116
136117 record .msg = self .ansi_escape .sub ('' , record .msg )
137118
138119 # Call the original formatter class to do the grunt work
139120 result = logging .Formatter .format (self , record )
140121
141122 # Restore the original format configured by the user
142- # self._fmt = format_orig
123+ self ._fmt = format_orig
143124
144125 return result
145126
@@ -184,28 +165,6 @@ class MyLogger(Logger):
184165 def save_log (self , path ):
185166 shutil .copyfile (self .log_filename , os .path .expanduser (path ))
186167
187- def _show_warning (self , message , category , * args , ** kwargs ):
188-
189- if not issubclass (category , exceptions .cookiecutter .package_name [0 :1 ]| upper ~ cookiecutter .package_name [1 :]Warning ):
190- warnings ._showwarning_orig (message , category , * args , ** kwargs )
191- return
192-
193- message = '{0}: {1}' .format (message .__class__ .__name__ , message )
194- mod_path = args [0 ]
195-
196- mod_name = None
197- mod_path , ext = os .path .splitext (mod_path )
198- for name , mod in sys .modules .items ():
199- path = os .path .splitext (getattr (mod , '__file__' , '' ))[0 ]
200- if path == mod_path :
201- mod_name = mod .__name__
202- break
203-
204- if mod_name is not None :
205- self .warning (message , extra = {'origin' : mod_name })
206- else :
207- self .warning (message , extra = {'origin' : 'no_module' })
208-
209168 def _catch_exceptions (self , exctype , value , tb ):
210169 """Catches all exceptions and logs them."""
211170
@@ -215,6 +174,50 @@ def _catch_exceptions(self, exctype, value, tb):
215174 # First, we print to stdout with some colouring.
216175 print_exception_formatted (exctype , value , tb )
217176
177+ def warning (self , msg , category = None , use_filters = True ):
178+ """Custom ``logging.warning``.
179+
180+ Behaves like the default ``logging.warning`` but accepts ``category``
181+ and ``use_filters`` as arguments. ``category`` is the type of warning
182+ we are issuing (defaults to `UserWarning`). If ``use_filters=True``,
183+ checks whether there are global filters set for the message or the
184+ warning category and behaves accordingly.
185+
186+ """
187+
188+ if category is None :
189+ category = UserWarning
190+
191+ full_msg = '{0} {1}' .format (category .__name__ , msg )
192+
193+ n_issued = 0
194+ if category in self .warning_registry :
195+ if msg in self .warning_registry [category ]:
196+ n_issued = self .warning_registry [category ]
197+
198+ if use_filters :
199+
200+ category_filter = None
201+ regex_filter = None
202+ for warnings_filter in warnings .filters :
203+ if issubclass (category , warnings_filter [2 ]):
204+ category_filter = warnings_filter [0 ]
205+ regex_filter = warnings_filter [1 ]
206+
207+ if (category_filter == 'ignore' ) or (category_filter == 'once' and n_issued >= 1 ):
208+ if regex_filter is None or regex_filter .search (msg ) is not None :
209+ return
210+
211+ if category_filter == 'error' :
212+ raise ValueError (full_msg )
213+
214+ super (MyLogger , self ).warning (full_msg )
215+
216+ if msg in self .warning_registry [category ]:
217+ self .warning_registry [category ][msg ] += 1
218+ else :
219+ self .warning_registry [category ][msg ] = 1
220+
218221 def _set_defaults (self , log_level = logging .INFO , redirect_stdout = False ):
219222 """Reset logger to its initial state."""
220223
@@ -230,25 +233,13 @@ def _set_defaults(self, log_level=logging.INFO, redirect_stdout=False):
230233
231234 self .sh .setLevel (log_level )
232235
233- self .enable_warnings ()
234-
235236 # Redirects all stdout to the logger
236237 if redirect_stdout :
237238 sys .stdout = LoggerStdout (self ._print )
238239
239240 # Catches exceptions
240241 sys .excepthook = self ._catch_exceptions
241242
242- def enable_warnings (self ):
243- """Redirects warnings to the log."""
244-
245- warnings .showwarning = self ._show_warning
246-
247- def disable_warnings (self ):
248- """Restores normal warning system."""
249-
250- warnings .showwarning = warnings ._show_warning
251-
252243 def start_file_logger (self , path , log_file_level = logging .DEBUG ):
253244 """Start file logging."""
254245
@@ -269,16 +260,16 @@ def start_file_logger(self, path, log_file_level=logging.DEBUG):
269260 str (log_file_path ), when = 'midnight' , utc = True )
270261 self .fh .suffix = '%Y-%m-%d_%H:%M:%S'
271262 except (IOError , OSError ) as ee :
272- warnings . warn ('log file {0!r} could not be opened for writing: '
273- '{1}' . format ( log_file_path , ee ), RuntimeWarning )
263+ self . warning ('log file {0!r} could not be opened for writing: {1}' . format (
264+ log_file_path , ee ), RuntimeWarning )
274265 else :
275266 self .fh .setFormatter (fmt )
276267 self .addHandler (self .fh )
277268 self .fh .setLevel (log_file_level )
278269
279270 self .log_filename = log_file_path
280271
281- def setLevel (self , level ):
272+ def set_level (self , level ):
282273 """Sets levels for both sh and (if initialised) fh."""
283274
284275 self .sh .setLevel (level )
0 commit comments