def test_print_css_stats(self): # On Travis CI these auto-generated files are inaccessible and need to be recreated. # Change the expected file size reduction percentage since Ubuntu's math is different. # Create directories and CSS files if they do not exist. blowdry_css = unittest_file_path('test_examplesite/test_css', 'blowdry.css') blowdry_min_css = unittest_file_path('test_examplesite/test_css', 'blowdry.min.css') #if not path.isfile(blowdry_css) or not path.isfile(blowdry_min_css): substrings = [ 'blowdry.css:\t 0.3kB', 'blowdry.min.css: 0.2kB', 'CSS file size reduced by 28.4%.' ] blowdry_css_text = '.bgc-hf8f8f8 {\n background-color: #f8f8f8\n }\n.border-1px-solid-gray {\n border: 1px solid gray\n }\n.padding-5 {\n padding: 0.3125em\n }\n.bold {\n font-weight: bold\n }\n.talign-center {\n text-align: center\n }\n.display-inline {\n display: inline\n }' blowdry_min_css_text = '.bgc-hf8f8f8{background-color:#f8f8f8}.border-1px-solid-gray{border:1px solid gray}.padding-5{padding:.3125em}.bold{font-weight:bold}.talign-center{text-align:center}.display-inline{display:inline}' # Create directories. make_directory(unittest_file_path('test_examplesite', '')) make_directory(unittest_file_path('test_examplesite/test_css', '')) # Create files. with open(blowdry_css, 'wb') as generic_file: generic_file.write(bytearray(blowdry_css_text, 'utf-8')) with open(blowdry_min_css, 'wb') as generic_file: generic_file.write(bytearray(blowdry_min_css_text, 'utf-8')) # Handle printed output. saved_stdout = sys.stdout try: out = StringIO() sys.stdout = out print_css_stats(file_name='blowdry') output = out.getvalue() for substring in substrings: self.assertTrue(substring in output, msg=substring + '\noutput:\n' + output) finally: sys.stdout = saved_stdout
def test_print_css_stats_ZeroDivisionError(self): # On Travis CI these auto-generated files are inaccessible and need to be recreated. # Change the expected file size reduction percentage since Ubuntu's math is different. # Create directories and CSS files if they do not exist. empty_css = unittest_file_path('test_examplesite/test_css', 'empty.css') empty_min_css = unittest_file_path('test_examplesite/test_css', 'empty.min.css') #if not path.isfile(blowdry_css) or not path.isfile(blowdry_min_css): substrings = [ 'empty.css:\t 0.0kB', 'empty.min.css: 0.0kB', 'CSS file size reduced by 0.0%.' ] # Create directories. make_directory(unittest_file_path('test_examplesite', '')) make_directory(unittest_file_path('test_examplesite/test_css', '')) # Create files. with open(empty_css, 'w') as generic_file: generic_file.write(u'') with open(empty_min_css, 'w') as generic_file: generic_file.write(u'') # Handle printed output. saved_stdout = sys.stdout try: out = StringIO() sys.stdout = out print_css_stats(file_name='empty') output = out.getvalue() for substring in substrings: self.assertTrue(substring in output, msg=substring + '\noutput:\n' + output) finally: sys.stdout = saved_stdout delete_file_paths((empty_css, empty_min_css, ))
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(file_directory=settings.css_directory, file_name='blowdry') css_file.write(css_text=css_text) print(path.join(settings.css_directory, css_file.file_name) + '.css') # Output the Minified DRY CSS file. (user setting option) if settings.minify: css_file = CSSFile(file_directory=settings.css_directory, file_name='blowdry') css_file.minify(css_text=css_text) print(path.join(settings.css_directory, css_file.file_name) + '.min.css') if settings.timing_enabled: timer.report() if settings.minify: print_css_stats(file_name='blowdry') return class_set, css_text