File: C:/Users/fred/anaconda3/Lib/site-packages/astropy/io/fits/verify.py
# Licensed under a 3-clause BSD style license - see PYFITS.rst
import operator
import warnings
from textwrap import indent
from astropy.utils.exceptions import AstropyUserWarning
class VerifyError(Exception):
"""
Verify exception class.
"""
class VerifyWarning(AstropyUserWarning):
"""
Verify warning class.
"""
VERIFY_OPTIONS = [
"ignore",
"warn",
"exception",
"fix",
"silentfix",
"fix+ignore",
"fix+warn",
"fix+exception",
"silentfix+ignore",
"silentfix+warn",
"silentfix+exception",
]
class _Verify:
"""
Shared methods for verification.
"""
def run_option(
self, option="warn", err_text="", fix_text="Fixed.", fix=None, fixable=True
):
"""
Execute the verification with selected option.
"""
text = err_text
if option in ["warn", "exception"]:
fixable = False
# fix the value
elif not fixable:
text = f"Unfixable error: {text}"
else:
if fix:
fix()
text += " " + fix_text
return (fixable, text)
def verify(self, option="warn"):
"""
Verify all values in the instance.
Parameters
----------
option : str
Output verification option. Must be one of ``"fix"``,
``"silentfix"``, ``"ignore"``, ``"warn"``, or
``"exception"``. May also be any combination of ``"fix"`` or
``"silentfix"`` with ``"+ignore"``, ``"+warn"``, or ``"+exception"``
(e.g. ``"fix+warn"``). See :ref:`astropy:verify` for more info.
"""
opt = option.lower()
if opt not in VERIFY_OPTIONS:
raise ValueError(f"Option {option!r} not recognized.")
if opt == "ignore":
return
errs = self._verify(opt)
# Break the verify option into separate options related to reporting of
# errors, and fixing of fixable errors
if "+" in opt:
fix_opt, report_opt = opt.split("+")
elif opt in ["fix", "silentfix"]:
# The original default behavior for 'fix' and 'silentfix' was to
# raise an exception for unfixable errors
fix_opt, report_opt = opt, "exception"
else:
fix_opt, report_opt = None, opt
if fix_opt == "silentfix" and report_opt == "ignore":
# Fixable errors were fixed, but don't report anything
return
if fix_opt == "silentfix":
# Don't print out fixable issues; the first element of each verify
# item is a boolean indicating whether or not the issue was fixable
line_filter = lambda x: not x[0]
elif fix_opt == "fix" and report_opt == "ignore":
# Don't print *unfixable* issues, but do print fixed issues; this
# is probably not very useful but the option exists for
# completeness
line_filter = operator.itemgetter(0)
else:
line_filter = None
unfixable = False
messages = []
for fixable, message in errs.iter_lines(filter=line_filter):
if fixable is not None:
unfixable = not fixable
messages.append(message)
if messages:
messages.insert(0, "Verification reported errors:")
messages.append("Note: astropy.io.fits uses zero-based indexing.\n")
if fix_opt == "silentfix" and not unfixable:
return
elif report_opt == "warn" or (fix_opt == "fix" and not unfixable):
for line in messages:
warnings.warn(line, VerifyWarning)
else:
raise VerifyError("\n" + "\n".join(messages))
class _ErrList(list):
"""
Verification errors list class. It has a nested list structure
constructed by error messages generated by verifications at
different class levels.
"""
def __init__(self, val=(), unit="Element"):
super().__init__(val)
self.unit = unit
def __str__(self):
return "\n".join(item[1] for item in self.iter_lines())
def iter_lines(self, filter=None, shift=0):
"""
Iterate the nested structure as a list of strings with appropriate
indentations for each level of structure.
"""
element = 0
# go through the list twice, first time print out all top level
# messages
for item in self:
if not isinstance(item, _ErrList):
if filter is None or filter(item):
yield item[0], indent(item[1], 4 * shift * " ")
# second time go through the next level items, each of the next level
# must present, even it has nothing.
for item in self:
if isinstance(item, _ErrList):
next_lines = item.iter_lines(filter=filter, shift=shift + 1)
try:
first_line = next(next_lines)
except StopIteration:
first_line = None
if first_line is not None:
if self.unit:
# This line is sort of a header for the next level in
# the hierarchy
yield None, indent(f"{self.unit} {element}:", 4 * shift * " ")
yield first_line
yield from next_lines
element += 1