<commit_before>import re

import six

from nerodia.exception import Error, NoValueFoundException, UnknownObjectException
from nerodia.wait.wait import TimeoutError
from .html_elements import HTMLElement
from .option import Option
from ..meta_elements import MetaHTMLElement
from ..wait.wait import Wait


@six.add_metaclass(MetaHTMLElement)
class Select(HTMLElement):
    def clear(self):
        """ Clears all selected options """
        if not self.multiple:
            raise Error('you can only clear multi-selects')

        for option in self.options():
            if option.selected:
                self.click_option(option)

    def options(self, *args, **kwargs):
        """
        Gets all the options in the select list

        :rtype: nerodia.elements.option.OptionColletion
        """
        return self._element_call(lambda: super(Select, self).options(*args, **kwargs),
                                  self.wait_for_exists)

    def includes(self, term):
        """
        Returns True if the select list has at least one option where text or label matches the
        given value
        :param term: string or regex to match against the option
        :rtype: bool
        """
        def func():
            elements = self.el.find_elements_by_css_selector('option')
            for e in elements:
                text = e.text
                label = e.get_attribute('label')
                if term in [text, label] or re.search(term, text) or re.search(term, label):
                    return True
            return False
        return self._element_call(func)

    def select(self, term):
        """
        Select the option(s) whose text or label matches the given string
        If this is a multi-select and several options match the value given, all will be selected
        :param term: string or regex to match against the option
        :return:
        """
        self._select_by('text', term)

    def select_value(self, value):
        """
        Selects the option(s) whose value attribute matches the given string
        If this is a multi-select and several options match the value given, all will be selected
        :param value: string or regex to match against the option
        """
        self._select_by('value', value)

    def is_selected(self, term):
        """
        Returns True if any of the selected options' text or label matches the given value
        :param term: string or regex to match against the option
        :rtype: bool
        :raises: UnknownObjectException
        """
        def func():
            elements = self.el.find_elements_by_css_selector('option')
            for e in elements:
                text = e.text
                label = e.get_attribute('label')
                if term in [text, label] or re.search(term, text) or re.search(term, label):
                    if e.is_selected():
                        return True
            return False
        result = self._element_call(func)
        if result is not True:
            raise UnknownObjectException('Unable to locate option matching {}'.format(term))
        return result

    @property
    def value(self):
        """
        Returns the value of the first selected option in the select list
        Returns None if no option is selected
        :rtype: str or None
        """
        selected = self.selected_options
        return selected[0] if selected else None

    @property
    def text(self):
        # Returns the text of the first selected option in the select list
        # Returns nil if no option is selected
        # :rtype: str or None
        return next((o.text for o in self.options() if o.is_selected()), None)

    @property
    def selected_options(self):
        """
        Returns an array of currently selected options
        :rtype: list[nerodia.elements.option.Option]
        """
        script = 'var result = [];' \
                 'var options = arguments[0].options;' \
                 'for (var i = 0; i < options.length; i++) {' \
                 '  var option = options[i];' \
                 '  if (option.selected) { result.push(option) }' \
                 '}' \
                 'return result;'
        return self._element_call(lambda: self.query_scope.execute_script(script, self.el))

    # private

    def _select_by(self, how, term):
        found = []

        def func(sel):
            if type(term) in [str, int, re._pattern_type]:
                opt = {how: term}
                found.extend(sel.options(**opt))
                if not list(found):
                    found.extend(self.options(label=term))
            else:
                raise TypeError('expected str, got {}:{}'.format(term, term.__class__))<commit_msg>update Select#text to use new Select#value implementation<commit_after>import re

import six

from nerodia.exception import Error, NoValueFoundException, UnknownObjectException
from nerodia.wait.wait import TimeoutError
from .html_elements import HTMLElement
from .option import Option
from ..meta_elements import MetaHTMLElement
from ..wait.wait import Wait


@six.add_metaclass(MetaHTMLElement)
class Select(HTMLElement):
    def clear(self):
        """ Clears all selected options """
        if not self.multiple:
            raise Error('you can only clear multi-selects')

        for option in self.options():
            if option.selected:
                self.click_option(option)

    def options(self, *args, **kwargs):
        """
        Gets all the options in the select list

        :rtype: nerodia.elements.option.OptionColletion
        """
        return self._element_call(lambda: super(Select, self).options(*args, **kwargs),
                                  self.wait_for_exists)

    def includes(self, term):
        """
        Returns True if the select list has at least one option where text or label matches the
        given value
        :param term: string or regex to match against the option
        :rtype: bool
        """
        def func():
            elements = self.el.find_elements_by_css_selector('option')
            for e in elements:
                text = e.text
                label = e.get_attribute('label')
                if term in [text, label] or re.search(term, text) or re.search(term, label):
                    return True
            return False
        return self._element_call(func)

    def select(self, term):
        """
        Select the option(s) whose text or label matches the given string
        If this is a multi-select and several options match the value given, all will be selected
        :param term: string or regex to match against the option
        :return:
        """
        self._select_by('text', term)

    def select_value(self, value):
        """
        Selects the option(s) whose value attribute matches the given string
        If this is a multi-select and several options match the value given, all will be selected
        :param value: string or regex to match against the option
        """
        self._select_by('value', value)

    def is_selected(self, term):
        """
        Returns True if any of the selected options' text or label matches the given value
        :param term: string or regex to match against the option
        :rtype: bool
        :raises: UnknownObjectException
        """
        def func():
            elements = self.el.find_elements_by_css_selector('option')
            for e in elements:
                text = e.text
                label = e.get_attribute('label')
                if term in [text, label] or re.search(term, text) or re.search(term, label):
                    if e.is_selected():
                        return True
            return False
        result = self._element_call(func)
        if result is not True:
            raise UnknownObjectException('Unable to locate option matching {}'.format(term))
        return result

    @property
    def value(self):
        """
        Returns the value of the first selected option in the select list
        Returns None if no option is selected
        :rtype: str or None
        """
        selected = self.selected_options
        return selected[0].value if selected else None

    @property
    def text(self):
        # Returns the text of the first selected option in the select list
        # Returns nil if no option is selected
        # :rtype: str or None
        selected = self.selected_options
        return selected[0].text if selected else None

    @property
    def selected_options(self):
        """
        Returns an array of currently selected options
        :rtype: list[nerodia.elements.option.Option]
        """
        script = 'var result = [];' \
                 'var options = arguments[0].options;' \
                 'for (var i = 0; i < options.length; i++) {' \
                 '  var option = options[i];' \
                 '  if (option.selected) { result.push(option) }' \
                 '}' \
                 'return result;'
        return self._element_call(lambda: self.query_scope.execute_script(script, self.el))

    # private

    def _select_by(self, how, term):
        found = []

        def func(sel):
            if type(term) in [str, int, re._pattern_type]:
                opt = {how: term}
                found.extend(sel.options(**opt))
                if not list(found):
                    found.extend(self.options(label=term))
            else:
                raise TypeError('expected str, got {}:{}'.format(term, term.__class__))
{'fraction_non_alphanumeric': 0.08681135225375626, 'fraction_numerical': 0.0007303839732888147, 'mean_word_length': 1.944700460829493, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4861963', 'n_tokens_mistral': 2469, 'n_tokens_neox': 2398, 'n_words': 872}