Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deep magic underscore error messages rebase #2843

Merged
merged 26 commits into from
Nov 16, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2209b2d
Better magic underscore errors
nicholas-esterer Oct 19, 2020
afd5b7a
Remove whitespace-only changes
nicholas-esterer Oct 20, 2020
b894b89
Assert that errors are raised
nicholas-esterer Oct 20, 2020
4c659db
Also state when a property doesn't support subscripting
nicholas-esterer Oct 20, 2020
2bf2526
Tests for non-subscriptable property errors
nicholas-esterer Oct 20, 2020
5695969
updated changelog
nicholas-esterer Oct 20, 2020
22b3e03
Improved error message when subscripting types that don't support it
nicholas-esterer Oct 23, 2020
c09c03e
Removed garbage line from test_dict_path_errors.py
nicholas-esterer Oct 23, 2020
f4be2b1
Changed PlotlyKeyError's superclass to KeyError
nicholas-esterer Nov 4, 2020
73051a6
BasePlotlyType._raise_on_invalid_property_error raises PlotlyKeyError
nicholas-esterer Nov 4, 2020
651b712
Cast some errors to PlotlyKeyError
nicholas-esterer Nov 4, 2020
9bb2470
Updated the tests to reflect the new Exception behaviour
nicholas-esterer Nov 4, 2020
bf4cd97
BasePlotlyType.__setitem__ exceptions casted to ValueError
nicholas-esterer Nov 5, 2020
7d42ffe
Merge master's whitespace changes
nicholas-esterer Nov 5, 2020
a18b341
Merge branch 'master' into deep-magic-underscore-error-msg-rebase
nicholas-esterer Nov 5, 2020
4bda7b2
Now subscripting errors triggered on types throwing TypeError
nicholas-esterer Nov 5, 2020
9e1b667
subscripting error tests compatible with Python2
nicholas-esterer Nov 5, 2020
d6aee64
Changed dict path error display to always ^
nicholas-esterer Nov 9, 2020
c6e5b4d
Try taking length of string-like objects
nicholas-esterer Nov 9, 2020
82f9bb1
leading, trailing, multiple underscores detected in dict path strings
nicholas-esterer Nov 9, 2020
70f18ca
Added tests for leading, trailing and embedded extra underscore errors
nicholas-esterer Nov 10, 2020
00851fa
Complain about trailing underscores, find closest key
nicholas-esterer Nov 10, 2020
d2bc400
Updated error messages for trailing underscores and find closest key
nicholas-esterer Nov 10, 2020
20518c1
Key guessing before and after list of valid properties
nicholas-esterer Nov 10, 2020
4066ae2
Test single property key guessing
nicholas-esterer Nov 11, 2020
86f4217
Merge branch 'master' into deep-magic-underscore-error-msg-rebase
nicholas-esterer Nov 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ node_modules/

# virtual envs
vv
venv
venv*

# dist files
build
Expand Down
11 changes: 11 additions & 0 deletions packages/python/plotly/_plotly_utils/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,14 @@ def __init__(self, obj, path, notes=()):
super(PlotlyDataTypeError, self).__init__(
message=message, path=path, notes=notes
)


class PlotlyKeyError(LookupError):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is technically a breaking change unfortunately, since this will behave differently:

try:
    fig.update(...)
except KeyError:
    pass

Instead, I think you should be able to subclass KeyError and override the __str__ magic method.

"""
KeyErrors are not printed as beautifully as other errors (this is so that
{}[''] prints "KeyError: ''" and not "KeyError:"). So here we subclass
LookupError to make a PlotlyKeyError object which will print nicer error
messages for KeyErrors.
"""

pass
88 changes: 88 additions & 0 deletions packages/python/plotly/_plotly_utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import json as _json
import sys
import re
from functools import reduce

from _plotly_utils.optional_imports import get_module
from _plotly_utils.basevalidators import ImageUriValidator
Expand All @@ -10,6 +11,20 @@
PY36_OR_LATER = sys.version_info >= (3, 6)


def cumsum(x):
"""
Custom cumsum to avoid a numpy import.
"""

def _reducer(a, x):
if len(a) == 0:
return [x]
return a + [a[-1] + x]

ret = reduce(_reducer, x, [])
return ret


class PlotlyJSONEncoder(_json.JSONEncoder):
"""
Meant to be passed as the `cls` kwarg to json.dumps(obj, cls=..)
Expand Down Expand Up @@ -256,3 +271,76 @@ def _get_int_type():
else:
int_type = (int,)
return int_type


def split_multichar(ss, chars):
"""
Split all the strings in ss at any of the characters in chars.
Example:

>>> ss = ["a.string[0].with_separators"]
>>> chars = list(".[]_")
>>> split_multichar(ss, chars)
['a', 'string', '0', '', 'with', 'separators']

:param (list) ss: A list of strings.
:param (list) chars: Is a list of chars (note: not a string).
"""
if len(chars) == 0:
return ss
c = chars.pop()
ss = reduce(lambda x, y: x + y, map(lambda x: x.split(c), ss))
return split_multichar(ss, chars)


def split_string_positions(ss):
"""
Given a list of strings split using split_multichar, return a list of
integers representing the indices of the first character of every string in
the original string.
Example:

>>> ss = ["a.string[0].with_separators"]
>>> chars = list(".[]_")
>>> ss_split = split_multichar(ss, chars)
>>> ss_split
['a', 'string', '0', '', 'with', 'separators']
>>> split_string_positions(ss_split)
[0, 2, 9, 11, 12, 17]

:param (list) ss: A list of strings.
"""
return list(
map(
lambda t: t[0] + t[1],
zip(range(len(ss)), cumsum([0] + list(map(len, ss[:-1])))),
)
)


def display_string_positions(p, i=None):
"""
Return a string that is whitespace except at p[i] which is replaced with ^.
If i is None then all the indices of the string in p are replaced with ^.
Example:

>>> ss = ["a.string[0].with_separators"]
>>> chars = list(".[]_")
>>> ss_split = split_multichar(ss, chars)
>>> ss_split
['a', 'string', '0', '', 'with', 'separators']
>>> ss_pos = split_string_positions(ss_split)
>>> ss[0]
'a.string[0].with_separators'
>>> display_string_positions(ss_pos,4)
' ^'
:param (list) p: A list of integers.
:param (integer|None) i: Optional index of p to display.
"""
s = [" " for _ in range(max(p) + 1)]
if i is None:
for p_ in p:
s[p_] = "^"
else:
s[p[i]] = "^"
return "".join(s)
Loading