def is_valid_pseudo_format(self, pseudo_item='', css_class=''):
        """ Returns True if the CSS class contains a properly formatted pseudo class or element, and False otherwise.

        **Rules**

        - The ``css_class`` may end with '-' + pseudo_item. Example prefix: ``color-green-i-hover``

        - The ``css_class`` may end with '-' + pseudo_item + '-i'. Example prefix: ``color-green-hover-i``

        - The ``css_class`` must be longer than the suffix or suffix + '-i'.

        :type pseudo_item: str
        :type css_class: str

        :param pseudo_item: Either a pseudo class or pseudo element as defined
            `here <http://www.w3schools.com/css/css_pseudo_classes.asp>`__
        :param css_class: This value may or may not be identical to the property_value.
        :return: *bool* -- Returns True if the CSS class contains the pseudo item, and False otherwise.

        """
        deny_empty_or_whitespace(string=pseudo_item, variable_name='pseudo_item')
        deny_empty_or_whitespace(string=css_class, variable_name='css_class')

        suffix = '-' + pseudo_item
        isuffix = suffix + self.importance_designator

        if css_class.endswith(suffix) and len(css_class) > len(suffix):     # '-i-hover' case
            return True

        if css_class.endswith(isuffix) and len(css_class) > len(isuffix):   # '-hover-i' case
            return True

        return False
    def strip_property_abbreviation(self, property_name='', css_class=''):
        """
        Strip property abbreviation from css_class if applicable and return the result.

        :raises ValueError: If either property_name or css_class are empty or only contain whitespace values.

        :type property_name: str
        :type css_class: str

        :param property_name: Presumed to match a key or value in the ``property_alias_dict``
        :param css_class: Initially this value may or may not contain the property_name.
        :return: (str) -- Returns the encoded property value portion of the css_class.

        **Examples:**

        >>> property_parser = ClassPropertyParser()
        >>> property_parser.strip_property_abbreviation('color', 'c-lime')
        'lime'
        >>> property_parser.strip_property_abbreviation('', 'c-lime')
        ValueError
        >>> property_parser.strip_property_abbreviation('color', '  ')
        ValueError

        """
        deny_empty_or_whitespace(string=css_class, variable_name='css_class')
        deny_empty_or_whitespace(string=property_name, variable_name='property_name')

        property_abbreviations = self.get_property_abbreviations(property_name=property_name)

        for property_abbreviation in property_abbreviations:
            if css_class.startswith(property_abbreviation):
                return css_class[len(property_abbreviation):]
        return css_class
    def strip_property_name(property_name='', css_class=''):
        """
        Strip property name from css_class if applicable and return the css_class.

        :raises ValueError: If either property_name or css_class are empty or only contain whitespace values.

        :type property_name: str
        :type css_class: str

        :param property_name: Presumed to match a key or value in the ``property_alias_dict``.
        :param css_class: This value may or may not be identical to the property_value.
        :return: (str) -- Returns the encoded property value portion of the css_class.

        **Examples:**

        >>> ClassPropertyParser.strip_property_name('padding', 'padding-1-2-1-2')
        '1-2-1-2'
        >>> ClassPropertyParser.strip_property_name('font-weight', 'bold')
        'bold'
        >>> ClassPropertyParser.strip_property_name('', 'padding-1-2-1-2')
        ValueError
        >>> ClassPropertyParser.strip_property_name('font-weight', '    ')
        ValueError
        
        """
        deny_empty_or_whitespace(string=css_class, variable_name='css_class')
        deny_empty_or_whitespace(string=property_name, variable_name='property_name')

        property_name += '-'                                        # Append '-' to property to match the class format.

        if css_class.startswith(property_name):                     # Strip property name
            return css_class[len(property_name):]
        else:                                                       # If it doesn't have a property name ignore it.
            return css_class
    def __init__(self, css_class='', css_property=Property()):
        deny_empty_or_whitespace(css_class, variable_name='css_class')
        deny_empty_or_whitespace(css_property.cssText, variable_name='css_property')

        self.css_class = css_class
        self.css_property = css_property
        self.scale_dict = {
            'large': 1.043,
            'medium': 1.125,
            'small': 1.25,
        }
        self.scaling_flag = '-s'
        self.is_scaling = self._is_scaling()
    def set_pseudo_element(self, css_class=''):
        """ Check the pseudo element set for a match. Sets the ``pseudo_element`` if found. Otherwise, returns ''.

        :raises ValueError: If either property_name or css_class are empty or only contain whitespace values.

        :type css_class: str

        :param css_class: This value may or may not be identical to the property_value.
        :return: None

        """
        deny_empty_or_whitespace(string=css_class, variable_name='css_class')

        self.pseudo_element = ''
        for pseudo_element in pseudo_elements:
            if self.is_valid_pseudo_format(pseudo_element, css_class):
                self.pseudo_element = pseudo_element
    def __init__(self, css_class='', css_property=Property()):
        deny_empty_or_whitespace(css_class, variable_name='css_class')
        deny_empty_or_whitespace(css_property.cssText, variable_name='name')

        self.css_class = css_class
        self.css_property = css_property
        self.units = 'em' if use_em else 'px'

        # Dictionary of Breakpoint Dictionaries {'-only': (), '-down': [1], '-up': [0], }
        # '-only': ('min-width', 'max-width'),      # Lower and Upper Limits of the size.
        # '-down': ('max-width'),                   # Upper limit_key of size.
        # '-up': ('min-width'),                     # Lower Limit of size.
        self.breakpoint_dict = {
            '-xxsmall': {'-only': xxsmall, '-down': xxsmall[1], '-up': xxsmall[0], },
            '-xsmall': {'-only': xsmall, '-down': xsmall[1], '-up': xsmall[0], },
            '-small': {'-only': small, '-down': small[1], '-up': small[0], },
            '-medium': {'-only': medium, '-down': medium[1], '-up': medium[0], },
            '-large': {'-only': large, '-down': large[1], '-up': large[0], },
            '-xlarge': {'-only': xlarge, '-down': xlarge[1], '-up': xlarge[0], },
            '-xxlarge': {'-only': xxlarge, '-down': xxlarge[1], '-up': xxlarge[0], },
            '-giant': {'-only': giant, '-down': giant[1], '-up': giant[0], },
            '-xgiant': {'-only': xgiant, '-down': xgiant[1], '-up': xgiant[0], },
            '-xxgiant': {'-only': xxgiant, '-down': xxgiant[1], '-up': xxgiant[0], },
            'custom': {'-down': None, '-up': None, 'breakpoint': None},
        }

        self.limit_key_set = {'-only', '-down', '-up', }

        self.breakpoint_key = ''
        self.limit_key = ''

        self.is_breakpoint = True       # Naively assume True. set_breakpoint_key and set_limit_key can change to False.
        self.set_breakpoint_key()
        self.set_limit_key()

        if self.limit_key in self.limit_key_set and not self.is_breakpoint:     # Handle custom breakpoints.
            self.set_custom_breakpoint_key()

        self.limit_key_methods = {
            '-only': self.css_for_only,
            '-down': self.css_for_down,
            '-up': self.css_for_up,
        }
    def get_property_value(property_name='', encoded_property_value=''):
        """
        Accepts an encoded_property_value that's been stripped of it's property named and priority
        Uses CSSPropertyValueParser, and returns a valid css property value or ''.

        Usage Note: Invalid CSS values can be returned by this method.  CSS validation occurs at a later step.

        :raises ValueError: If either property_name or css_class are empty or only contain whitespace values.

        :type property_name: str
        :type encoded_property_value: str

        :param property_name: Name of CSS property that matches a key in ``property_alias_dict``.
        :param encoded_property_value: A property value that may or may not contain dashes and underscores.
        :return: (str) -- An unvalidated / potential CSS property value.

        **Examples:**

        >>> property_parser = ClassPropertyParser(set(), False)                 # Turn OFF unit conversion.
        >>> property_parser.get_property_value('font-weight', 'bold')           # Special case: alias == property value
        'bold'
        >>> property_parser.get_property_value('padding', '1-10-10-5')          # Multi-value encoding contains dashes.
        '1px 10px 10px 5px'
        >>> property_parser.get_property_value('width', '7_25rem')              # Single value contains underscores.
        '7.25rem'
        >>> property_parser.get_property_value('margin', '1ap-10xp-3qp-1mp3')   # Invalid CSS returned.
        '1a% 10x% 3q% 1mp3'
        >>> property_parser.get_property_value('', 'c-lime')
        ValueError
        >>> property_parser.get_property_value('color', '  ')
        ValueError

        """
        deny_empty_or_whitespace(string=property_name, variable_name='property_name')
        deny_empty_or_whitespace(string=encoded_property_value, variable_name='encoded_property_value')

        value_parser = CSSPropertyValueParser(property_name=property_name)
        value = value_parser.decode_property_value(value=encoded_property_value)
        return value
    def strip_pseudo_item(self, css_class=''):
        """ Strip property name from css_class if applicable and return the css_class.

        *Note:* This method must be called after ``strip_property_name()``.

        :raises ValueError: If either pseudo_item or css_class are empty or only contain whitespace values.

        :type css_class: str

        :param css_class:  _value.
        :return: (str) -- Returns the encoded property value portion of the css_class.

        **Examples:**

        >>> ClassPropertyParser.strip_pseudo_item('hover-padding-1-2-1-2')
        '1-2-1-2'
        >>> ClassPropertyParser.strip_pseudo_item('before-bold')
        'bold'
        >>> ClassPropertyParser.strip_pseudo_item('after-1-2-1-2')
        ValueError
        >>> ClassPropertyParser.strip_pseudo_item('    ')
        ValueError

        """
        deny_empty_or_whitespace(string=css_class, variable_name='css_class')

        self.set_pseudo_class(css_class=css_class)
        self.set_pseudo_element(css_class=css_class)

        if self.pseudo_class:                                       # Prepend '-' to property to match the class format.
            pseudo_item = '-' + self.pseudo_class
            return css_class.replace(pseudo_item, '')
        elif self.pseudo_element:
            pseudo_item = '-' + self.pseudo_element
            return css_class.replace(pseudo_item, '')
        else:                                                       # No pseudo encoding found.
            return css_class
    def build_media_query(self):
        """ Returns CSS media queries that scales pixel / em values in response to screen size changes.

        **Generated CSS for ``font-size-24-s`` minus the inline comments & line breaks**::

            // Default size above medium
            .font-size-24-s { font-size: 24px; }

            // medium screen font size reduction
            @media only screen and (max-width: 64.0em) {
                .font-size-24-s { font-size: 23.0px; }
            }

            // medium screen font size reduction
            @media only screen and (max-width: 45.0em) {
                .font-size-24-s { font-size: 21.3px; }
            }

            // small screen font size reduction
            @media only screen and (max-width: 30.0em) {
                .font-size-24-s { font-size: 19.2px; }
            }


        **Priority !important -- Generated CSS for ``font-size-24-s-i`` minus the inline comments & line breaks**::

            // Default size above the maximum 'medium' width breakpoint.
            .font-size-24-s-i { font-size: 24px !important; }

            // medium screen font size reduction
            @media only screen and (max-width: 64.0em) {
                .font-size-24-s-i { font-size: 23.0px !important; }
            }

            // Apply 'medium' screen font size reduction.
            @media only screen and (max-width: 45.0em) {
                .font-size-24-s-i { font-size: 21.3px !important; }
            }

            // Apply 'small' screen font size reduction.
            @media only screen and (max-width: 30.0em) {
                .font-size-24-s-i { font-size: 19.2px !important; }
            }

        :return: (*str*) -- Returns CSS media queries that scales pixel / em values in response to screen size changes.

        """
        if not self.is_scaling:
            return ''

        name = self.css_property.name
        value = self.css_property.value
        units = ''.join(filter(lambda x: x.isalpha(), value))                   # Only keep letters.
        priority = self.css_property.priority
        deny_empty_or_whitespace(str(value), variable_name='value')
        float_value = float(value.replace(units, ''))                           # Remove units.

        _max = 1

        large_property = Property(name=name, value=value, priority=priority)
        medium_property = Property(name=name, value=value, priority=priority)
        small_property = Property(name=name, value=value, priority=priority)

        large_value = round(float_value / self.scale_dict['large'], 4)          # Scale to large screen
        large_property.value = str(large_value) + units                         # Add units

        medium_value = round(float_value / self.scale_dict['medium'], 4)        # Scale to medium screen
        medium_property.value = str(medium_value) + units                       # Add units

        small_value = round(float_value / self.scale_dict['small'], 4)          # Scale to small screen
        small_property.value = str(small_value) + units                         # Add units

        return (
            '.' + self.css_class + ' { ' + self.css_property.cssText + '; }\n\n' +
            '@media only screen and (max-width: ' + large[_max] + ') {\n' +
            '\t.' + self.css_class + ' { ' + large_property.cssText + '; }\n' +
            '}\n\n' +
            '@media only screen and (max-width: ' + medium[_max] + ') {\n' +
            '\t.' + self.css_class + ' { ' + medium_property.cssText + '; }\n' +
            '}\n\n' +
            '@media only screen and (max-width: ' + small[_max] + ') {\n' +
            '\t.' + self.css_class + ' { ' + small_property.cssText + '; }\n' +
            '}\n\n'
        )
 def test_deny_empty_or_whitespace_valid(self):
     self.assertEqual(deny_empty_or_whitespace(string='valid_string', variable_name='valid_variable'), None)