webhelpers2: added backport code not compatible with python3.11.
This commit is contained in:
parent
0c53201403
commit
3731a4a02c
1 changed files with 137 additions and 0 deletions
137
rhodecode/lib/_vendor/webhelpers_backports/__init__.py
Normal file
137
rhodecode/lib/_vendor/webhelpers_backports/__init__.py
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
# backport of broken code for python 3.11 on webhelpers2
|
||||
|
||||
import collections
|
||||
from webhelpers2.misc import NotGiven
|
||||
from webhelpers2.html.tags import _set_id_attr, NL, _OptionsList, OptGroup, HTML
|
||||
|
||||
|
||||
class Options(_OptionsList):
|
||||
"""A list of options and/or optgroups for a select or datalist.
|
||||
|
||||
I'm a subclass of ``list``. My elements are ``Option`` and/or ``OptGroup``
|
||||
instances. Do not add other element types or they may cause
|
||||
``options.render`` or ``str(options)`` to fail.
|
||||
"""
|
||||
|
||||
def __init__(self, options=None, prompt=None):
|
||||
"""Construct an ``Options`` instance.
|
||||
|
||||
**options**: An iterable of ``Option`` instances, ``OptGroup``
|
||||
instances and/or strings. If you pass strings, they will be converted
|
||||
to simple ``Option`` instances (i.e., the label will be the string, and
|
||||
the value will be ``None``).
|
||||
|
||||
**prompt**: If passed, this will be turned into an extra option before
|
||||
the others. The string argument will become the option's label, and
|
||||
the option's value will be the empty string.
|
||||
"""
|
||||
if prompt:
|
||||
self.add_option(prompt, "")
|
||||
if options:
|
||||
self._parse_options(options)
|
||||
|
||||
def __repr__(self):
|
||||
classname = self.__class__.__name__
|
||||
return "{0}({1!r})".format(classname, list(self))
|
||||
|
||||
def add_optgroup(self, label, options=None):
|
||||
"""Create an ``OptGroup``, append it, and return it.
|
||||
|
||||
The return value is the ``OptGroup`` instance. Call its
|
||||
``.add_option`` method to add options to the group.
|
||||
"""
|
||||
group = OptGroup(label, options)
|
||||
self.append(group)
|
||||
return group
|
||||
|
||||
def render(self, selected_values=None):
|
||||
"""
|
||||
Render the options as a concatenated literal of <option> and/or
|
||||
<optgroup> tags, with a newline after each.
|
||||
|
||||
**selected_values**: The value(s) that should be preselected. You
|
||||
can pass a string, int, bool, or other scalar type, or a sequence of
|
||||
these. If you pass a scalar it will be standardized to a one-element
|
||||
tuple. If you don't pass anything, it will default to ``("",)`` (a tuple
|
||||
containing the empty string); this will correctly preselect prompts.
|
||||
|
||||
Note that ``selected_values`` *does not do type conversions*. If you
|
||||
pass an int, the corresponding ``Option.value`` must also be an int or
|
||||
otherwise equal to it. (The actual comparision operator is ``in``.)
|
||||
|
||||
Calling ``str(options)`` or ``options.__html__()`` is the same as
|
||||
calling ``options.render()`` without arguments. This is only useful if
|
||||
you don't want to pass any selected values.
|
||||
"""
|
||||
|
||||
selected_values = self._parse_selected_values(selected_values)
|
||||
return self._render(self, selected_values)
|
||||
|
||||
__str__ = __html__ = render
|
||||
|
||||
def _render(self, options, selected_values):
|
||||
tags = []
|
||||
for opt in options:
|
||||
if isinstance(opt, OptGroup):
|
||||
content = self._render(opt, selected_values)
|
||||
tag = HTML.tag("optgroup", NL, content, label=opt.label)
|
||||
tags.append(tag)
|
||||
else:
|
||||
value = opt.value if opt.value is not None else opt.label
|
||||
selected = value in selected_values
|
||||
tag = HTML.tag("option", opt.label, value=opt.value, selected=selected)
|
||||
tags.append(tag)
|
||||
return HTML(*tags, nl=True)
|
||||
|
||||
@staticmethod
|
||||
def _parse_selected_values(values):
|
||||
if values is None:
|
||||
return ("",)
|
||||
is_string = isinstance(values, str)
|
||||
is_seq = isinstance(values, collections.abc.Sequence)
|
||||
if is_string or not is_seq:
|
||||
return (values,)
|
||||
else:
|
||||
return values
|
||||
|
||||
|
||||
def raw_select(name, selected_values, options, id=NotGiven, **attrs):
|
||||
"""Create a dropdown selection box.
|
||||
|
||||
Arguments:
|
||||
|
||||
* **name**: the name of this control.
|
||||
|
||||
* **selected_values**: the value(s) that should be preselected.
|
||||
A string or list of strings. Some other types are allowed; see the
|
||||
``Options.render`` method for details.
|
||||
|
||||
* **options**: an ``Options`` instance, or an iterable to pass to the
|
||||
its constructor. See the ``Options`` class for allowed element types.
|
||||
|
||||
* **id**: the HTML ID attribute. This should be a keyword argument if
|
||||
passed. By default the ID is the same as the name. filtered through
|
||||
``_make_safe_id_component()``. Pass None to suppress the
|
||||
ID attribute entirely.
|
||||
|
||||
The following options may only be keyword arguments:
|
||||
|
||||
* **multiple**: if true, this control will allow multiple
|
||||
selections.
|
||||
|
||||
* **prompt**: An extra option that will be prepended to the list.
|
||||
The argument is the option label; e.g., "Please choose ...". The generated
|
||||
option's value will be the empty string (""), which is equivalent to not
|
||||
making a selection. If you specify this and also pass an ``Options``
|
||||
instance in ``options``, it will combine the two into a new ``Options``
|
||||
object rather than reusing the existing one.
|
||||
|
||||
Any other keyword args will become HTML attributes for the <select>.
|
||||
"""
|
||||
|
||||
_set_id_attr(attrs, id, name)
|
||||
attrs["name"] = name
|
||||
prompt = attrs.pop("prompt", None)
|
||||
if prompt or not isinstance(options, Options):
|
||||
options = Options(options, prompt=prompt)
|
||||
return HTML.tag("select", NL, options.render(selected_values), **attrs)
|
||||
Loading…
Add table
Add a link
Reference in a new issue