# HG changeset patch # User RhodeCode Admin # Date 2023-03-10 09:02:43 # Node ID 9268931e623aa8daf1e8db1fb60b69f3cbcda253 # Parent e4140a41413f128f0c3b2a1ccacd8765ab92c7bd webhelpers2: added backport code not compatible with python3.11. diff --git a/rhodecode/lib/_vendor/webhelpers_backports/__init__.py b/rhodecode/lib/_vendor/webhelpers_backports/__init__.py new file mode 100644 --- /dev/null +++ b/rhodecode/lib/_vendor/webhelpers_backports/__init__.py @@ -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 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