Issue #3602 - Code Review (original) (raw)

OLD

NEW

1 """Python part of the warnings subsystem."""

1 """Python part of the warnings subsystem."""

2

2

3 # Note: function level imports should *not* be used

3 # Note: function level imports should *not* be used

4 # in this module as it may cause import lock deadlock.

4 # in this module as it may cause import lock deadlock.

5 # See bug 683658.

5 # See bug 683658.

6 import linecache

6 import linecache

7 import sys

7 import sys

8 import types

8 import types

9

9

10 __all__ = ["warn", "showwarning", "formatwarning", "filterwarnings",

10 __all__ = ["warn", "showwarning", "formatwarning", "filterwarnings",

(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading...

259 registry[key] = 1

259 registry[key] = 1

260 else:

260 else:

261 # Unrecognized actions are errors

261 # Unrecognized actions are errors

262 raise RuntimeError(

262 raise RuntimeError(

263 "Unrecognized action (%r) in warnings.filters:\n %s" %

263 "Unrecognized action (%r) in warnings.filters:\n %s" %

264 (action, item))

264 (action, item))

265 # Warn if showwarning() does not support the 'line' argument.

265 # Warn if showwarning() does not support the 'line' argument.

266 # Don't use 'inspect' as it relies on an extension module, which break the

266 # Don't use 'inspect' as it relies on an extension module, which break the

267 # build thanks to 'warnings' being imported by setup.py.

267 # build thanks to 'warnings' being imported by setup.py.

268 fxn_code = None

268 fxn_code = None

269 if hasattr(showwarning, 'func_code'):

269 if hasattr(showwarning, 'func_code'):

270 fxn_code = showwarning.func_code

270 fxn_code = showwarning.func_code

271 elif hasattr(showwarning, '__func__'):

271 elif hasattr(showwarning, '__func__'):

272 fxn_code = showwarning.__func__.func_code

272 fxn_code = showwarning.__func__.func_code

273 if fxn_code:

273 if fxn_code:

274 args = fxn_code.co_varnames[:fxn_code.co_argcount]

274 args = fxn_code.co_varnames[:fxn_code.co_argcount]

275 if 'line' not in args:

275 CO_VARARGS = 0x4

276 if 'line' not in args and not fxn_code.co_flags & CO_VARARGS:

276 showwarning_msg = ("functions overriding warnings.showwarning() "

277 showwarning_msg = ("functions overriding warnings.showwarning() "

277 "must support the 'line' argument")

278 "must support the 'line' argument")

278 if message == showwarning_msg:

279 if message == showwarning_msg:

279 _show_warning(message, category, filename, lineno)

280 _show_warning(message, category, filename, lineno)

280 else:

281 else:

281 warn(showwarning_msg, DeprecationWarning)

282 warn(showwarning_msg, DeprecationWarning)

282 # Print message and context

283 # Print message and context

283 showwarning(message, category, filename, lineno)

284 showwarning(message, category, filename, lineno)

284

285

285

286

287 class WarningMessage(object):

288

289 """Holds the result of a single showwarning() call."""

290

291 _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file",

292 "line")

293

294 def __init__(self, message, category, filename, lineno, file=None,

295 line=None):

296 local_values = locals()

297 for attr in self._WARNING_DETAILS:

298 setattr(self, attr, local_values[attr])

299 self._category_name = category.__name__ if category else None

300

301 def __str__(self):

302 return ("{message : %r, category : %r, filename : %r, lineno : %s, "

303 "line : %r}" % (self.message, self._category_name,

304 self.filename, self.lineno, self.line))

305

306

307 class WarningsRecorder(list):

308

309 """Record the result of various showwarning() calls."""

310

311 # Explicitly stated arguments so as to not trigger DeprecationWarning

312 # about adding 'line'.

313 def showwarning(self, *args, **kwargs):

314 self.append(WarningMessage(*args, **kwargs))

315

316 def __getattr__(self, attr):

317 return getattr(self[-1], attr)

318

319 def reset(self):

320 while True:

321 try:

322 self.pop()

323 except IndexError:

324 break

325

326

327 class catch_warnings(object):

328

329 """Guard the warnings filter from being permanently changed and optionally

330 record the details of any warnings that are issued.

331

332 Context manager returns an instance of warnings.WarningRecorder which is a

333 list of WarningMessage instances. Attributes on WarningRecorder are

334 redirected to the last created WarningMessage instance.

335

336 """

337

338 def __init__(self, record=False, module=None):

339 """Specify whether to record warnings and if an alternative module

340 should be used other than sys.modules['warnings'].

341 ·······

342 For compatibility with Python 3.0, please consider all arguments to be

343 keyword-only.

344 ········

345 """

346 self._recorder = WarningsRecorder() if record else None

347 self._module = sys.modules['warnings'] if module is None else module

348

349 def __enter__(self):

350 self._filters = self._module.filters

351 self._module.filters = self._filters[:]

352 self._showwarning = self._module.showwarning

353 if self._recorder is not None:

354 self._recorder.reset() # In case the instance is being reused.

355 self._module.showwarning = self._recorder.showwarning

356 return self._recorder

357

358 def __exit__(self, *exc_info):

359 self._module.filters = self._filters

360 self._module.showwarning = self._showwarning

361

362

286 # filters contains a sequence of filter 5-tuples

363 # filters contains a sequence of filter 5-tuples

287 # The components of the 5-tuple are:

364 # The components of the 5-tuple are:

288 # - an action: error, ignore, always, default, module, or once

365 # - an action: error, ignore, always, default, module, or once

289 # - a compiled regex that must match the warning message

366 # - a compiled regex that must match the warning message

290 # - a class representing the warning category

367 # - a class representing the warning category

291 # - a compiled regex that must match the module that is being warned

368 # - a compiled regex that must match the module that is being warned

292 # - a line number for the line being warning, or 0 to mean any line

369 # - a line number for the line being warning, or 0 to mean any line

293 # If either if the compiled regexs are None, match anything.

370 # If either if the compiled regexs are None, match anything.

294 _warnings_defaults = False

371 _warnings_defaults = False

295 try:

372 try:

(...skipping 15 matching lines...) Expand all Loading...

311 simplefilter("ignore", category=ImportWarning, append=1)

388 simplefilter("ignore", category=ImportWarning, append=1)

312 bytes_warning = sys.flags.bytes_warning

389 bytes_warning = sys.flags.bytes_warning

313 if bytes_warning > 1:

390 if bytes_warning > 1:

314 bytes_action = "error"

391 bytes_action = "error"

315 elif bytes_warning:

392 elif bytes_warning:

316 bytes_action = "default"

393 bytes_action = "default"

317 else:

394 else:

318 bytes_action = "ignore"

395 bytes_action = "ignore"

319 simplefilter(bytes_action, category=BytesWarning, append=1)

396 simplefilter(bytes_action, category=BytesWarning, append=1)

320 del _warnings_defaults

397 del _warnings_defaults

OLD

NEW