Source code for blowdry

# python 2
from __future__ import absolute_import, print_function, unicode_literals
from builtins import bytes, str
# builtins
import logging
import cssutils
from os import path
# custom
from blowdrycss import log
from blowdrycss.filehandler import FileFinder, CSSFile, GenericFile
from blowdrycss.classparser import ClassParser
from blowdrycss.classpropertyparser import ClassPropertyParser
from blowdrycss.cssbuilder import CSSBuilder
from blowdrycss.datalibrary import clashing_alias_markdown, property_alias_markdown, clashing_alias_html, \
    property_alias_html, clashing_alias_rst, property_alias_rst
from blowdrycss.mediaquerybuilder import MediaQueryBuilder
from blowdrycss.utilities import print_minification_stats, validate_output_file_name_setting, validate_output_extension_setting
import blowdrycss_settings as settings

__author__ = 'chad nelson'
__project__ = 'blowdrycss'


[docs]def boilerplate(): """ Watchdog wrapper only calls this once to eliminate recurring performance impact. - Validate the output_file_name and output_extenion settings. - Generate Markdown documentation files. - Generate HTML documentation files. (This location is important since it allows encoded css to be included in the documentation files.) - Generate reStructuredText documentation files. :return: None """ validate_output_file_name_setting() validate_output_extension_setting() if settings.logging_enabled: log.enable() if settings.hide_css_errors: cssutils.log.setLevel(logging.CRITICAL) # Generate Markdown documentation files. if settings.markdown_docs: markdown_file = GenericFile( # Document forbidden clashing aliases. file_directory=settings.markdown_directory, file_name='clashing_aliases', extension='.md' ) markdown_file.write(str(clashing_alias_markdown)) markdown_file = GenericFile( # Document allowed property aliases. file_directory=settings.markdown_directory, file_name='property_aliases', extension='.md' ) markdown_file.write(str(property_alias_markdown)) # Generate HTML documentation files. (This location is important since it allows encoded css to be included # in the documentation files.) if settings.html_docs: html_file = GenericFile( # Document forbidden clashing aliases. file_directory=settings.project_directory, file_name='clashing_aliases', extension='.html' ) html_file.write(str(clashing_alias_html)) html_file = GenericFile( # Document allowed property aliases. file_directory=settings.project_directory, file_name='property_aliases', extension='.html' ) html_file.write(str(property_alias_html)) # Generate reStructuredText documentation files. if settings.rst_docs: print('\nDocumentation Directory:', str(settings.docs_directory)) # str() is required for Python2 rst_file = GenericFile(file_directory=settings.docs_directory, file_name='clashing_aliases', extension='.rst') rst_file.write(str(clashing_alias_rst)) rst_file = GenericFile(file_directory=settings.docs_directory, file_name='property_aliases', extension='.rst') rst_file.write(str(property_alias_rst))
[docs]def parse(recent=True, class_set=set(), css_text=b''): """ It parses every eligible file in the project i.e. file type matches an element of settings.file_types. This ensures that from time to time unused CSS class selectors are removed from blowdry.css. **Order of Operations:** - Initialize settings. - Start performance timer. - Define File all file types/extensions to search for in project_directory - Get all files associated with defined file_types in project_directory - Get set of all defined classes - Filter class names only keeping classes that match the defined class encoding. - Build a set() of valid css properties. Some classes may be removed during cssutils validation. - Output the DRY CSS file. (user command option) - Output the Minified DRY CSS file. (user command option) **Depending on the settings this script generates the following:** - DRY CSS files - blowdry.css |sp| |sp| |sp| |sp| |sp| **human readable** - blowdry.min.css |sp| **minified** - Clashing Alias files (Encoded class selector aliases that are invalid and cannot be used because they clash.) - Markdown |sp| |sp| |sp| |sp| |sp| |sp| **Github** - HTML |sp| |sp| |sp| |sp| |sp| |sp| |sp| |sp| |sp| **Browser** - reStructuredText |sp| **Sphinx** - Property Alias File (Encoded class selector aliases that are valid and can be used to construct class selectors.) - Markdown |sp| |sp| |sp| |sp| |sp| |sp| **Github** - HTML |sp| |sp| |sp| |sp| |sp| |sp| |sp| |sp| |sp| **Browser** - reStructuredText |sp| **Sphinx** - Temporal Statistics **Note:** The default locations of these files can be overridden to suit your needs. **Directory assignments** ``project_directory`` -- Allows ``blowdrycss`` to know where the HTML project is located. It will only search the files in the directory specified here. .. |sp| raw:: html   :param css_text: :type recent: bool :param recent: Flag that indicates whether to parse the most recently modified files (True Case) or all eligible files (False Case). :type class_set: set :param class_set: The set of known css class selectors. :type css_text: bytes :param css_text: The current version of the CSS text. """ if settings.timing_enabled: from blowdrycss.timing import Timer timer = Timer() print('\n~~~ blowdrycss started ~~~') # Get files to parse. file_finder = FileFinder(recent=recent) # Create set of all defined classes class_parser = ClassParser(file_dict=file_finder.file_dict) # Unite class sets during on_modified case. if recent: modified_class_set = class_parser.class_set use_this_set = modified_class_set.difference(class_set) else: use_this_set = class_parser.class_set # Filter class names. Only keep classes matching the defined class encoding. class_property_parser = ClassPropertyParser(class_set=use_this_set) logging.info(msg='blowdry.class_property_parser.class_set:\t' + str(class_property_parser.class_set)) use_this_set = class_property_parser.class_set.copy() # Build a set() of valid css properties. Some classes may be removed during cssutils validation. css_builder = CSSBuilder(property_parser=class_property_parser) css_text += bytes(css_builder.get_css_text()) builder_class_set = css_builder.property_parser.class_set.copy() # Build Media Queries if settings.media_queries_enabled: unassigned_class_set = use_this_set.difference(css_builder.property_parser.class_set) css_builder.property_parser.class_set = unassigned_class_set.copy() # Only use unassigned classes css_builder.property_parser.removed_class_set = set() # Clear set media_query_builder = MediaQueryBuilder(property_parser=class_property_parser) logging.debug( msg=( 'blowdry.media_query_builder.property_parser.class_set:\t' + str(media_query_builder.property_parser.class_set) ) ) css_text += bytes(media_query_builder.get_css_text(), 'utf-8') media_class_set = unassigned_class_set.intersection(media_query_builder.property_parser.class_set) if recent: class_set = class_set.union(builder_class_set) class_set = class_set.union(media_class_set) else: class_set = builder_class_set.copy() class_set = class_set.union(media_class_set) else: if recent: class_set = class_set.union(builder_class_set) else: class_set = builder_class_set.copy() logging.debug('\nCSS Text:\n\n' + str(css_text)) print('\nAuto-Generated CSS:') # Output the DRY CSS file. (user setting option) if settings.human_readable: css_file = CSSFile() css_file.write(css_text=css_text) print(path.join(css_file.file_directory, css_file.file_name) + css_file.extension) # Output the Minified DRY CSS file. (user setting option) if settings.minify: css_file = CSSFile() css_file.minify(css_text=css_text) print(path.join(css_file.file_directory, css_file.file_name) + '.min' + css_file.extension) if settings.timing_enabled: timer.report() if settings.minify: print_minification_stats(file_name=settings.output_file_name, extension=settings.output_extension) return class_set, css_text