-
-
Notifications
You must be signed in to change notification settings - Fork 85
Expanded range info shown in HTML repr #821
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
Changes from 3 commits
433e917
bcb8a4c
600c7b2
0fa2f85
c4e90dd
d1cfbf8
d7244b5
3836e04
e7c4d0c
9f9830b
af1465d
7eaf157
f67b710
094722c
c8ed056
bf723f6
f0e3a09
a289244
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,7 @@ | |
| import operator | ||
| import typing | ||
| import warnings | ||
| import html | ||
|
|
||
| # Allow this file to be used standalone if desired, albeit without JSON serialization | ||
| try: | ||
|
|
@@ -3573,39 +3574,65 @@ def _name_if_set(parameterized): | |
| return '' if default_name else parameterized.name | ||
|
|
||
|
|
||
| def _get_param_repr(key, val, p, truncate=40): | ||
| def truncate(str_, maxlen = 30): | ||
| """Return HTML-safe truncated version of given string""" | ||
| rep = (str_[:(maxlen-2)] + '..') if (len(str_) > (maxlen-2)) else str_ | ||
| return html.escape(rep) | ||
|
|
||
|
|
||
| def _get_param_repr(key, val, p, vallen=30, doclen=40): | ||
| """HTML representation for a single Parameter object and its value""" | ||
| if hasattr(val, "_repr_html_"): | ||
| try: | ||
| value = val._repr_html_(open=False) | ||
| except: | ||
| value = val._repr_html_() | ||
| else: | ||
| rep = repr(val) | ||
| value = (rep[:truncate] + '..') if len(rep) > truncate else rep | ||
| value = truncate(repr(val), vallen) | ||
|
|
||
| modes = [] | ||
| if p.constant: | ||
| modes.append('constant') | ||
| if p.readonly: | ||
| modes.append('read-only') | ||
| if getattr(p, 'allow_None', False): | ||
| modes.append('nullable') | ||
| mode = ' | '.join(modes) | ||
| if hasattr(p, 'bounds'): | ||
| bounds = p.bounds | ||
| if p.bounds is None: | ||
| range_ = '(-∞,∞)' | ||
| elif hasattr(p,'inclusive_bounds'): | ||
| # Numeric bounds use ( and [ to indicate exclusive and inclusive | ||
| bl,bu = p.bounds | ||
| il,iu = p.inclusive_bounds | ||
| lb = ('[' if il else '(') + ('-∞' if bl is None else str(bl)) | ||
| ub = ('∞' if bu is None else str(bu)) + (']' if iu else ')') | ||
| range_ = lb + ', ' + ub | ||
| else: | ||
| range_ = repr(p.bounds) | ||
| elif hasattr(p, 'objects') and p.objects: | ||
| bounds = ', '.join(list(map(repr, p.objects))) | ||
| range_ = ', '.join(list(map(repr, p.objects))) | ||
| elif hasattr(p, 'class_'): | ||
| if isinstance(p.class_, tuple): | ||
| range_ = ' | '.join(kls.__name__ for kls in p.class_) | ||
| else: | ||
| range_ = p.class_.__name__ | ||
| elif hasattr(p, 'regex'): | ||
| range_ = '.*' if p.regex is None else str(p.regex) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it's super frequent to define a regex for a
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The reason to include it is only that when
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I agree that most options here aren't very good. Not sure I love it but if there's no regex I'd also be okay with
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (That's the same reason I went with (-Inf,Inf) for numbers;
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm; looks like @philippjfr 's notes weren't updated on my screen until after I made the above note. I don't mind "str", but I'd like us to use the same approach for number parameters as for string, since it's precisely the same concept: any allowed string, or any allowed number. Instead of (-Inf, Inf), would a number be "num" in this approach, as in "num | None"?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, None is a different type, so I suppose we really ought to be putting it into the Type column! I.e. the type isn't really Assuming we do that, then there is still a question whether to combine the type and range columns. Combining them makes it clear that the constraints apply to the non-None type, not None: I can't quite decide which I prefer; any votes? |
||
| else: | ||
| bounds = '' | ||
| range_ = '' | ||
|
|
||
| if p.readonly: | ||
| range_ = ' '.join(['<i>read-only</i>', range_]) | ||
| elif p.constant: | ||
| range_ = ' '.join(['<i>constant</i>', range_]) | ||
|
|
||
| if getattr(p, 'allow_None', False): | ||
| range_ = ' | '.join(['None', range_]) | ||
|
|
||
| tooltip = f' class="param-doc-tooltip" data-tooltip="{escape(p.doc.strip())}"' if p.doc else '' | ||
|
|
||
| doc = "" if p.doc is None else truncate(p.doc.strip(), doclen) | ||
|
|
||
| return ( | ||
| f'<tr>' | ||
| f' <td><tt{tooltip}>{key}</tt></td>' | ||
| f' <td><p{tooltip}>{key}</p></td>' | ||
| f' <td style="max-width: 200px;">{value}</td>' | ||
| f' <td>{p.__class__.__name__}</td>' | ||
| f' <td>{value}</td>' | ||
| f' <td style="max-width: 300px;">{bounds}</td>' | ||
| f' <td>{mode}</td>' | ||
| f' <td style="max-width: 300px;">{range_}</td>' | ||
| f' <td style="max-width: 500px;"><p{tooltip}>{doc}</p></td>' | ||
| f'</tr>\n' | ||
| ) | ||
|
|
||
|
|
@@ -3652,8 +3679,9 @@ def _parameterized_repr_html(p, open): | |
| } | ||
| """ | ||
| openstr = " open" if open else "" | ||
| contents = "".join(_get_param_repr(key, val, p.param.params(key)) | ||
| for key, val in p.param.get_param_values()) | ||
| param_values = p.param.values().items() | ||
| contents = "".join(_get_param_repr(key, val, p.param[key]) | ||
| for key, val in param_values) | ||
| return ( | ||
| f'<style>{tooltip_css}</style>\n' | ||
| f'<details {openstr}>\n' | ||
|
|
@@ -3662,7 +3690,7 @@ def _parameterized_repr_html(p, open): | |
| ' </summary>\n' | ||
| ' <div style="padding-left:10px; padding-bottom:5px;">\n' | ||
| ' <table style="max-width:100%; border:1px solid #AAAAAA;">\n' | ||
| f' <tr><th>Name</th><th>Type</th><th>{value_field}</th><th>Bounds/Objects</th><th>Mode</th></tr>\n' | ||
| f' <tr><th>Name</th><th>{value_field}</th><th>Type</th><th>Range</th><th>Doc</th></tr>\n' | ||
| f'{contents}\n' | ||
| ' </table>\n </div>\n</details>\n' | ||
| ) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import param | ||
|
|
||
| from param.parameterized import _parameterized_repr_html | ||
|
|
||
|
|
||
| def test_repr_html_ClassSelector_tuple(): | ||
| class P(param.Parameterized): | ||
| c = param.ClassSelector(class_=(str, int)) | ||
|
|
||
| rhtml = _parameterized_repr_html(P, True) | ||
| assert 'None | str | int' in rhtml |
Uh oh!
There was an error while loading. Please reload this page.