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 151 152 153 154 155 156 157 158 159 160 161 162
|
"""Getting specific information for IndexError"""
import ast
import re
from typing import Dict
import pure_eval
from .. import debug_helper, info_variables
from ..ft_gettext import current_lang
from ..message_parser import get_parser
from ..tb_data import TracebackData # for type checking only
from ..typing_info import CauseInfo # for type checking only
parser = get_parser(IndexError)
_ = current_lang.translate
@parser._add
def object_assignment_out_of_range(message: str, tb_data: TracebackData) -> CauseInfo:
pattern = re.compile(r"(.*) assignment index out of range")
match = re.search(pattern, message)
if not match:
return {}
obj_type = match[1]
frame = tb_data.exception_frame
# first, try to identify object
left_hand_side = tb_data.bad_line.split("=")[0].strip()
all_objects = info_variables.get_all_objects(left_hand_side, frame)
for name, sequence in all_objects["name, obj"]:
truncated = left_hand_side.replace(name, "", 1).strip()
if truncated.startswith("[") and truncated.endswith("]"):
break
else: # pragma: no cover
cause = _(
"You have tried to assign a value to an item of an object\n"
"of type `{obj_type}` which I cannot identify.\n"
"The index you gave was not an allowed value.\n"
).format(obj_type=obj_type)
return {"cause": cause}
index = truncated[1:-1]
length = len(sequence)
cause = _(
"You have tried to assign a value to index `{index}` of `{name}`,\n"
"{obj_type} of length `{length}`.\n"
).format(
index=index,
name=name,
length=length,
obj_type=info_variables.convert_type(obj_type),
)
if length != 0:
cause += _(
"The valid index values of `{name}` are integers ranging from\n"
"`{min}` to `{max}`.\n"
).format(name=name, min=-length, max=length - 1)
if index == length:
hint = _(
"Remember: the first item of {obj_type} is not at index 1 but at index 0.\n"
).format(obj_type=info_variables.convert_type(obj_type))
return {"cause": cause, "suggest": hint}
else:
hint = _("`{name}` contains no item.\n").format(name=name)
cause = _(
"You have tried to assign a value to index `{index}` of `{name}`,\n"
"{obj_type} which contains no item.\n"
).format(index=index, name=name, obj_type=info_variables.convert_type(obj_type))
return {"cause": cause, "suggest": hint}
return {"cause": cause}
def cannot_identify_object(obj_type: str, bad_line: str) -> Dict:
message = f"Cannot identify `{obj_type}` object. line: {bad_line}"
debug_helper.log(message)
cause = _(
"You have tried to get an item of an object\n"
"of type `{obj_type}` which I cannot identify.\n"
"The index you gave was not an allowed value.\n"
).format(obj_type=obj_type)
return {"cause": cause}
@parser._add
def index_out_of_range(message: str, tb_data: TracebackData) -> CauseInfo:
pattern = re.compile(r"(.*) index out of range")
match = re.search(pattern, message)
if not match:
return {}
obj_type = match[1]
frame = tb_data.exception_frame
bad_line = tb_data.bad_line
# first, try to identify object
all_objects = info_variables.get_all_objects(bad_line, frame)
for name, sequence in all_objects["name, obj"]:
truncated = bad_line.replace(name, "", 1).strip()
if truncated.startswith("[") and truncated.endswith("]"):
break
else: # pragma: no cover
return cannot_identify_object(obj_type, bad_line)
try:
node = tb_data.node
except Exception: # noqa # pragma: no cover
return cannot_identify_object(obj_type, bad_line)
if not (node and isinstance(node, ast.Subscript)): # pragma: no cover
return cannot_identify_object(obj_type, bad_line)
length = len(sequence)
evaluator = pure_eval.Evaluator.from_frame(frame)
# The information that we want may differ for different Python versions
try:
index = evaluator[node.slice.value] # noqa
except Exception: # noqa
try:
index = evaluator[node.slice]
except Exception: # noqa # pragma: no cover
debug_helper.log("Unknown index: new case to consider.")
cause = _(
"You have tried to get an item from `{name}`,\n"
"{obj_type} of length `{length}`, by using a value for the index\n"
"that I cannot determine but which is not allowed.\n"
).format(
name=name, length=length, obj_type=info_variables.convert_type(obj_type)
)
return {"cause": cause}
cause = _(
"You have tried to get the item with index `{index}` of `{name}`,\n"
"{obj_type} of length `{length}`.\n"
).format(
index=index,
name=name,
length=length,
obj_type=info_variables.convert_type(obj_type),
)
if length != 0:
cause += _(
"The valid index values of `{name}` are integers ranging from\n"
"`{min}` to `{max}`.\n"
).format(name=name, min=-length, max=length - 1)
if index == length:
hint = _(
"Remember: the first item of {obj_type} is not at index 1 but at index 0.\n"
).format(obj_type=info_variables.convert_type(obj_type))
return {"cause": cause, "suggest": hint}
else:
hint = _("`{name}` contains no item.\n").format(name=name)
cause = _(
"You have tried to get the item with index `{index}` of `{name}`,\n"
"{obj_type} which contains no item.\n"
).format(index=index, name=name, obj_type=info_variables.convert_type(obj_type))
return {"cause": cause, "suggest": hint}
return {"cause": cause}
|