diff --git a/docs/conf.py b/docs/conf.py index 6cce570a..6612bef2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -25,20 +25,20 @@ extensions = [] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = 'django-pipeline' -copyright = '2011-2014, Timothée Peignier' +project = "django-pipeline" +copyright = "2011-2014, Timothée Peignier" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -61,7 +61,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build'] +exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all documents. # default_role = None @@ -78,7 +78,7 @@ # show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] @@ -88,7 +88,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +html_theme = "default" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -161,7 +161,7 @@ # html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'django-pipelinedoc' +htmlhelp_basename = "django-pipelinedoc" # -- Options for LaTeX output -------------------------------------------------- @@ -175,8 +175,13 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('index', 'django-pipeline.tex', 'Pipeline Documentation', - 'Timothée Peignier', 'manual'), + ( + "index", + "django-pipeline.tex", + "Pipeline Documentation", + "Timothée Peignier", + "manual", + ), ] # The name of an image file (relative to this directory) to place at the top of @@ -208,6 +213,5 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'django-pipeline', 'Pipeline Documentation', - ['Timothée Peignier'], 1) + ("index", "django-pipeline", "Pipeline Documentation", ["Timothée Peignier"], 1) ] diff --git a/pipeline/collector.py b/pipeline/collector.py index 70b7fed2..a98a545a 100644 --- a/pipeline/collector.py +++ b/pipeline/collector.py @@ -37,15 +37,16 @@ def collect(self, request=None, files=[]): # Ignore our finder to avoid looping if isinstance(finder, PipelineFinder): continue - for path, storage in finder.list(['CVS', '.*', '*~']): + for path, storage in finder.list(["CVS", ".*", "*~"]): # Prefix the relative path if the source storage contains it - if getattr(storage, 'prefix', None): + if getattr(storage, "prefix", None): prefixed_path = os.path.join(storage.prefix, path) else: prefixed_path = path - if (prefixed_path not in found_files and - (not files or prefixed_path in files)): + if prefixed_path not in found_files and ( + not files or prefixed_path in files + ): found_files[prefixed_path] = (storage, path) self.copy_file(path, prefixed_path, storage) @@ -82,8 +83,9 @@ def delete_file(self, path, prefixed_path, source_storage): else: # Skip the file if the source file is younger # Avoid sub-second precision - if (target_last_modified.replace(microsecond=0) - >= source_last_modified.replace(microsecond=0)): + if target_last_modified.replace( + microsecond=0 + ) >= source_last_modified.replace(microsecond=0): return False # Then delete the existing file if really needed self.storage.delete(prefixed_path) diff --git a/pipeline/compilers/__init__.py b/pipeline/compilers/__init__.py index 473022e3..cba0c4af 100644 --- a/pipeline/compilers/__init__.py +++ b/pipeline/compilers/__init__.py @@ -36,9 +36,13 @@ def _compile(input_path): project_infile = finders.find(input_path) outfile = compiler.output_path(infile, compiler.output_extension) outdated = compiler.is_outdated(project_infile, outfile) - compiler.compile_file(project_infile, outfile, - outdated=outdated, force=force, - **compiler_options) + compiler.compile_file( + project_infile, + outfile, + outdated=outdated, + force=force, + **compiler_options, + ) return compiler.output_path(input_path, compiler.output_extension) else: @@ -71,14 +75,14 @@ def save_file(self, path, content): return self.storage.save(path, ContentFile(content)) def read_file(self, path): - file = self.storage.open(path, 'rb') + file = self.storage.open(path, "rb") content = file.read() file.close() return content def output_path(self, path, extension): path = os.path.splitext(path) - return '.'.join((path[0], extension)) + return ".".join((path[0], extension)) def is_outdated(self, infile, outfile): if not os.path.exists(outfile): @@ -125,12 +129,11 @@ def execute_command(self, command, cwd=None, stdout_captured=None): cwd or os.path.dirname(stdout_captured or "") or os.getcwd() ) with NamedTemporaryFile( - 'wb', delete=False, dir=temp_file_container + "wb", delete=False, dir=temp_file_container ) as stdout: - compiling = subprocess.Popen(argument_list, - cwd=cwd, - stdout=stdout, - stderr=subprocess.PIPE) + compiling = subprocess.Popen( + argument_list, cwd=cwd, stdout=stdout, stderr=subprocess.PIPE + ) _, stderr = compiling.communicate() set_std_streams_blocking() @@ -139,17 +142,17 @@ def execute_command(self, command, cwd=None, stdout_captured=None): raise CompilerError( f"{argument_list!r} exit code {compiling.returncode}\n{stderr}", command=argument_list, - error_output=force_str(stderr)) + error_output=force_str(stderr), + ) # User wants to see everything that happened. if self.verbose: - with open(stdout.name, 'rb') as out: + with open(stdout.name, "rb") as out: print(out.read()) print(stderr) except OSError as e: stdout_captured = None # Don't save erroneous result. - raise CompilerError(e, command=argument_list, - error_output=str(e)) + raise CompilerError(e, command=argument_list, error_output=str(e)) finally: # Decide what to do with captured stdout. if stdout: diff --git a/pipeline/compilers/coffee.py b/pipeline/compilers/coffee.py index f8a8af24..04eeee83 100644 --- a/pipeline/compilers/coffee.py +++ b/pipeline/compilers/coffee.py @@ -3,10 +3,10 @@ class CoffeeScriptCompiler(SubProcessCompiler): - output_extension = 'js' + output_extension = "js" def match_file(self, path): - return path.endswith('.coffee') or path.endswith('.litcoffee') + return path.endswith(".coffee") or path.endswith(".litcoffee") def compile_file(self, infile, outfile, outdated=False, force=False): if not outdated and not force: diff --git a/pipeline/compilers/es6.py b/pipeline/compilers/es6.py index 068a938f..d35fcc76 100644 --- a/pipeline/compilers/es6.py +++ b/pipeline/compilers/es6.py @@ -3,10 +3,10 @@ class ES6Compiler(SubProcessCompiler): - output_extension = 'js' + output_extension = "js" def match_file(self, path): - return path.endswith('.es6') + return path.endswith(".es6") def compile_file(self, infile, outfile, outdated=False, force=False): if not outdated and not force: @@ -16,6 +16,6 @@ def compile_file(self, infile, outfile, outdated=False, force=False): settings.BABEL_ARGUMENTS, infile, "-o", - outfile + outfile, ) return self.execute_command(command) diff --git a/pipeline/compilers/less.py b/pipeline/compilers/less.py index 34a5d3e1..722cee04 100644 --- a/pipeline/compilers/less.py +++ b/pipeline/compilers/less.py @@ -5,10 +5,10 @@ class LessCompiler(SubProcessCompiler): - output_extension = 'css' + output_extension = "css" def match_file(self, filename): - return filename.endswith('.less') + return filename.endswith(".less") def compile_file(self, infile, outfile, outdated=False, force=False): # Pipe to file rather than provide outfile arg due to a bug in lessc diff --git a/pipeline/compilers/livescript.py b/pipeline/compilers/livescript.py index 3390e498..4cded97c 100644 --- a/pipeline/compilers/livescript.py +++ b/pipeline/compilers/livescript.py @@ -3,10 +3,10 @@ class LiveScriptCompiler(SubProcessCompiler): - output_extension = 'js' + output_extension = "js" def match_file(self, path): - return path.endswith('.ls') + return path.endswith(".ls") def compile_file(self, infile, outfile, outdated=False, force=False): if not outdated and not force: diff --git a/pipeline/compilers/sass.py b/pipeline/compilers/sass.py index 43d184bb..f37adb36 100644 --- a/pipeline/compilers/sass.py +++ b/pipeline/compilers/sass.py @@ -5,16 +5,11 @@ class SASSCompiler(SubProcessCompiler): - output_extension = 'css' + output_extension = "css" def match_file(self, filename): - return filename.endswith(('.scss', '.sass')) + return filename.endswith((".scss", ".sass")) def compile_file(self, infile, outfile, outdated=False, force=False): - command = ( - settings.SASS_BINARY, - settings.SASS_ARGUMENTS, - infile, - outfile - ) + command = (settings.SASS_BINARY, settings.SASS_ARGUMENTS, infile, outfile) return self.execute_command(command, cwd=dirname(infile)) diff --git a/pipeline/compilers/stylus.py b/pipeline/compilers/stylus.py index 041158bd..92c87102 100644 --- a/pipeline/compilers/stylus.py +++ b/pipeline/compilers/stylus.py @@ -5,15 +5,11 @@ class StylusCompiler(SubProcessCompiler): - output_extension = 'css' + output_extension = "css" def match_file(self, filename): - return filename.endswith('.styl') + return filename.endswith(".styl") def compile_file(self, infile, outfile, outdated=False, force=False): - command = ( - settings.STYLUS_BINARY, - settings.STYLUS_ARGUMENTS, - infile - ) + command = (settings.STYLUS_BINARY, settings.STYLUS_ARGUMENTS, infile) return self.execute_command(command, cwd=dirname(infile)) diff --git a/pipeline/compilers/typescript.py b/pipeline/compilers/typescript.py index 7a13e12d..882d7b36 100644 --- a/pipeline/compilers/typescript.py +++ b/pipeline/compilers/typescript.py @@ -3,10 +3,10 @@ class TypeScriptCompiler(SubProcessCompiler): - output_extension = 'js' + output_extension = "js" def match_file(self, path): - return path.endswith('.ts') + return path.endswith(".ts") def compile_file(self, infile, outfile, outdated=False, force=False): if not outdated and not force: @@ -15,7 +15,7 @@ def compile_file(self, infile, outfile, outdated=False, force=False): settings.TYPE_SCRIPT_BINARY, settings.TYPE_SCRIPT_ARGUMENTS, infile, - '--outFile', + "--outFile", outfile, ) return self.execute_command(command) diff --git a/pipeline/compressors/__init__.py b/pipeline/compressors/__init__.py index dcf9fa60..fb1cd738 100644 --- a/pipeline/compressors/__init__.py +++ b/pipeline/compressors/__init__.py @@ -14,24 +14,24 @@ URL_DETECTOR = r"""url\((['"]?)\s*(.*?)\1\)""" URL_REPLACER = r"""url\(__EMBED__(.+?)(\?\d+)?\)""" -NON_REWRITABLE_URL = re.compile(r'^(#|http:|https:|data:|//)') +NON_REWRITABLE_URL = re.compile(r"^(#|http:|https:|data:|//)") DEFAULT_TEMPLATE_FUNC = "template" -TEMPLATE_FUNC = r"""var template = function(str){var fn = new Function('obj', 'var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push(\''+str.replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/<%=([\s\S]+?)%>/g,function(match,code){return "',"+code.replace(/\\'/g, "'")+",'";}).replace(/<%([\s\S]+?)%>/g,function(match,code){return "');"+code.replace(/\\'/g, "'").replace(/[\r\n\t]/g,' ')+"__p.push('";}).replace(/\r/g,'\\r').replace(/\n/g,'\\n').replace(/\t/g,'\\t')+"');}return __p.join('');");return fn;};""" # noqa +TEMPLATE_FUNC = r"""var template = function(str){var fn = new Function('obj', 'var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push(\''+str.replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/<%=([\s\S]+?)%>/g,function(match,code){return "',"+code.replace(/\\'/g, "'")+",'";}).replace(/<%([\s\S]+?)%>/g,function(match,code){return "');"+code.replace(/\\'/g, "'").replace(/[\r\n\t]/g,' ')+"__p.push('";}).replace(/\r/g,'\\r').replace(/\n/g,'\\n').replace(/\t/g,'\\t')+"');}return __p.join('');");return fn;};""" # noqa MIME_TYPES = { - '.png': 'image/png', - '.jpg': 'image/jpeg', - '.jpeg': 'image/jpeg', - '.gif': 'image/gif', - '.tif': 'image/tiff', - '.tiff': 'image/tiff', - '.ttf': 'font/truetype', - '.otf': 'font/opentype', - '.woff': 'font/woff' + ".png": "image/png", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".gif": "image/gif", + ".tif": "image/tiff", + ".tiff": "image/tiff", + ".ttf": "font/truetype", + ".otf": "font/opentype", + ".woff": "font/woff", } EMBED_EXTS = MIME_TYPES.keys() -FONT_EXTS = ['.ttf', '.otf', '.woff'] +FONT_EXTS = [".ttf", ".otf", ".woff"] class Compressor: @@ -62,7 +62,7 @@ def compress_js(self, paths, templates=None, **kwargs): compressor = self.js_compressor if compressor: - js = getattr(compressor(verbose=self.verbose), 'compress_js')(js) + js = getattr(compressor(verbose=self.verbose), "compress_js")(js) return js @@ -71,18 +71,18 @@ def compress_css(self, paths, output_filename, variant=None, **kwargs): css = self.concatenate_and_rewrite(paths, output_filename, variant) compressor = self.css_compressor if compressor: - css = getattr(compressor(verbose=self.verbose), 'compress_css')(css) + css = getattr(compressor(verbose=self.verbose), "compress_css")(css) if not variant: return css elif variant == "datauri": return self.with_data_uri(css) else: - raise CompressorError(f"\"{variant}\" is not a valid variant") + raise CompressorError(f'"{variant}" is not a valid variant') def compile_templates(self, paths): compiled = [] if not paths: - return '' + return "" namespace = settings.TEMPLATE_NAMESPACE base_path = self.base_path(paths) for path in paths: @@ -90,25 +90,27 @@ def compile_templates(self, paths): contents = re.sub("\r?\n", "\\\\n", contents) contents = re.sub("'", "\\'", contents) name = self.template_name(path, base_path) - compiled.append("{}['{}'] = {}('{}');\n".format( - namespace, - name, - settings.TEMPLATE_FUNC, - contents - )) + compiled.append( + "{}['{}'] = {}('{}');\n".format( + namespace, name, settings.TEMPLATE_FUNC, contents + ) + ) if settings.TEMPLATE_FUNC == DEFAULT_TEMPLATE_FUNC: compiler = TEMPLATE_FUNC else: compiler = "" - return "\n".join([ - "{namespace} = {namespace} || {{}};".format(namespace=namespace), - compiler, - ''.join(compiled) - ]) + return "\n".join( + [ + "{namespace} = {namespace} || {{}};".format(namespace=namespace), + compiler, + "".join(compiled), + ] + ) def base_path(self, paths): def names_equal(name): return all(n == name[0] for n in name[1:]) + directory_levels = zip(*[p.split(os.sep) for p in paths]) return os.sep.join(x[0] for x in takewhile(names_equal, directory_levels)) @@ -118,28 +120,35 @@ def template_name(self, path, base): path = os.path.basename(path) if path == base: base = os.path.dirname(path) - name = re.sub(r"^{}[\/\\]?(.*){}$".format( - re.escape(base), re.escape(settings.TEMPLATE_EXT) - ), r"\1", path) + name = re.sub( + r"^{}[\/\\]?(.*){}$".format( + re.escape(base), re.escape(settings.TEMPLATE_EXT) + ), + r"\1", + path, + ) return re.sub(r"[\/\\]", settings.TEMPLATE_SEPARATOR, name) def concatenate_and_rewrite(self, paths, output_filename, variant=None): """Concatenate together files and rewrite urls""" stylesheets = [] for path in paths: + def reconstruct(match): - quote = match.group(1) or '' + quote = match.group(1) or "" asset_path = match.group(2) if NON_REWRITABLE_URL.match(asset_path): return f"url({quote}{asset_path}{quote})" - asset_url = self.construct_asset_path(asset_path, path, - output_filename, variant) + asset_url = self.construct_asset_path( + asset_path, path, output_filename, variant + ) return f"url({asset_url})" + content = self.read_text(path) # content needs to be unicode to avoid explosions with non-ascii chars content = re.sub(URL_DETECTOR, reconstruct, content) stylesheets.append(content) - return '\n'.join(stylesheets) + return "\n".join(stylesheets) def concatenate(self, paths): """Concatenate together a list of files""" @@ -153,7 +162,7 @@ def construct_asset_path(self, asset_path, css_path, output_filename, variant=No """Return a rewritten asset URL for a stylesheet""" public_path = self.absolute_path( asset_path, - os.path.dirname(css_path).replace('\\', '/'), + os.path.dirname(css_path).replace("\\", "/"), ) if self.embeddable(public_path, variant): return "__EMBED__%s" % public_path @@ -167,13 +176,16 @@ def embeddable(self, path, variant): font = ext in FONT_EXTS if not variant: return False - if not (re.search(settings.EMBED_PATH, path.replace('\\', '/')) - and self.storage.exists(path)): + if not ( + re.search(settings.EMBED_PATH, path.replace("\\", "/")) + and self.storage.exists(path) + ): return False if ext not in EMBED_EXTS: return False - if not (font or - len(self.encoded_content(path)) < settings.EMBED_MAX_IMAGE_SIZE): + if not ( + font or len(self.encoded_content(path)) < settings.EMBED_MAX_IMAGE_SIZE + ): return False return True @@ -182,7 +194,8 @@ def datauri(match): path = match.group(1) mime_type = self.mime_type(path) data = self.encoded_content(path) - return f"url(\"data:{mime_type};charset=utf-8;base64,{data}\")" + return f'url("data:{mime_type};charset=utf-8;base64,{data}")' + return re.sub(URL_REPLACER, datauri, css) def encoded_content(self, path): @@ -213,7 +226,8 @@ def relative_path(self, absolute_path, output_filename): """Rewrite paths relative to the output stylesheet path""" absolute_path = posixpath.join(settings.PIPELINE_ROOT, absolute_path) output_path = posixpath.join( - settings.PIPELINE_ROOT, posixpath.dirname(output_filename)) + settings.PIPELINE_ROOT, posixpath.dirname(output_filename) + ) return relpath(absolute_path, output_path) def read_bytes(self, path): @@ -248,10 +262,12 @@ def execute_command(self, command, content): else: argument_list.extend(flattening_arg) - pipe = subprocess.Popen(argument_list, - stdout=subprocess.PIPE, - stdin=subprocess.PIPE, - stderr=subprocess.PIPE) + pipe = subprocess.Popen( + argument_list, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE, + stderr=subprocess.PIPE, + ) if content: content = smart_bytes(content) stdout, stderr = pipe.communicate(content) diff --git a/pipeline/compressors/csshtmljsminify.py b/pipeline/compressors/csshtmljsminify.py index b2afd84c..7e306a83 100644 --- a/pipeline/compressors/csshtmljsminify.py +++ b/pipeline/compressors/csshtmljsminify.py @@ -6,10 +6,13 @@ class CssHtmlJsMinifyCompressor(CompressorBase): CSS, HTML and JS compressor based on the Python library css-html-js-minify (https://pypi.org/project/css-html-js-minify/). """ + def compress_css(self, css): from css_html_js_minify import css_minify + return css_minify(css) def compress_js(self, js): from css_html_js_minify import js_minify + return js_minify(js) diff --git a/pipeline/compressors/csstidy.py b/pipeline/compressors/csstidy.py index 30915b4f..82d77ff4 100644 --- a/pipeline/compressors/csstidy.py +++ b/pipeline/compressors/csstidy.py @@ -6,13 +6,13 @@ class CSSTidyCompressor(SubProcessCompressor): def compress_css(self, css): - output_file = tempfile.NamedTemporaryFile(suffix='.pipeline') + output_file = tempfile.NamedTemporaryFile(suffix=".pipeline") command = ( settings.CSSTIDY_BINARY, "-", settings.CSSTIDY_ARGUMENTS, - output_file.name + output_file.name, ) self.execute_command(command, css) diff --git a/pipeline/compressors/jsmin.py b/pipeline/compressors/jsmin.py index c26d5479..e520d333 100644 --- a/pipeline/compressors/jsmin.py +++ b/pipeline/compressors/jsmin.py @@ -6,6 +6,8 @@ class JSMinCompressor(CompressorBase): JS compressor based on the Python library jsmin (http://pypi.python.org/pypi/jsmin/). """ + def compress_js(self, js): from jsmin import jsmin + return jsmin(js) diff --git a/pipeline/compressors/terser.py b/pipeline/compressors/terser.py index 61a66df5..33debfa8 100644 --- a/pipeline/compressors/terser.py +++ b/pipeline/compressors/terser.py @@ -6,5 +6,5 @@ class TerserCompressor(SubProcessCompressor): def compress_js(self, js): command = (settings.TERSER_BINARY, settings.TERSER_ARGUMENTS) if self.verbose: - command += ' --verbose' + command += " --verbose" return self.execute_command(command, js) diff --git a/pipeline/compressors/uglifyjs.py b/pipeline/compressors/uglifyjs.py index 28557185..79253197 100644 --- a/pipeline/compressors/uglifyjs.py +++ b/pipeline/compressors/uglifyjs.py @@ -6,5 +6,5 @@ class UglifyJSCompressor(SubProcessCompressor): def compress_js(self, js): command = (settings.UGLIFYJS_BINARY, settings.UGLIFYJS_ARGUMENTS) if self.verbose: - command += ' --verbose' + command += " --verbose" return self.execute_command(command, js) diff --git a/pipeline/compressors/yuglify.py b/pipeline/compressors/yuglify.py index 22ec3422..b8894857 100644 --- a/pipeline/compressors/yuglify.py +++ b/pipeline/compressors/yuglify.py @@ -4,15 +4,11 @@ class YuglifyCompressor(SubProcessCompressor): def compress_common(self, content, compress_type, arguments): - command = ( - settings.YUGLIFY_BINARY, - f"--type={compress_type}", - arguments - ) + command = (settings.YUGLIFY_BINARY, f"--type={compress_type}", arguments) return self.execute_command(command, content) def compress_js(self, js): - return self.compress_common(js, 'js', settings.YUGLIFY_JS_ARGUMENTS) + return self.compress_common(js, "js", settings.YUGLIFY_JS_ARGUMENTS) def compress_css(self, css): - return self.compress_common(css, 'css', settings.YUGLIFY_CSS_ARGUMENTS) + return self.compress_common(css, "css", settings.YUGLIFY_CSS_ARGUMENTS) diff --git a/pipeline/compressors/yui.py b/pipeline/compressors/yui.py index 140e40e2..b2d7179e 100644 --- a/pipeline/compressors/yui.py +++ b/pipeline/compressors/yui.py @@ -4,15 +4,11 @@ class YUICompressor(SubProcessCompressor): def compress_common(self, content, compress_type, arguments): - command = ( - settings.YUI_BINARY, - f"--type={compress_type}", - arguments - ) + command = (settings.YUI_BINARY, f"--type={compress_type}", arguments) return self.execute_command(command, content) def compress_js(self, js): - return self.compress_common(js, 'js', settings.YUI_JS_ARGUMENTS) + return self.compress_common(js, "js", settings.YUI_JS_ARGUMENTS) def compress_css(self, css): - return self.compress_common(css, 'css', settings.YUI_CSS_ARGUMENTS) + return self.compress_common(css, "css", settings.YUI_CSS_ARGUMENTS) diff --git a/pipeline/conf.py b/pipeline/conf.py index a701a558..a36643e5 100644 --- a/pipeline/conf.py +++ b/pipeline/conf.py @@ -7,85 +7,62 @@ from django.dispatch import receiver DEFAULTS = { - 'PIPELINE_ENABLED': not _settings.DEBUG, - - 'PIPELINE_COLLECTOR_ENABLED': True, - - 'PIPELINE_ROOT': _settings.STATIC_ROOT, - 'PIPELINE_URL': _settings.STATIC_URL, - - 'SHOW_ERRORS_INLINE': _settings.DEBUG, - - 'CSS_COMPRESSOR': 'pipeline.compressors.yuglify.YuglifyCompressor', - 'JS_COMPRESSOR': 'pipeline.compressors.yuglify.YuglifyCompressor', - 'COMPILERS': [], - - 'STYLESHEETS': {}, - 'JAVASCRIPT': {}, - - 'TEMPLATE_NAMESPACE': "window.JST", - 'TEMPLATE_EXT': ".jst", - 'TEMPLATE_FUNC': "template", - 'TEMPLATE_SEPARATOR': "_", - - 'DISABLE_WRAPPER': False, - 'JS_WRAPPER': "(function() {\n%s\n}).call(this);", - - 'CSSTIDY_BINARY': '/usr/bin/env csstidy', - 'CSSTIDY_ARGUMENTS': '--template=highest', - - 'YUGLIFY_BINARY': '/usr/bin/env yuglify', - 'YUGLIFY_CSS_ARGUMENTS': '--terminal', - 'YUGLIFY_JS_ARGUMENTS': '--terminal', - - 'YUI_BINARY': '/usr/bin/env yuicompressor', - 'YUI_CSS_ARGUMENTS': '', - 'YUI_JS_ARGUMENTS': '', - - 'CLOSURE_BINARY': '/usr/bin/env closure', - 'CLOSURE_ARGUMENTS': '', - - 'UGLIFYJS_BINARY': '/usr/bin/env uglifyjs', - 'UGLIFYJS_ARGUMENTS': '', - - 'TERSER_BINARY': '/usr/bin/env terser', - 'TERSER_ARGUMENTS': '--compress', - - 'CSSMIN_BINARY': '/usr/bin/env cssmin', - 'CSSMIN_ARGUMENTS': '', - - 'COFFEE_SCRIPT_BINARY': '/usr/bin/env coffee', - 'COFFEE_SCRIPT_ARGUMENTS': '', - - 'BABEL_BINARY': '/usr/bin/env babel', - 'BABEL_ARGUMENTS': '', - - 'LIVE_SCRIPT_BINARY': '/usr/bin/env lsc', - 'LIVE_SCRIPT_ARGUMENTS': '', - - 'TYPE_SCRIPT_BINARY': '/usr/bin/env tsc', - 'TYPE_SCRIPT_ARGUMENTS': '', - - 'SASS_BINARY': '/usr/bin/env sass', - 'SASS_ARGUMENTS': '', - - 'STYLUS_BINARY': '/usr/bin/env stylus', - 'STYLUS_ARGUMENTS': '', - - 'LESS_BINARY': '/usr/bin/env lessc', - 'LESS_ARGUMENTS': '', - - 'MIMETYPES': ( - (('text/coffeescript'), ('.coffee')), - (('text/less'), ('.less')), - (('text/javascript'), ('.js')), - (('text/typescript'), ('.ts')), - (('text/x-sass'), ('.sass')), - (('text/x-scss'), ('.scss')) + "PIPELINE_ENABLED": not _settings.DEBUG, + "PIPELINE_COLLECTOR_ENABLED": True, + "PIPELINE_ROOT": _settings.STATIC_ROOT, + "PIPELINE_URL": _settings.STATIC_URL, + "SHOW_ERRORS_INLINE": _settings.DEBUG, + "CSS_COMPRESSOR": "pipeline.compressors.yuglify.YuglifyCompressor", + "JS_COMPRESSOR": "pipeline.compressors.yuglify.YuglifyCompressor", + "COMPILERS": [], + "STYLESHEETS": {}, + "JAVASCRIPT": {}, + "TEMPLATE_NAMESPACE": "window.JST", + "TEMPLATE_EXT": ".jst", + "TEMPLATE_FUNC": "template", + "TEMPLATE_SEPARATOR": "_", + "DISABLE_WRAPPER": False, + "JS_WRAPPER": "(function() {\n%s\n}).call(this);", + "CSSTIDY_BINARY": "/usr/bin/env csstidy", + "CSSTIDY_ARGUMENTS": "--template=highest", + "YUGLIFY_BINARY": "/usr/bin/env yuglify", + "YUGLIFY_CSS_ARGUMENTS": "--terminal", + "YUGLIFY_JS_ARGUMENTS": "--terminal", + "YUI_BINARY": "/usr/bin/env yuicompressor", + "YUI_CSS_ARGUMENTS": "", + "YUI_JS_ARGUMENTS": "", + "CLOSURE_BINARY": "/usr/bin/env closure", + "CLOSURE_ARGUMENTS": "", + "UGLIFYJS_BINARY": "/usr/bin/env uglifyjs", + "UGLIFYJS_ARGUMENTS": "", + "TERSER_BINARY": "/usr/bin/env terser", + "TERSER_ARGUMENTS": "--compress", + "CSSMIN_BINARY": "/usr/bin/env cssmin", + "CSSMIN_ARGUMENTS": "", + "COFFEE_SCRIPT_BINARY": "/usr/bin/env coffee", + "COFFEE_SCRIPT_ARGUMENTS": "", + "BABEL_BINARY": "/usr/bin/env babel", + "BABEL_ARGUMENTS": "", + "LIVE_SCRIPT_BINARY": "/usr/bin/env lsc", + "LIVE_SCRIPT_ARGUMENTS": "", + "TYPE_SCRIPT_BINARY": "/usr/bin/env tsc", + "TYPE_SCRIPT_ARGUMENTS": "", + "SASS_BINARY": "/usr/bin/env sass", + "SASS_ARGUMENTS": "", + "STYLUS_BINARY": "/usr/bin/env stylus", + "STYLUS_ARGUMENTS": "", + "LESS_BINARY": "/usr/bin/env lessc", + "LESS_ARGUMENTS": "", + "MIMETYPES": ( + (("text/coffeescript"), (".coffee")), + (("text/less"), (".less")), + (("text/javascript"), (".js")), + (("text/typescript"), (".ts")), + (("text/x-sass"), (".sass")), + (("text/x-scss"), (".scss")), ), - - 'EMBED_MAX_IMAGE_SIZE': 32700, - 'EMBED_PATH': r'[/]?embed/', + "EMBED_MAX_IMAGE_SIZE": 32700, + "EMBED_PATH": r"[/]?embed/", } @@ -93,6 +70,7 @@ class PipelineSettings(MutableMapping): """ Container object for pipeline settings """ + def __init__(self, wrapped_settings): self.settings = DEFAULTS.copy() self.settings.update(wrapped_settings) @@ -101,7 +79,7 @@ def __getitem__(self, key): value = self.settings[key] if key.endswith(("_BINARY", "_ARGUMENTS")): if isinstance(value, (str,)): - return tuple(shlex.split(value, posix=(os.name == 'posix'))) + return tuple(shlex.split(value, posix=(os.name == "posix"))) return tuple(value) return value @@ -126,5 +104,5 @@ def __getattr__(self, name): @receiver(setting_changed) def reload_settings(**kwargs): - if kwargs['setting'] == 'PIPELINE': - settings.update(kwargs['value']) + if kwargs["setting"] == "PIPELINE": + settings.update(kwargs["value"]) diff --git a/pipeline/finders.py b/pipeline/finders.py index 4739ee24..b0ce890e 100644 --- a/pipeline/finders.py +++ b/pipeline/finders.py @@ -1,11 +1,13 @@ from itertools import chain from os.path import normpath -from django.contrib.staticfiles.finders import \ - AppDirectoriesFinder as DjangoAppDirectoriesFinder +from django.contrib.staticfiles.finders import ( + AppDirectoriesFinder as DjangoAppDirectoriesFinder, +) from django.contrib.staticfiles.finders import BaseFinder, BaseStorageFinder -from django.contrib.staticfiles.finders import \ - FileSystemFinder as DjangoFileSystemFinder +from django.contrib.staticfiles.finders import ( + FileSystemFinder as DjangoFileSystemFinder, +) from django.contrib.staticfiles.finders import find from django.contrib.staticfiles.storage import staticfiles_storage from django.utils._os import safe_join @@ -33,7 +35,7 @@ def find(self, path, all=False): """ matches = [] for elem in chain(settings.STYLESHEETS.values(), settings.JAVASCRIPT.values()): - if normpath(elem['output_filename']) == normpath(path): + if normpath(elem["output_filename"]) == normpath(path): match = safe_join(settings.PIPELINE_ROOT, path) if not all: return match @@ -50,10 +52,10 @@ def find(self, path, all=False): Work out the uncached name of the file and look that up instead """ try: - start, _, extn = path.rsplit('.', 2) + start, _, extn = path.rsplit(".", 2) except ValueError: return [] - path = '.'.join((start, extn)) + path = ".".join((start, extn)) return find(path, all=all) or [] def list(self, *args): @@ -80,12 +82,13 @@ class AppDirectoriesFinder(PatternFilterMixin, DjangoAppDirectoriesFinder): This allows us to concentrate/compress our components without dragging the raw versions in via collectstatic. """ + ignore_patterns = [ - '*.js', - '*.css', - '*.less', - '*.scss', - '*.styl', + "*.js", + "*.css", + "*.less", + "*.scss", + "*.styl", ] @@ -96,28 +99,29 @@ class FileSystemFinder(PatternFilterMixin, DjangoFileSystemFinder): This allows us to concentrate/compress our components without dragging the raw versions in too. """ + ignore_patterns = [ - '*.js', - '*.css', - '*.less', - '*.scss', - '*.styl', - '*.sh', - '*.html', - '*.md', - '*.markdown', - '*.php', - '*.txt', - 'README*', - 'LICENSE*', - '*examples*', - '*test*', - '*bin*', - '*samples*', - '*docs*', - '*build*', - '*demo*', - 'Makefile*', - 'Gemfile*', - 'node_modules', + "*.js", + "*.css", + "*.less", + "*.scss", + "*.styl", + "*.sh", + "*.html", + "*.md", + "*.markdown", + "*.php", + "*.txt", + "README*", + "LICENSE*", + "*examples*", + "*test*", + "*bin*", + "*samples*", + "*docs*", + "*build*", + "*demo*", + "Makefile*", + "Gemfile*", + "node_modules", ] diff --git a/pipeline/forms.py b/pipeline/forms.py index 1c3cd8b7..57086735 100644 --- a/pipeline/forms.py +++ b/pipeline/forms.py @@ -122,8 +122,7 @@ def __new__(cls, name, bases, attrs): type: The new class. """ - new_class = super().__new__( - cls, name, bases, attrs) + new_class = super().__new__(cls, name, bases, attrs) # If we define any packages, we'll need to use our special # PipelineFormMediaProperty class. We use this instead of intercepting @@ -132,13 +131,15 @@ def __new__(cls, name, bases, attrs): # and accesses them from there. By using these special properties, we # can handle direct access (Media.css) and dictionary-based access # (Media.__dict__['css']). - if 'css_packages' in attrs: + if "css_packages" in attrs: new_class.css = PipelineFormMediaProperty( - cls._get_css_files, new_class, attrs.get('css') or {}) + cls._get_css_files, new_class, attrs.get("css") or {} + ) - if 'js_packages' in attrs: + if "js_packages" in attrs: new_class.js = PipelineFormMediaProperty( - cls._get_js_files, new_class, attrs.get('js') or []) + cls._get_js_files, new_class, attrs.get("js") or [] + ) return new_class @@ -156,13 +157,13 @@ def _get_css_files(cls, extra_files): attribute. """ packager = Packager() - css_packages = getattr(cls, 'css_packages', {}) + css_packages = getattr(cls, "css_packages", {}) return { media_target: cls._get_media_files( packager=packager, media_packages=media_packages, - media_type='css', + media_type="css", extra_files=extra_files.get(media_target, []), ) for media_target, media_packages in css_packages.items() @@ -182,12 +183,12 @@ def _get_js_files(cls, extra_files): """ return cls._get_media_files( packager=Packager(), - media_packages=getattr(cls, 'js_packages', {}), - media_type='js', - extra_files=extra_files) + media_packages=getattr(cls, "js_packages", {}), + media_type="js", + extra_files=extra_files, + ) - def _get_media_files(cls, packager, media_packages, media_type, - extra_files): + def _get_media_files(cls, packager, media_packages, media_type, extra_files): """Return source or output media files for a list of packages. This will go through the media files belonging to the provided list @@ -214,15 +215,14 @@ def _get_media_files(cls, packager, media_packages, media_type, """ source_files = list(extra_files) - if (not settings.PIPELINE_ENABLED and settings.PIPELINE_COLLECTOR_ENABLED): + if not settings.PIPELINE_ENABLED and settings.PIPELINE_COLLECTOR_ENABLED: default_collector.collect() for media_package in media_packages: package = packager.package_for(media_type, media_package) if settings.PIPELINE_ENABLED: - source_files.append( - staticfiles_storage.url(package.output_filename)) + source_files.append(staticfiles_storage.url(package.output_filename)) else: source_files += packager.compile(package.paths) diff --git a/pipeline/glob.py b/pipeline/glob.py index 26622b8a..e084b238 100644 --- a/pipeline/glob.py +++ b/pipeline/glob.py @@ -42,6 +42,7 @@ def iglob(pathname): for name in glob_in_dir(dirname, basename): yield os.path.join(dirname, name) + # These 2 helper functions non-recursively glob inside a literal directory. # They return a list of basenames. `glob1` accepts a pattern while `glob0` # takes a literal basename (so it only has to check for its existence). @@ -55,8 +56,8 @@ def glob1(dirname, pattern): # We are not sure that dirname is a real directory # and storage implementations are really exotic. return [] - if pattern[0] != '.': - names = [x for x in names if x[0] != '.'] + if pattern[0] != ".": + names = [x for x in names if x[0] != "."] return fnmatch.filter(names, pattern) @@ -66,7 +67,7 @@ def glob0(dirname, basename): return [] -magic_check = re.compile('[*?[]') +magic_check = re.compile("[*?[]") def has_magic(s): diff --git a/pipeline/jinja2/__init__.py b/pipeline/jinja2/__init__.py index dad04b9b..827003a2 100644 --- a/pipeline/jinja2/__init__.py +++ b/pipeline/jinja2/__init__.py @@ -8,7 +8,7 @@ class PipelineExtension(PipelineMixin, Extension): - tags = {'stylesheet', 'javascript'} + tags = {"stylesheet", "javascript"} def parse(self, parser): tag = next(parser.stream) @@ -20,61 +20,60 @@ def parse(self, parser): args = [package_name] if tag.value == "stylesheet": return nodes.CallBlock( - self.call_method('package_css', args), [], [], [] + self.call_method("package_css", args), [], [], [] ).set_lineno(tag.lineno) if tag.value == "javascript": return nodes.CallBlock( - self.call_method('package_js', args), [], [], [] + self.call_method("package_js", args), [], [], [] ).set_lineno(tag.lineno) return [] def package_css(self, package_name, *args, **kwargs): try: - package = self.package_for(package_name, 'css') + package = self.package_for(package_name, "css") except PackageNotFound: # fail silently, do not return anything if an invalid group is specified - return '' - return self.render_compressed(package, package_name, 'css') + return "" + return self.render_compressed(package, package_name, "css") def render_css(self, package, path): template_name = package.template_name or "pipeline/css.jinja" context = package.extra_context - context.update({ - 'type': guess_type(path, 'text/css'), - 'url': staticfiles_storage.url(path) - }) + context.update( + {"type": guess_type(path, "text/css"), "url": staticfiles_storage.url(path)} + ) template = self.environment.get_template(template_name) return template.render(context) def render_individual_css(self, package, paths, **kwargs): tags = [self.render_css(package, path) for path in paths] - return '\n'.join(tags) + return "\n".join(tags) def package_js(self, package_name, *args, **kwargs): try: - package = self.package_for(package_name, 'js') + package = self.package_for(package_name, "js") except PackageNotFound: # fail silently, do not return anything if an invalid group is specified - return '' - return self.render_compressed(package, package_name, 'js') + return "" + return self.render_compressed(package, package_name, "js") def render_js(self, package, path): template_name = package.template_name or "pipeline/js.jinja" context = package.extra_context - context.update({ - 'type': guess_type(path, 'text/javascript'), - 'url': staticfiles_storage.url(path) - }) + context.update( + { + "type": guess_type(path, "text/javascript"), + "url": staticfiles_storage.url(path), + } + ) template = self.environment.get_template(template_name) return template.render(context) def render_inline(self, package, js): context = package.extra_context - context.update({ - 'source': js - }) + context.update({"source": js}) template = self.environment.get_template("pipeline/inline_js.jinja") return template.render(context) @@ -82,4 +81,4 @@ def render_individual_js(self, package, paths, templates=None): tags = [self.render_js(package, js) for js in paths] if templates: tags.append(self.render_inline(package, templates)) - return '\n'.join(tags) + return "\n".join(tags) diff --git a/pipeline/middleware.py b/pipeline/middleware.py index abd477fd..a37eb01b 100644 --- a/pipeline/middleware.py +++ b/pipeline/middleware.py @@ -13,11 +13,13 @@ def __init__(self, *args, **kwargs): raise MiddlewareNotUsed def process_response(self, request, response): - if (response.has_header('Content-Type') and - 'text/html' in response['Content-Type']): + if ( + response.has_header("Content-Type") + and "text/html" in response["Content-Type"] + ): try: - response.content = minify_html(response.content.decode('utf-8').strip()) - response['Content-Length'] = str(len(response.content)) + response.content = minify_html(response.content.decode("utf-8").strip()) + response["Content-Length"] = str(len(response.content)) except DjangoUnicodeDecodeError: pass return response diff --git a/pipeline/packager.py b/pipeline/packager.py index 770bf855..f6c4a3ef 100644 --- a/pipeline/packager.py +++ b/pipeline/packager.py @@ -20,7 +20,7 @@ def __init__(self, config): def sources(self): if not self._sources: paths = [] - for pattern in self.config.get('source_filenames', []): + for pattern in self.config.get("source_filenames", []): for path in glob(pattern): if path not in paths and find(path): paths.append(str(path)) @@ -29,37 +29,37 @@ def sources(self): @property def paths(self): - return [path for path in self.sources - if not path.endswith(settings.TEMPLATE_EXT)] + return [ + path for path in self.sources if not path.endswith(settings.TEMPLATE_EXT) + ] @property def templates(self): - return [path for path in self.sources - if path.endswith(settings.TEMPLATE_EXT)] + return [path for path in self.sources if path.endswith(settings.TEMPLATE_EXT)] @property def output_filename(self): - return self.config.get('output_filename') + return self.config.get("output_filename") @property def extra_context(self): - return self.config.get('extra_context', {}) + return self.config.get("extra_context", {}) @property def template_name(self): - return self.config.get('template_name') + return self.config.get("template_name") @property def variant(self): - return self.config.get('variant') + return self.config.get("variant") @property def manifest(self): - return self.config.get('manifest', True) + return self.config.get("manifest", True) @property def compiler_options(self): - return self.config.get('compiler_options', {}) + return self.config.get("compiler_options", {}) class Packager: @@ -81,8 +81,8 @@ def __init__( if js_packages is None: js_packages = settings.JAVASCRIPT self.packages = { - 'css': self.create_packages(css_packages), - 'js': self.create_packages(js_packages), + "css": self.create_packages(css_packages), + "js": self.create_packages(js_packages), } def package_for(self, kind, package_name): @@ -99,9 +99,14 @@ def individual_url(self, filename): return self.storage.url(filename) def pack_stylesheets(self, package, **kwargs): - return self.pack(package, self.compressor.compress_css, css_compressed, - output_filename=package.output_filename, - variant=package.variant, **kwargs) + return self.pack( + package, + self.compressor.compress_css, + css_compressed, + output_filename=package.output_filename, + variant=package.variant, + **kwargs, + ) def compile(self, paths, compiler_options={}, force=False): paths = self.compiler.compile( @@ -159,7 +164,7 @@ def save_file(self, path, content): def find_source_storage(self, path): for finder in get_finders(): - for short_path, storage in finder.list(''): + for short_path, storage in finder.list(""): if short_path == path: if self.verbose: print("Found storage: %s" % str(self.storage)) diff --git a/pipeline/storage.py b/pipeline/storage.py index 6759e942..3b9e7020 100644 --- a/pipeline/storage.py +++ b/pipeline/storage.py @@ -2,12 +2,14 @@ from io import BytesIO from django import get_version as django_version -from django.contrib.staticfiles.storage import (ManifestStaticFilesStorage, - StaticFilesStorage) +from django.contrib.staticfiles.storage import ( + ManifestStaticFilesStorage, + StaticFilesStorage, +) from django.contrib.staticfiles.utils import matches_patterns from django.core.files.base import File -_CACHED_STATIC_FILES_STORAGE_AVAILABLE = django_version() < '3.1' +_CACHED_STATIC_FILES_STORAGE_AVAILABLE = django_version() < "3.1" if _CACHED_STATIC_FILES_STORAGE_AVAILABLE: from django.contrib.staticfiles.storage import CachedStaticFilesStorage @@ -21,16 +23,17 @@ def post_process(self, paths, dry_run=False, **options): return from pipeline.packager import Packager + packager = Packager(storage=self) - for package_name in packager.packages['css']: - package = packager.package_for('css', package_name) + for package_name in packager.packages["css"]: + package = packager.package_for("css", package_name) output_file = package.output_filename if self.packing: packager.pack_stylesheets(package) paths[output_file] = (self, output_file) yield output_file, output_file, True - for package_name in packager.packages['js']: - package = packager.package_for('js', package_name) + for package_name in packager.packages["js"]: + package = packager.package_for("js", package_name) output_file = package.output_filename if self.packing: packager.pack_javascripts(package) @@ -38,10 +41,8 @@ def post_process(self, paths, dry_run=False, **options): yield output_file, output_file, True super_class = super() - if hasattr(super_class, 'post_process'): - yield from super_class.post_process( - paths.copy(), dry_run, **options - ) + if hasattr(super_class, "post_process"): + yield from super_class.post_process(paths.copy(), dry_run, **options) def get_available_name(self, name, max_length=None): if self.exists(name): @@ -54,7 +55,7 @@ class GZIPMixin: def _compress(self, original_file): content = BytesIO() - gzip_file = gzip.GzipFile(mode='wb', fileobj=content) + gzip_file = gzip.GzipFile(mode="wb", fileobj=content) gzip_file.write(original_file.read()) gzip_file.close() content.seek(0) @@ -62,7 +63,7 @@ def _compress(self, original_file): def post_process(self, paths, dry_run=False, **options): super_class = super() - if hasattr(super_class, 'post_process'): + if hasattr(super_class, "post_process"): for name, hashed_name, processed in super_class.post_process( paths.copy(), dry_run, **options ): @@ -99,14 +100,13 @@ class NonPackagingPipelineStorage(NonPackagingMixin, PipelineStorage): if _CACHED_STATIC_FILES_STORAGE_AVAILABLE: + class PipelineCachedStorage(PipelineMixin, CachedStaticFilesStorage): # Deprecated since Django 2.2 # Removed in Django 3.1 pass - class NonPackagingPipelineCachedStorage( - NonPackagingMixin, PipelineCachedStorage - ): + class NonPackagingPipelineCachedStorage(NonPackagingMixin, PipelineCachedStorage): # Deprecated since Django 2.2 # Removed in Django 3.1 pass diff --git a/pipeline/templatetags/pipeline.py b/pipeline/templatetags/pipeline.py index 99edfe67..20c9bb42 100644 --- a/pipeline/templatetags/pipeline.py +++ b/pipeline/templatetags/pipeline.py @@ -25,21 +25,21 @@ class PipelineMixin: @property def request_var(self): if not self._request_var: - self._request_var = template.Variable('request') + self._request_var = template.Variable("request") return self._request_var def package_for(self, package_name, package_type): package = { - 'js': getattr(settings, 'JAVASCRIPT', {}).get(package_name, {}), - 'css': getattr(settings, 'STYLESHEETS', {}).get(package_name, {}), + "js": getattr(settings, "JAVASCRIPT", {}).get(package_name, {}), + "css": getattr(settings, "STYLESHEETS", {}).get(package_name, {}), }[package_type] if package: package = {package_name: package} packager = { - 'js': Packager(css_packages={}, js_packages=package), - 'css': Packager(css_packages=package, js_packages={}), + "js": Packager(css_packages={}, js_packages=package), + "css": Packager(css_packages=package, js_packages={}), }[package_type] return packager.package_for(package_type, package_name) @@ -62,11 +62,9 @@ def render_compressed(self, package, package_name, package_type): determining what to render. """ if settings.PIPELINE_ENABLED: - return self.render_compressed_output(package, package_name, - package_type) + return self.render_compressed_output(package, package_name, package_type) else: - return self.render_compressed_sources(package, package_name, - package_type) + return self.render_compressed_sources(package, package_name, package_type) def render_compressed_output(self, package, package_name, package_type): """Render HTML for using the package's output file. @@ -74,7 +72,7 @@ def render_compressed_output(self, package, package_name, package_type): Subclasses can override this method to provide custom behavior for rendering the output file. """ - method = getattr(self, f'render_{package_type}') + method = getattr(self, f"render_{package_type}") return method(package, package.output_filename) @@ -95,13 +93,13 @@ def render_compressed_sources(self, package, package_name, package_type): default_collector.collect(self.request) packager = Packager() - method = getattr(self, f'render_individual_{package_type}') + method = getattr(self, f"render_individual_{package_type}") try: paths = packager.compile(package.paths) except CompilerError as e: if settings.SHOW_ERRORS_INLINE: - method = getattr(self, f'render_error_{package_type}') + method = getattr(self, f"render_error_{package_type}") return method(package_name, e) else: raise @@ -111,12 +109,15 @@ def render_compressed_sources(self, package, package_name, package_type): return method(package, paths, templates=templates) def render_error(self, package_type, package_name, e): - return render_to_string('pipeline/compile_error.html', { - 'package_type': package_type, - 'package_name': package_name, - 'command': subprocess.list2cmdline(e.command), - 'errors': e.error_output, - }) + return render_to_string( + "pipeline/compile_error.html", + { + "package_type": package_type, + "package_name": package_name, + "command": subprocess.list2cmdline(e.command), + "errors": e.error_output, + }, + ) class StylesheetNode(PipelineMixin, template.Node): @@ -128,30 +129,31 @@ def render(self, context): package_name = template.Variable(self.name).resolve(context) try: - package = self.package_for(package_name, 'css') + package = self.package_for(package_name, "css") except PackageNotFound: w = "Package %r is unknown. Check PIPELINE['STYLESHEETS'] in your settings." logger.warn(w, package_name) # fail silently, do not return anything if an invalid group is specified - return '' - return self.render_compressed(package, package_name, 'css') + return "" + return self.render_compressed(package, package_name, "css") def render_css(self, package, path): template_name = package.template_name or "pipeline/css.html" context = package.extra_context - context.update({ - 'type': guess_type(path, 'text/css'), - 'url': mark_safe(staticfiles_storage.url(path)) - }) + context.update( + { + "type": guess_type(path, "text/css"), + "url": mark_safe(staticfiles_storage.url(path)), + } + ) return render_to_string(template_name, context) def render_individual_css(self, package, paths, **kwargs): tags = [self.render_css(package, path) for path in paths] - return '\n'.join(tags) + return "\n".join(tags) def render_error_css(self, package_name, e): - return super().render_error( - 'CSS', package_name, e) + return super().render_error("CSS", package_name, e) class JavascriptNode(PipelineMixin, template.Node): @@ -163,39 +165,38 @@ def render(self, context): package_name = template.Variable(self.name).resolve(context) try: - package = self.package_for(package_name, 'js') + package = self.package_for(package_name, "js") except PackageNotFound: w = "Package %r is unknown. Check PIPELINE['JAVASCRIPT'] in your settings." logger.warn(w, package_name) # fail silently, do not return anything if an invalid group is specified - return '' - return self.render_compressed(package, package_name, 'js') + return "" + return self.render_compressed(package, package_name, "js") def render_js(self, package, path): template_name = package.template_name or "pipeline/js.html" context = package.extra_context - context.update({ - 'type': guess_type(path, 'text/javascript'), - 'url': mark_safe(staticfiles_storage.url(path)) - }) + context.update( + { + "type": guess_type(path, "text/javascript"), + "url": mark_safe(staticfiles_storage.url(path)), + } + ) return render_to_string(template_name, context) def render_inline(self, package, js): context = package.extra_context - context.update({ - 'source': js - }) + context.update({"source": js}) return render_to_string("pipeline/inline_js.html", context) def render_individual_js(self, package, paths, templates=None): tags = [self.render_js(package, js) for js in paths] if templates: tags.append(self.render_inline(package, templates)) - return '\n'.join(tags) + return "\n".join(tags) def render_error_js(self, package_name, e): - return super().render_error( - 'JavaScript', package_name, e) + return super().render_error("JavaScript", package_name, e) @register.tag @@ -204,8 +205,8 @@ def stylesheet(parser, token): tag_name, name = token.split_contents() except ValueError: e = ( - '%r requires exactly one argument: the name ' - 'of a group in the PIPELINE.STYLESHEETS setting' + "%r requires exactly one argument: the name " + "of a group in the PIPELINE.STYLESHEETS setting" ) raise template.TemplateSyntaxError(e % token.split_contents()[0]) return StylesheetNode(name) @@ -217,8 +218,8 @@ def javascript(parser, token): tag_name, name = token.split_contents() except ValueError: e = ( - '%r requires exactly one argument: the name ' - 'of a group in the PIPELINE.JAVASVRIPT setting' + "%r requires exactly one argument: the name " + "of a group in the PIPELINE.JAVASVRIPT setting" ) raise template.TemplateSyntaxError(e % token.split_contents()[0]) return JavascriptNode(name) diff --git a/pipeline/utils.py b/pipeline/utils.py index 1eff4dcc..add18328 100644 --- a/pipeline/utils.py +++ b/pipeline/utils.py @@ -20,8 +20,8 @@ def to_class(class_str): if not class_str: return None - module_bits = class_str.split('.') - module_path, class_name = '.'.join(module_bits[:-1]), module_bits[-1] + module_bits = class_str.split(".") + module_path, class_name = ".".join(module_bits[:-1]), module_bits[-1] module = importlib.import_module(module_path) return getattr(module, class_name, None) diff --git a/pipeline/views.py b/pipeline/views.py index 2d8eecb9..b801ac8c 100644 --- a/pipeline/views.py +++ b/pipeline/views.py @@ -22,9 +22,11 @@ def serve_static(request, path, insecure=False, **kwargs): # Follow the same logic Django uses for determining access to the # static-serving view. if not django_settings.DEBUG and not insecure: - raise ImproperlyConfigured("The staticfiles view can only be used in " - "debug mode or if the --insecure " - "option of 'runserver' is used") + raise ImproperlyConfigured( + "The staticfiles view can only be used in " + "debug mode or if the --insecure " + "option of 'runserver' is used" + ) if not settings.PIPELINE_ENABLED and settings.PIPELINE_COLLECTOR_ENABLED: # Collect only the requested file, in order to serve the result as @@ -32,5 +34,4 @@ def serve_static(request, path, insecure=False, **kwargs): # way, as those will still cause Django to collect all media. default_collector.collect(request, files=[path]) - return serve(request, path, document_root=django_settings.STATIC_ROOT, - **kwargs) + return serve(request, path, document_root=django_settings.STATIC_ROOT, **kwargs) diff --git a/setup.py b/setup.py index 394669e4..7f11fcec 100644 --- a/setup.py +++ b/setup.py @@ -1,45 +1,45 @@ from setuptools import find_packages, setup setup( - name='django-pipeline', + name="django-pipeline", use_scm_version={"version_scheme": "post-release"}, setup_requires=["setuptools_scm"], - description='Pipeline is an asset packaging library for Django.', + description="Pipeline is an asset packaging library for Django.", long_description=( - open('README.rst', encoding='utf-8').read() + '\n\n' + - open('HISTORY.rst', encoding='utf-8').read() + open("README.rst", encoding="utf-8").read() + + "\n\n" + + open("HISTORY.rst", encoding="utf-8").read() ), - author='Timothée Peignier', - author_email='timothee.peignier@tryphon.org', - url='https://github.com/jazzband/django-pipeline', - license='MIT', - packages=find_packages(exclude=['tests', 'tests.tests']), + author="Timothée Peignier", + author_email="timothee.peignier@tryphon.org", + url="https://github.com/jazzband/django-pipeline", + license="MIT", + packages=find_packages(exclude=["tests", "tests.tests"]), zip_safe=False, include_package_data=True, - keywords=('django pipeline asset compiling concatenation compression' - ' packaging'), + keywords=("django pipeline asset compiling concatenation compression" " packaging"), classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Environment :: Web Environment', - 'Framework :: Django', - 'Framework :: Django :: 3.2', - 'Framework :: Django :: 4.0', - 'Framework :: Django :: 4.1', - 'Framework :: Django :: 4.2', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3 :: Only', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - 'Programming Language :: Python :: Implementation :: PyPy', - 'Topic :: Utilities', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'Topic :: Internet :: WWW/HTTP', - 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', - ] + "Development Status :: 5 - Production/Stable", + "Environment :: Web Environment", + "Framework :: Django", + "Framework :: Django :: 3.2", + "Framework :: Django :: 4.0", + "Framework :: Django :: 4.1", + "Framework :: Django :: 4.2", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Utilities", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Internet :: WWW/HTTP :: Dynamic Content", + ], ) diff --git a/tests/settings.py b/tests/settings.py index e5b4f4fc..be61ffad 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -8,10 +8,7 @@ def local_path(path): DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'TEST_NAME': ':memory:' - } + "default": {"ENGINE": "django.db.backends.sqlite3", "TEST_NAME": ":memory:"} } DEBUG = False @@ -19,221 +16,222 @@ def local_path(path): SITE_ID = 1 INSTALLED_APPS = [ - 'django.contrib.contenttypes', - 'django.contrib.messages', - 'django.contrib.sites', - 'django.contrib.sessions', - 'django.contrib.staticfiles', - 'django.contrib.auth', - 'django.contrib.admin', - 'pipeline', - 'tests.tests' + "django.contrib.contenttypes", + "django.contrib.messages", + "django.contrib.sites", + "django.contrib.sessions", + "django.contrib.staticfiles", + "django.contrib.auth", + "django.contrib.admin", + "pipeline", + "tests.tests", ] -ROOT_URLCONF = 'tests.urls' +ROOT_URLCONF = "tests.urls" MIDDLEWARE = [ - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', + "django.contrib.sessions.middleware.SessionMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", ] -MEDIA_URL = '/media/' +MEDIA_URL = "/media/" -MEDIA_ROOT = local_path('media') +MEDIA_ROOT = local_path("media") -STATICFILES_STORAGE = 'pipeline.storage.PipelineStorage' -STATIC_ROOT = local_path('static/') -STATIC_URL = '/static/' -STATICFILES_DIRS = ( - ('pipeline', local_path('assets/')), -) +STATICFILES_STORAGE = "pipeline.storage.PipelineStorage" +STATIC_ROOT = local_path("static/") +STATIC_URL = "/static/" +STATICFILES_DIRS = (("pipeline", local_path("assets/")),) STATICFILES_FINDERS = ( - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', - 'pipeline.finders.PipelineFinder', + "django.contrib.staticfiles.finders.FileSystemFinder", + "django.contrib.staticfiles.finders.AppDirectoriesFinder", + "pipeline.finders.PipelineFinder", ) SECRET_KEY = "django-pipeline" PIPELINE = { - 'PIPELINE_ENABLED': True, - 'JS_COMPRESSOR': None, - 'CSS_COMPRESSOR': None, - 'STYLESHEETS': { - 'screen': { - 'source_filenames': ( - 'pipeline/css/first.css', - 'pipeline/css/second.css', - 'pipeline/css/urls.css' + "PIPELINE_ENABLED": True, + "JS_COMPRESSOR": None, + "CSS_COMPRESSOR": None, + "STYLESHEETS": { + "screen": { + "source_filenames": ( + "pipeline/css/first.css", + "pipeline/css/second.css", + "pipeline/css/urls.css", ), - 'output_filename': 'screen.css' + "output_filename": "screen.css", }, - 'screen_media': { - 'source_filenames': ( - 'pipeline/css/first.css', - 'pipeline/css/second.css', - 'pipeline/css/urls.css' + "screen_media": { + "source_filenames": ( + "pipeline/css/first.css", + "pipeline/css/second.css", + "pipeline/css/urls.css", ), - 'output_filename': 'screen_media.css', - 'extra_context': { - 'media': 'screen and (min-width:500px)', + "output_filename": "screen_media.css", + "extra_context": { + "media": "screen and (min-width:500px)", }, }, - 'screen_title': { - 'source_filenames': ( - 'pipeline/css/first.css', - 'pipeline/css/second.css', - 'pipeline/css/urls.css' + "screen_title": { + "source_filenames": ( + "pipeline/css/first.css", + "pipeline/css/second.css", + "pipeline/css/urls.css", ), - 'output_filename': 'screen_title.css', - 'extra_context': { - 'title': 'Default Style', + "output_filename": "screen_title.css", + "extra_context": { + "title": "Default Style", }, - } + }, }, - 'JAVASCRIPT': { - 'scripts': { - 'source_filenames': ( - 'pipeline/js/first.js', - 'pipeline/js/second.js', - 'pipeline/js/application.js', - 'pipeline/templates/**/*.jst' + "JAVASCRIPT": { + "scripts": { + "source_filenames": ( + "pipeline/js/first.js", + "pipeline/js/second.js", + "pipeline/js/application.js", + "pipeline/templates/**/*.jst", ), - 'output_filename': 'scripts.js' + "output_filename": "scripts.js", }, - 'scripts_async': { - 'source_filenames': ( - 'pipeline/js/first.js', - 'pipeline/js/second.js', - 'pipeline/js/application.js', - 'pipeline/templates/**/*.jst' + "scripts_async": { + "source_filenames": ( + "pipeline/js/first.js", + "pipeline/js/second.js", + "pipeline/js/application.js", + "pipeline/templates/**/*.jst", ), - 'output_filename': 'scripts_async.js', - 'extra_context': { - 'async': True, - } + "output_filename": "scripts_async.js", + "extra_context": { + "async": True, + }, }, - 'scripts_defer': { - 'source_filenames': ( - 'pipeline/js/first.js', - 'pipeline/js/second.js', - 'pipeline/js/application.js', - 'pipeline/templates/**/*.jst' + "scripts_defer": { + "source_filenames": ( + "pipeline/js/first.js", + "pipeline/js/second.js", + "pipeline/js/application.js", + "pipeline/templates/**/*.jst", ), - 'output_filename': 'scripts_defer.js', - 'extra_context': { - 'defer': True, - } + "output_filename": "scripts_defer.js", + "extra_context": { + "defer": True, + }, }, - 'scripts_async_defer': { - 'source_filenames': ( - 'pipeline/js/first.js', - 'pipeline/js/second.js', - 'pipeline/js/application.js', - 'pipeline/templates/**/*.jst' + "scripts_async_defer": { + "source_filenames": ( + "pipeline/js/first.js", + "pipeline/js/second.js", + "pipeline/js/application.js", + "pipeline/templates/**/*.jst", ), - 'output_filename': 'scripts_async_defer.js', - 'extra_context': { - 'async': True, - 'defer': True, - } - } - } + "output_filename": "scripts_async_defer.js", + "extra_context": { + "async": True, + "defer": True, + }, + }, + }, } -NODE_MODULES_PATH = local_path('../node_modules') -NODE_BIN_PATH = os.path.join(NODE_MODULES_PATH, '.bin') -NODE_EXE_PATH = distutils.spawn.find_executable('node') -JAVA_EXE_PATH = distutils.spawn.find_executable('java') -CSSTIDY_EXE_PATH = distutils.spawn.find_executable('csstidy') +NODE_MODULES_PATH = local_path("../node_modules") +NODE_BIN_PATH = os.path.join(NODE_MODULES_PATH, ".bin") +NODE_EXE_PATH = distutils.spawn.find_executable("node") +JAVA_EXE_PATH = distutils.spawn.find_executable("java") +CSSTIDY_EXE_PATH = distutils.spawn.find_executable("csstidy") HAS_NODE = bool(NODE_EXE_PATH) HAS_JAVA = bool(JAVA_EXE_PATH) HAS_CSSTIDY = bool(CSSTIDY_EXE_PATH) if HAS_NODE: + def node_exe_path(command): - exe_ext = '.cmd' if os.name == 'nt' else '' + exe_ext = ".cmd" if os.name == "nt" else "" return os.path.join(NODE_BIN_PATH, "{}{}".format(command, exe_ext)) - PIPELINE.update({ - 'SASS_BINARY': node_exe_path('node-sass'), - 'COFFEE_SCRIPT_BINARY': node_exe_path('coffee'), - 'COFFEE_SCRIPT_ARGUMENTS': ['--no-header'], - 'LESS_BINARY': node_exe_path('lessc'), - 'BABEL_BINARY': node_exe_path('babel'), - 'BABEL_ARGUMENTS': ['--presets', 'es2015'], - 'STYLUS_BINARY': node_exe_path('stylus'), - 'LIVE_SCRIPT_BINARY': node_exe_path('lsc'), - 'LIVE_SCRIPT_ARGUMENTS': ['--no-header'], - 'YUGLIFY_BINARY': node_exe_path('yuglify'), - 'UGLIFYJS_BINARY': node_exe_path('uglifyjs'), - 'TERSER_BINARY': node_exe_path('terser'), - 'CSSMIN_BINARY': node_exe_path('cssmin'), - 'TYPE_SCRIPT_BINARY': node_exe_path('tsc'), - }) + PIPELINE.update( + { + "SASS_BINARY": node_exe_path("node-sass"), + "COFFEE_SCRIPT_BINARY": node_exe_path("coffee"), + "COFFEE_SCRIPT_ARGUMENTS": ["--no-header"], + "LESS_BINARY": node_exe_path("lessc"), + "BABEL_BINARY": node_exe_path("babel"), + "BABEL_ARGUMENTS": ["--presets", "es2015"], + "STYLUS_BINARY": node_exe_path("stylus"), + "LIVE_SCRIPT_BINARY": node_exe_path("lsc"), + "LIVE_SCRIPT_ARGUMENTS": ["--no-header"], + "YUGLIFY_BINARY": node_exe_path("yuglify"), + "UGLIFYJS_BINARY": node_exe_path("uglifyjs"), + "TERSER_BINARY": node_exe_path("terser"), + "CSSMIN_BINARY": node_exe_path("cssmin"), + "TYPE_SCRIPT_BINARY": node_exe_path("tsc"), + } + ) if HAS_NODE and HAS_JAVA: - PIPELINE.update({ - 'CLOSURE_BINARY': [ - JAVA_EXE_PATH, - '-jar', - os.path.join( - NODE_MODULES_PATH, - 'google-closure-compiler-java', - 'compiler.jar', - ), - ], - 'YUI_BINARY': [ - JAVA_EXE_PATH, - '-jar', - glob.glob( - os.path.join(NODE_MODULES_PATH, 'yuicompressor', 'build', '*.jar') - )[0], - ] - }) + PIPELINE.update( + { + "CLOSURE_BINARY": [ + JAVA_EXE_PATH, + "-jar", + os.path.join( + NODE_MODULES_PATH, + "google-closure-compiler-java", + "compiler.jar", + ), + ], + "YUI_BINARY": [ + JAVA_EXE_PATH, + "-jar", + glob.glob( + os.path.join(NODE_MODULES_PATH, "yuicompressor", "build", "*.jar") + )[0], + ], + } + ) if HAS_CSSTIDY: - PIPELINE.update({'CSSTIDY_BINARY': CSSTIDY_EXE_PATH}) + PIPELINE.update({"CSSTIDY_BINARY": CSSTIDY_EXE_PATH}) TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'APP_DIRS': True, - 'DIRS': [local_path('templates')], - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "APP_DIRS": True, + "DIRS": [local_path("templates")], + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", ] - } + }, }, { - 'BACKEND': 'django.template.backends.jinja2.Jinja2', - 'APP_DIRS': True, - 'DIRS': [local_path('templates')], - 'OPTIONS': { - 'extensions': ['pipeline.jinja2.PipelineExtension'] - } - } + "BACKEND": "django.template.backends.jinja2.Jinja2", + "APP_DIRS": True, + "DIRS": [local_path("templates")], + "OPTIONS": {"extensions": ["pipeline.jinja2.PipelineExtension"]}, + }, ] LOGGING = { - 'version': 1, - 'disable_existing_loggers': False, - 'handlers': { - 'console': { - 'class': 'logging.StreamHandler', + "version": 1, + "disable_existing_loggers": False, + "handlers": { + "console": { + "class": "logging.StreamHandler", }, }, - 'loggers': { - 'pipeline.templatetags.pipeline': { - 'handlers': ['console'], - 'level': 'ERROR', + "loggers": { + "pipeline.templatetags.pipeline": { + "handlers": ["console"], + "level": "ERROR", }, }, } diff --git a/tests/tests/__init__.py b/tests/tests/__init__.py index 3a6f83db..da0615bf 100644 --- a/tests/tests/__init__.py +++ b/tests/tests/__init__.py @@ -1,8 +1,8 @@ import os import sys -if sys.platform.startswith('win'): - os.environ.setdefault('NUMBER_OF_PROCESSORS', '1') +if sys.platform.startswith("win"): + os.environ.setdefault("NUMBER_OF_PROCESSORS", "1") from .test_collector import * # noqa diff --git a/tests/tests/test_collector.py b/tests/tests/test_collector.py index 5c273523..046b8f9a 100644 --- a/tests/tests/test_collector.py +++ b/tests/tests/test_collector.py @@ -9,7 +9,7 @@ def local_path(path): - return os.path.abspath(os.path.join(os.path.dirname(__file__), '..', path)) + return os.path.abspath(os.path.join(os.path.dirname(__file__), "..", path)) class CollectorTest(TestCase): @@ -20,43 +20,57 @@ def tearDown(self): def test_collect(self): self.assertEqual( - set(default_collector.collect()), - set(self._get_collectable_files())) + set(default_collector.collect()), set(self._get_collectable_files()) + ) def test_collect_with_files(self): self.assertEqual( - set(default_collector.collect(files=[ - 'pipeline/js/first.js', - 'pipeline/js/second.js', - ])), + set( + default_collector.collect( + files=[ + "pipeline/js/first.js", + "pipeline/js/second.js", + ] + ) + ), { - 'pipeline/js/first.js', - 'pipeline/js/second.js', - }) + "pipeline/js/first.js", + "pipeline/js/second.js", + }, + ) def test_delete_file_with_modified(self): list(default_collector.collect()) - storage = FileSystemStorage(local_path('assets')) - new_mtime = os.path.getmtime(storage.path('js/first.js')) - 1000 - os.utime(default_collector.storage.path('pipeline/js/first.js'), - (new_mtime, new_mtime)) + storage = FileSystemStorage(local_path("assets")) + new_mtime = os.path.getmtime(storage.path("js/first.js")) - 1000 + os.utime( + default_collector.storage.path("pipeline/js/first.js"), + (new_mtime, new_mtime), + ) - self.assertTrue(default_collector.delete_file( - 'js/first.js', 'pipeline/js/first.js', storage)) + self.assertTrue( + default_collector.delete_file( + "js/first.js", "pipeline/js/first.js", storage + ) + ) def test_delete_file_with_unmodified(self): - list(default_collector.collect(files=['pipeline/js/first.js'])) + list(default_collector.collect(files=["pipeline/js/first.js"])) - self.assertFalse(default_collector.delete_file( - 'js/first.js', 'pipeline/js/first.js', - FileSystemStorage(local_path('assets')))) + self.assertFalse( + default_collector.delete_file( + "js/first.js", + "pipeline/js/first.js", + FileSystemStorage(local_path("assets")), + ) + ) def _get_collectable_files(self): for finder in finders.get_finders(): if not isinstance(finder, PipelineFinder): - for path, storage in finder.list(['CVS', '.*', '*~']): - if getattr(storage, 'prefix', None): + for path, storage in finder.list(["CVS", ".*", "*~"]): + if getattr(storage, "prefix", None): yield os.path.join(storage.prefix, path) else: yield path diff --git a/tests/tests/test_compiler.py b/tests/tests/test_compiler.py index 3039fbd8..702473f2 100644 --- a/tests/tests/test_compiler.py +++ b/tests/tests/test_compiler.py @@ -14,82 +14,87 @@ class FailingCompiler(SubProcessCompiler): - output_extension = 'junk' + output_extension = "junk" def match_file(self, path): - return path.endswith('.coffee') + return path.endswith(".coffee") def compile_file(self, infile, outfile, outdated=False, force=False): - command = (("/usr/bin/env", "false",),) + command = ( + ( + "/usr/bin/env", + "false", + ), + ) return self.execute_command(command) class InvalidCompiler(SubProcessCompiler): - output_extension = 'junk' + output_extension = "junk" def match_file(self, path): - return path.endswith('.coffee') + return path.endswith(".coffee") def compile_file(self, infile, outfile, outdated=False, force=False): command = ( ("this-exists-nowhere-as-a-command-and-should-fail",), infile, - outfile + outfile, ) return self.execute_command(command) class CompilerWithEmptyFirstArg(SubProcessCompiler): - output_extension = 'junk' + output_extension = "junk" def match_file(self, path): - return path.endswith('.coffee') + return path.endswith(".coffee") def compile_file(self, infile, outfile, outdated=False, force=False): command = ( - ('', '/usr/bin/env', 'cat'), + ("", "/usr/bin/env", "cat"), infile, ) return self.execute_command(command, stdout_captured=outfile) class CopyingCompiler(SubProcessCompiler): - output_extension = 'junk' + output_extension = "junk" def match_file(self, path): - return path.endswith('.coffee') + return path.endswith(".coffee") def compile_file(self, infile, outfile, outdated=False, force=False): - command = ( - "cp", - infile, - outfile - ) + command = ("cp", infile, outfile) return self.execute_command(command) class LineNumberingCompiler(SubProcessCompiler): - output_extension = 'junk' + output_extension = "junk" def match_file(self, path): - return path.endswith('.coffee') + return path.endswith(".coffee") def compile_file(self, infile, outfile, outdated=False, force=False): - command = (("/usr/bin/env", "cat"), ("-n",), infile,) + command = ( + ("/usr/bin/env", "cat"), + ("-n",), + infile, + ) return self.execute_command(command, stdout_captured=outfile) class DummyCompiler(CompilerBase): - output_extension = 'js' + output_extension = "js" def match_file(self, path): - return path.endswith('.coffee') + return path.endswith(".coffee") def compile_file(self, infile, outfile, outdated=False, force=False): return -@pipeline_settings(COMPILERS=['tests.tests.test_compiler.DummyCompiler']) +@pipeline_settings(COMPILERS=["tests.tests.test_compiler.DummyCompiler"]) class DummyCompilerTest(TestCase): def setUp(self): default_collector.collect() @@ -109,12 +114,14 @@ def test_compilers_class(self): self.assertEqual(compilers_class[0], DummyCompiler) def test_compile(self): - paths = self.compiler.compile([ - _('pipeline/js/dummy.coffee'), - _('pipeline/js/application.js'), - ]) + paths = self.compiler.compile( + [ + _("pipeline/js/dummy.coffee"), + _("pipeline/js/application.js"), + ] + ) self.assertEqual( - [_('pipeline/js/dummy.js'), _('pipeline/js/application.js')], + [_("pipeline/js/dummy.js"), _("pipeline/js/application.js")], list(paths), ) @@ -123,7 +130,7 @@ def tearDown(self): @skipIf(sys.platform.startswith("win"), "requires posix platform") -@pipeline_settings(COMPILERS=['tests.tests.test_compiler.LineNumberingCompiler']) +@pipeline_settings(COMPILERS=["tests.tests.test_compiler.LineNumberingCompiler"]) class CompilerStdoutTest(TestCase): def setUp(self): default_collector.collect() @@ -139,15 +146,15 @@ def test_output_path(self): self.assertEqual(output_path, "js/helpers.js") def test_compile(self): - paths = self.compiler.compile([_('pipeline/js/dummy.coffee')]) - self.assertEqual([_('pipeline/js/dummy.junk')], list(paths)) + paths = self.compiler.compile([_("pipeline/js/dummy.coffee")]) + self.assertEqual([_("pipeline/js/dummy.junk")], list(paths)) def tearDown(self): default_collector.clear() @skipIf(sys.platform.startswith("win"), "requires posix platform") -@pipeline_settings(COMPILERS=['tests.tests.test_compiler.CopyingCompiler']) +@pipeline_settings(COMPILERS=["tests.tests.test_compiler.CopyingCompiler"]) class CompilerSelfWriterTest(TestCase): def setUp(self): default_collector.collect() @@ -163,30 +170,30 @@ def test_output_path(self): self.assertEqual(output_path, "js/helpers.js") def test_compile(self): - paths = self.compiler.compile([_('pipeline/js/dummy.coffee')]) + paths = self.compiler.compile([_("pipeline/js/dummy.coffee")]) default_collector.collect() - self.assertEqual([_('pipeline/js/dummy.junk')], list(paths)) + self.assertEqual([_("pipeline/js/dummy.junk")], list(paths)) def tearDown(self): default_collector.clear() -@pipeline_settings(COMPILERS=['tests.tests.test_compiler.CompilerWithEmptyFirstArg']) +@pipeline_settings(COMPILERS=["tests.tests.test_compiler.CompilerWithEmptyFirstArg"]) class CompilerWithEmptyFirstArgTest(TestCase): def setUp(self): default_collector.collect() self.compiler = Compiler() def test_compile(self): - paths = self.compiler.compile([_('pipeline/js/dummy.coffee')]) + paths = self.compiler.compile([_("pipeline/js/dummy.coffee")]) default_collector.collect() - self.assertEqual([_('pipeline/js/dummy.junk')], list(paths)) + self.assertEqual([_("pipeline/js/dummy.junk")], list(paths)) def tearDown(self): default_collector.clear() -@pipeline_settings(COMPILERS=['tests.tests.test_compiler.InvalidCompiler']) +@pipeline_settings(COMPILERS=["tests.tests.test_compiler.InvalidCompiler"]) class InvalidCompilerTest(TestCase): def setUp(self): default_collector.collect() @@ -194,21 +201,24 @@ def setUp(self): def test_compile(self): with self.assertRaises(CompilerError) as cm: - self.compiler.compile([_('pipeline/js/dummy.coffee')]) + self.compiler.compile([_("pipeline/js/dummy.coffee")]) e = cm.exception self.assertEqual( e.command, - ['this-exists-nowhere-as-a-command-and-should-fail', - 'pipeline/js/dummy.coffee', - 'pipeline/js/dummy.junk']) - self.assertEqual(e.error_output, '') + [ + "this-exists-nowhere-as-a-command-and-should-fail", + "pipeline/js/dummy.coffee", + "pipeline/js/dummy.junk", + ], + ) + self.assertEqual(e.error_output, "") def tearDown(self): default_collector.clear() @skipIf(sys.platform.startswith("win"), "requires posix platform") -@pipeline_settings(COMPILERS=['tests.tests.test_compiler.FailingCompiler']) +@pipeline_settings(COMPILERS=["tests.tests.test_compiler.FailingCompiler"]) class FailingCompilerTest(TestCase): def setUp(self): default_collector.collect() @@ -216,11 +226,11 @@ def setUp(self): def test_compile(self): with self.assertRaises(CompilerError) as cm: - self.compiler.compile([_('pipeline/js/dummy.coffee')]) + self.compiler.compile([_("pipeline/js/dummy.coffee")]) e = cm.exception - self.assertEqual(e.command, ['/usr/bin/env', 'false']) - self.assertEqual(e.error_output, '') + self.assertEqual(e.command, ["/usr/bin/env", "false"]) + self.assertEqual(e.error_output, "") def tearDown(self): default_collector.clear() @@ -228,10 +238,9 @@ def tearDown(self): @skipUnless(settings.HAS_NODE, "requires node") class CompilerImplementation(TestCase): - def setUp(self): self.compiler = Compiler() - default_collector.collect(RequestFactory().get('/')) + default_collector.collect(RequestFactory().get("/")) def tearDown(self): default_collector.clear() @@ -244,55 +253,55 @@ def _test_compiler(self, compiler_cls_str, infile, expected): compiler.compile_file(_(infile_path), _(outfile_path), force=True) with open(outfile_path) as f: result = f.read() - with staticfiles_storage.open(expected, 'r') as f: + with staticfiles_storage.open(expected, "r") as f: expected = f.read() self.assertEqual(result, expected) def test_sass(self): self._test_compiler( - 'pipeline.compilers.sass.SASSCompiler', - 'pipeline/compilers/scss/input.scss', - 'pipeline/compilers/scss/expected.css', + "pipeline.compilers.sass.SASSCompiler", + "pipeline/compilers/scss/input.scss", + "pipeline/compilers/scss/expected.css", ) def test_coffeescript(self): self._test_compiler( - 'pipeline.compilers.coffee.CoffeeScriptCompiler', - 'pipeline/compilers/coffee/input.coffee', - 'pipeline/compilers/coffee/expected.js', + "pipeline.compilers.coffee.CoffeeScriptCompiler", + "pipeline/compilers/coffee/input.coffee", + "pipeline/compilers/coffee/expected.js", ) def test_less(self): self._test_compiler( - 'pipeline.compilers.less.LessCompiler', - 'pipeline/compilers/less/input.less', - 'pipeline/compilers/less/expected.css', + "pipeline.compilers.less.LessCompiler", + "pipeline/compilers/less/input.less", + "pipeline/compilers/less/expected.css", ) def test_es6(self): self._test_compiler( - 'pipeline.compilers.es6.ES6Compiler', - 'pipeline/compilers/es6/input.es6', - 'pipeline/compilers/es6/expected.js', + "pipeline.compilers.es6.ES6Compiler", + "pipeline/compilers/es6/input.es6", + "pipeline/compilers/es6/expected.js", ) def test_typescript(self): self._test_compiler( - 'pipeline.compilers.typescript.TypeScriptCompiler', - 'pipeline/compilers/typescript/input.ts', - 'pipeline/compilers/typescript/expected.js', + "pipeline.compilers.typescript.TypeScriptCompiler", + "pipeline/compilers/typescript/input.ts", + "pipeline/compilers/typescript/expected.js", ) def test_stylus(self): self._test_compiler( - 'pipeline.compilers.stylus.StylusCompiler', - 'pipeline/compilers/stylus/input.styl', - 'pipeline/compilers/stylus/expected.css', + "pipeline.compilers.stylus.StylusCompiler", + "pipeline/compilers/stylus/input.styl", + "pipeline/compilers/stylus/expected.css", ) def test_livescript(self): self._test_compiler( - 'pipeline.compilers.livescript.LiveScriptCompiler', - 'pipeline/compilers/livescript/input.ls', - 'pipeline/compilers/livescript/expected.js', + "pipeline.compilers.livescript.LiveScriptCompiler", + "pipeline/compilers/livescript/input.ls", + "pipeline/compilers/livescript/expected.js", ) diff --git a/tests/tests/test_compressor.py b/tests/tests/test_compressor.py index 3a64f657..425669b9 100644 --- a/tests/tests/test_compressor.py +++ b/tests/tests/test_compressor.py @@ -14,15 +14,15 @@ from django.test.client import RequestFactory from pipeline.collector import default_collector -from pipeline.compressors import (TEMPLATE_FUNC, Compressor, - SubProcessCompressor) +from pipeline.compressors import TEMPLATE_FUNC, Compressor, SubProcessCompressor from pipeline.compressors.yuglify import YuglifyCompressor from tests.utils import _, pipeline_settings @pipeline_settings( - CSS_COMPRESSOR='pipeline.compressors.yuglify.YuglifyCompressor', - JS_COMPRESSOR='pipeline.compressors.yuglify.YuglifyCompressor') + CSS_COMPRESSOR="pipeline.compressors.yuglify.YuglifyCompressor", + JS_COMPRESSOR="pipeline.compressors.yuglify.YuglifyCompressor", +) class CompressorTest(TestCase): def setUp(self): self.maxDiff = None @@ -36,124 +36,139 @@ def test_css_compressor_class(self): self.assertEqual(self.compressor.css_compressor, YuglifyCompressor) def test_concatenate_and_rewrite(self): - css = self.compressor.concatenate_and_rewrite([ - _('pipeline/css/first.css'), - _('pipeline/css/second.css') - ], 'css/screen.css') - expected = """.concat {\n display: none;\n}\n\n.concatenate {\n display: block;\n}\n""" # noqa + css = self.compressor.concatenate_and_rewrite( + [_("pipeline/css/first.css"), _("pipeline/css/second.css")], + "css/screen.css", + ) + expected = """.concat {\n display: none;\n}\n\n.concatenate {\n display: block;\n}\n""" # noqa self.assertEqual(expected, css) def test_concatenate(self): - js = self.compressor.concatenate([ - _('pipeline/js/first.js'), - _('pipeline/js/second.js') - ]) - expected = """(function() {\n window.concat = function() {\n console.log(arguments);\n }\n}()) // No semicolon\n\n;(function() {\n window.cat = function() {\n console.log("hello world");\n }\n}());\n""" # noqa + js = self.compressor.concatenate( + [_("pipeline/js/first.js"), _("pipeline/js/second.js")] + ) + expected = """(function() {\n window.concat = function() {\n console.log(arguments);\n }\n}()) // No semicolon\n\n;(function() {\n window.cat = function() {\n console.log("hello world");\n }\n}());\n""" # noqa self.assertEqual(expected, js) - @patch.object(base64, 'b64encode') + @patch.object(base64, "b64encode") def test_encoded_content(self, mock): self.compressor.asset_contents.clear() - self.compressor.encoded_content(_('pipeline/images/arrow.png')) + self.compressor.encoded_content(_("pipeline/images/arrow.png")) self.assertTrue(mock.called) mock.reset_mock() - self.compressor.encoded_content(_('pipeline/images/arrow.png')) + self.compressor.encoded_content(_("pipeline/images/arrow.png")) self.assertFalse(mock.called) def test_encoded_content_output(self): self.compressor.asset_contents.clear() - encoded = self.compressor.encoded_content(_('pipeline/images/arrow.png')) - expected = ('iVBORw0KGgoAAAANSUhEUgAAAAkAAAAGCAYAAAARx7TFAAAAMk' - 'lEQVR42oXKwQkAMAxC0Q7rEk5voSEepCHC9/SOpLV3JPULgArV' - 'RtDIMEEiQ4NECRNdciCfK3K3wvEAAAAASUVORK5CYII=') + encoded = self.compressor.encoded_content(_("pipeline/images/arrow.png")) + expected = ( + "iVBORw0KGgoAAAANSUhEUgAAAAkAAAAGCAYAAAARx7TFAAAAMk" + "lEQVR42oXKwQkAMAxC0Q7rEk5voSEepCHC9/SOpLV3JPULgArV" + "RtDIMEEiQ4NECRNdciCfK3K3wvEAAAAASUVORK5CYII=" + ) self.assertEqual(encoded, expected) def test_relative_path(self): relative_path = self.compressor.relative_path( "images/sprite.png", - 'css/screen.css', + "css/screen.css", ) - self.assertEqual(relative_path, '../images/sprite.png') + self.assertEqual(relative_path, "../images/sprite.png") def test_base_path(self): - base_path = self.compressor.base_path([ - _('js/templates/form.jst'), _('js/templates/field.jst') - ]) - self.assertEqual(base_path, _('js/templates')) + base_path = self.compressor.base_path( + [_("js/templates/form.jst"), _("js/templates/field.jst")] + ) + self.assertEqual(base_path, _("js/templates")) def test_absolute_path(self): absolute_path = self.compressor.absolute_path( - '../../images/sprite.png', 'css/plugins/') - self.assertEqual(absolute_path, 'images/sprite.png') + "../../images/sprite.png", "css/plugins/" + ) + self.assertEqual(absolute_path, "images/sprite.png") absolute_path = self.compressor.absolute_path( - '/images/sprite.png', 'css/plugins/') - self.assertEqual(absolute_path, '/images/sprite.png') + "/images/sprite.png", "css/plugins/" + ) + self.assertEqual(absolute_path, "/images/sprite.png") def test_template_name(self): + name = self.compressor.template_name("templates/photo/detail.jst", "templates/") + self.assertEqual(name, "photo_detail") + name = self.compressor.template_name("templates/photo_edit.jst", "") + self.assertEqual(name, "photo_edit") name = self.compressor.template_name( - 'templates/photo/detail.jst', 'templates/') - self.assertEqual(name, 'photo_detail') - name = self.compressor.template_name('templates/photo_edit.jst', '') - self.assertEqual(name, 'photo_edit') - name = self.compressor.template_name( - r'templates\photo\detail.jst', # noqa - 'templates\\', + r"templates\photo\detail.jst", # noqa + "templates\\", ) - self.assertEqual(name, 'photo_detail') + self.assertEqual(name, "photo_detail") - @pipeline_settings(TEMPLATE_SEPARATOR='/') + @pipeline_settings(TEMPLATE_SEPARATOR="/") def test_template_name_separator(self): + name = self.compressor.template_name("templates/photo/detail.jst", "templates/") + self.assertEqual(name, "photo/detail") + name = self.compressor.template_name("templates/photo_edit.jst", "") + self.assertEqual(name, "photo_edit") name = self.compressor.template_name( - 'templates/photo/detail.jst', 'templates/') - self.assertEqual(name, 'photo/detail') - name = self.compressor.template_name('templates/photo_edit.jst', '') - self.assertEqual(name, 'photo_edit') - name = self.compressor.template_name( - r'templates\photo\detail.jst', # noqa - 'templates\\', + r"templates\photo\detail.jst", # noqa + "templates\\", ) - self.assertEqual(name, 'photo/detail') + self.assertEqual(name, "photo/detail") def test_compile_templates(self): templates = self.compressor.compile_templates( - [_('pipeline/templates/photo/list.jst')] + [_("pipeline/templates/photo/list.jst")] ) self.assertEqual( templates, - """window.JST = window.JST || {};\n%s\nwindow.JST[\'list\'] = template(\'
\\n \\n
\\n <%%= caption %%>\\n
\\n
\');\n""" % TEMPLATE_FUNC, # noqa + """window.JST = window.JST || {};\n%s\nwindow.JST[\'list\'] = template(\'
\\n \\n
\\n <%%= caption %%>\\n
\\n
\');\n""" + % TEMPLATE_FUNC, # noqa + ) + templates = self.compressor.compile_templates( + [ + _("pipeline/templates/video/detail.jst"), + _("pipeline/templates/photo/detail.jst"), + ] ) - templates = self.compressor.compile_templates([ - _('pipeline/templates/video/detail.jst'), - _('pipeline/templates/photo/detail.jst') - ]) self.assertEqual( templates, - """window.JST = window.JST || {};\n%s\nwindow.JST[\'video_detail\'] = template(\'
\\n
\');\nwindow.JST[\'photo_detail\'] = template(\'
\\n \\n
\\n <%%= caption %%> by <%%= author %%>\\n
\\n
\');\n""" % TEMPLATE_FUNC, # noqa + """window.JST = window.JST || {};\n%s\nwindow.JST[\'video_detail\'] = template(\'
\\n
\');\nwindow.JST[\'photo_detail\'] = template(\'
\\n \\n
\\n <%%= caption %%> by <%%= author %%>\\n
\\n
\');\n""" + % TEMPLATE_FUNC, # noqa ) def test_embeddable(self): - self.assertFalse(self.compressor.embeddable( - _('pipeline/images/sprite.png'), None)) - self.assertFalse(self.compressor.embeddable( - _('pipeline/images/arrow.png'), 'datauri')) - self.assertTrue(self.compressor.embeddable( - _('pipeline/images/embed/arrow.png'), 'datauri')) - self.assertFalse(self.compressor.embeddable( - _('pipeline/images/arrow.dat'), 'datauri')) + self.assertFalse( + self.compressor.embeddable(_("pipeline/images/sprite.png"), None) + ) + self.assertFalse( + self.compressor.embeddable(_("pipeline/images/arrow.png"), "datauri") + ) + self.assertTrue( + self.compressor.embeddable(_("pipeline/images/embed/arrow.png"), "datauri") + ) + self.assertFalse( + self.compressor.embeddable(_("pipeline/images/arrow.dat"), "datauri") + ) def test_construct_asset_path(self): asset_path = self.compressor.construct_asset_path( - "../../images/sprite.png", "css/plugins/gallery.css", "css/gallery.css") + "../../images/sprite.png", "css/plugins/gallery.css", "css/gallery.css" + ) self.assertEqual(asset_path, "../images/sprite.png") asset_path = self.compressor.construct_asset_path( - "/images/sprite.png", "css/plugins/gallery.css", "css/gallery.css") + "/images/sprite.png", "css/plugins/gallery.css", "css/gallery.css" + ) self.assertEqual(asset_path, "/images/sprite.png") def test_url_rewrite(self): - output = self.compressor.concatenate_and_rewrite([ - _('pipeline/css/urls.css'), - ], 'css/screen.css') - self.assertEqual(""".embedded-url-svg { + output = self.compressor.concatenate_and_rewrite( + [ + _("pipeline/css/urls.css"), + ], + "css/screen.css", + ) + self.assertEqual( + """.embedded-url-svg { background-image: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 8h24M4 16h24M4 24h24'/%3E% 3C/svg%3E"); } @font-face { @@ -183,42 +198,52 @@ def test_url_rewrite(self): background-image: url(#image-gradient); } @font-face{src:url(../pipeline/fonts/pipeline.eot);src:url(../pipeline/fonts/pipeline.eot?#iefix) format('embedded-opentype'),url(../pipeline/fonts/pipeline.woff) format('woff'),url(../pipeline/fonts/pipeline.ttf) format('truetype');} -""", output) # noqa +""", + output, + ) # noqa def test_url_rewrite_data_uri(self): - output = self.compressor.concatenate_and_rewrite([ - _('pipeline/css/nested/nested.css'), - ], 'pipeline/screen.css') - self.assertEqual(""".data-url { + output = self.compressor.concatenate_and_rewrite( + [ + _("pipeline/css/nested/nested.css"), + ], + "pipeline/screen.css", + ) + self.assertEqual( + """.data-url { background-image: url(data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2212px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2012%2014%22%20style%3D%22enable-background%3Anew%200%200%2012%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M11%2C6V5c0-2.762-2.239-5-5-5S1%2C2.238%2C1%2C5v1H0v8h12V6H11z%20M6.5%2C9.847V12h-1V9.847C5.207%2C9.673%2C5%2C9.366%2C5%2C9%20c0-0.553%2C0.448-1%2C1-1s1%2C0.447%2C1%2C1C7%2C9.366%2C6.793%2C9.673%2C6.5%2C9.847z%20M9%2C6H3V5c0-1.657%2C1.343-3%2C3-3s3%2C1.343%2C3%2C3V6z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E); } .data-url-quoted { background-image: url('data:image/svg+xml;charset=US-ASCII,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%3Csvg%20version%3D%221.1%22%20id%3D%22Layer_1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%20%20width%3D%2212px%22%20height%3D%2214px%22%20viewBox%3D%220%200%2012%2014%22%20style%3D%22enable-background%3Anew%200%200%2012%2014%3B%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20d%3D%22M11%2C6V5c0-2.762-2.239-5-5-5S1%2C2.238%2C1%2C5v1H0v8h12V6H11z%20M6.5%2C9.847V12h-1V9.847C5.207%2C9.673%2C5%2C9.366%2C5%2C9%20c0-0.553%2C0.448-1%2C1-1s1%2C0.447%2C1%2C1C7%2C9.366%2C6.793%2C9.673%2C6.5%2C9.847z%20M9%2C6H3V5c0-1.657%2C1.343-3%2C3-3s3%2C1.343%2C3%2C3V6z%22%2F%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3Cg%3E%3C%2Fg%3E%3C%2Fsvg%3E'); } -""", output) # noqa +""", + output, + ) # noqa @skipIf(sys.platform.startswith("win"), "requires posix platform") def test_compressor_subprocess_unicode(self): path = os.path.dirname(os.path.dirname(__file__)) - content = open(path + '/assets/css/unicode.css', encoding="utf-8").read() - output = SubProcessCompressor(False).execute_command(('cat',), content) - self.assertEqual(""".some_class { + content = open(path + "/assets/css/unicode.css", encoding="utf-8").read() + output = SubProcessCompressor(False).execute_command(("cat",), content) + self.assertEqual( + """.some_class { // Some unicode content: "áéíóú"; } -""", output) +""", + output, + ) def tearDown(self): default_collector.clear() class CompressorImplementationTest(TestCase): - maxDiff = None def setUp(self): self.compressor = Compressor() - default_collector.collect(RequestFactory().get('/')) + default_collector.collect(RequestFactory().get("/")) def tearDown(self): default_collector.clear() @@ -228,104 +253,106 @@ def _test_compressor(self, compressor_cls, compress_type, expected_file): ("%s_COMPRESSOR" % compress_type.upper()): compressor_cls, } with pipeline_settings(**override_settings): - if compress_type == 'js': + if compress_type == "js": result = self.compressor.compress_js( - [_('pipeline/js/first.js'), _('pipeline/js/second.js')]) + [_("pipeline/js/first.js"), _("pipeline/js/second.js")] + ) else: result = self.compressor.compress_css( - [_('pipeline/css/first.css'), _('pipeline/css/second.css')], - os.path.join('pipeline', 'css', os.path.basename(expected_file))) - with self.compressor.storage.open(expected_file, 'r') as f: + [_("pipeline/css/first.css"), _("pipeline/css/second.css")], + os.path.join("pipeline", "css", os.path.basename(expected_file)), + ) + with self.compressor.storage.open(expected_file, "r") as f: expected = f.read() self.assertEqual(result, expected) def test_jsmin(self): self._test_compressor( - 'pipeline.compressors.jsmin.JSMinCompressor', - 'js', - 'pipeline/compressors/jsmin.js', + "pipeline.compressors.jsmin.JSMinCompressor", + "js", + "pipeline/compressors/jsmin.js", ) def test_csshtmljsminify(self): self._test_compressor( - 'pipeline.compressors.csshtmljsminify.CssHtmlJsMinifyCompressor', - 'css', - 'pipeline/compressors/csshtmljsminify.css', + "pipeline.compressors.csshtmljsminify.CssHtmlJsMinifyCompressor", + "css", + "pipeline/compressors/csshtmljsminify.css", ) self._test_compressor( - 'pipeline.compressors.csshtmljsminify.CssHtmlJsMinifyCompressor', - 'js', - 'pipeline/compressors/csshtmljsminify.js', + "pipeline.compressors.csshtmljsminify.CssHtmlJsMinifyCompressor", + "js", + "pipeline/compressors/csshtmljsminify.js", ) @skipUnless(settings.HAS_NODE, "requires node") def test_uglifyjs(self): self._test_compressor( - 'pipeline.compressors.uglifyjs.UglifyJSCompressor', - 'js', - 'pipeline/compressors/uglifyjs.js', + "pipeline.compressors.uglifyjs.UglifyJSCompressor", + "js", + "pipeline/compressors/uglifyjs.js", ) @skipUnless(settings.HAS_NODE, "requires node") def test_terser(self): self._test_compressor( - 'pipeline.compressors.terser.TerserCompressor', - 'js', - 'pipeline/compressors/terser.js', + "pipeline.compressors.terser.TerserCompressor", + "js", + "pipeline/compressors/terser.js", ) @skipUnless(settings.HAS_NODE, "requires node") def test_yuglify(self): self._test_compressor( - 'pipeline.compressors.yuglify.YuglifyCompressor', - 'css', - 'pipeline/compressors/yuglify.css', + "pipeline.compressors.yuglify.YuglifyCompressor", + "css", + "pipeline/compressors/yuglify.css", ) self._test_compressor( - 'pipeline.compressors.yuglify.YuglifyCompressor', - 'js', - 'pipeline/compressors/yuglify.js', + "pipeline.compressors.yuglify.YuglifyCompressor", + "js", + "pipeline/compressors/yuglify.js", ) @skipUnless(settings.HAS_NODE, "requires node") def test_cssmin(self): self._test_compressor( - 'pipeline.compressors.cssmin.CSSMinCompressor', - 'css', - 'pipeline/compressors/cssmin.css', + "pipeline.compressors.cssmin.CSSMinCompressor", + "css", + "pipeline/compressors/cssmin.css", ) @skipUnless(settings.HAS_NODE, "requires node") @skipUnless(settings.HAS_JAVA, "requires java") def test_closure(self): self._test_compressor( - 'pipeline.compressors.closure.ClosureCompressor', - 'js', - 'pipeline/compressors/closure.js', + "pipeline.compressors.closure.ClosureCompressor", + "js", + "pipeline/compressors/closure.js", ) @skipUnless(settings.HAS_NODE, "requires node") @skipUnless(settings.HAS_JAVA, "requires java") def test_yui_js(self): self._test_compressor( - 'pipeline.compressors.yui.YUICompressor', - 'js', - 'pipeline/compressors/yui.js', + "pipeline.compressors.yui.YUICompressor", + "js", + "pipeline/compressors/yui.js", ) @skipUnless(settings.HAS_NODE, "requires node") @skipUnless(settings.HAS_JAVA, "requires java") def test_yui_css(self): self._test_compressor( - 'pipeline.compressors.yui.YUICompressor', - 'css', - 'pipeline/compressors/yui.css', + "pipeline.compressors.yui.YUICompressor", + "css", + "pipeline/compressors/yui.css", ) @skipUnless(settings.HAS_CSSTIDY, "requires csstidy") def test_csstidy(self): self._test_compressor( - 'pipeline.compressors.csstidy.CSSTidyCompressor', - 'css', - 'pipeline/compressors/csstidy.css', + "pipeline.compressors.csstidy.CSSTidyCompressor", + "css", + "pipeline/compressors/csstidy.css", ) diff --git a/tests/tests/test_conf.py b/tests/tests/test_conf.py index f084ceb0..d427430c 100644 --- a/tests/tests/test_conf.py +++ b/tests/tests/test_conf.py @@ -9,30 +9,30 @@ class TestSettings(TestCase): def test_3unicode(self): s = PipelineSettings({"FOO_BINARY": "env actualprogram"}) - self.assertEqual(s.FOO_BINARY, ('env', 'actualprogram')) + self.assertEqual(s.FOO_BINARY, ("env", "actualprogram")) def test_2unicode(self): s = PipelineSettings({"FOO_BINARY": "env actualprogram"}) - self.assertEqual(s.FOO_BINARY, ('env', 'actualprogram')) + self.assertEqual(s.FOO_BINARY, ("env", "actualprogram")) def test_2bytes(self): s = PipelineSettings({"FOO_BINARY": "env actualprogram"}) - self.assertEqual(s.FOO_BINARY, ('env', 'actualprogram')) + self.assertEqual(s.FOO_BINARY, ("env", "actualprogram")) def test_expected_splitting(self): s = PipelineSettings({"FOO_BINARY": "env actualprogram"}) - self.assertEqual(s.FOO_BINARY, ('env', 'actualprogram')) + self.assertEqual(s.FOO_BINARY, ("env", "actualprogram")) @skipIf(sys.platform.startswith("win"), "requires posix platform") def test_expected_preservation(self): s = PipelineSettings({"FOO_BINARY": r"actual\ program"}) - self.assertEqual(s.FOO_BINARY, ('actual program',)) + self.assertEqual(s.FOO_BINARY, ("actual program",)) @skipUnless(sys.platform.startswith("win"), "requires windows") def test_win_path_preservation(self): s = PipelineSettings({"FOO_BINARY": "C:\\Test\\ActualProgram.exe argument"}) - self.assertEqual(s.FOO_BINARY, ('C:\\Test\\ActualProgram.exe', 'argument')) + self.assertEqual(s.FOO_BINARY, ("C:\\Test\\ActualProgram.exe", "argument")) def test_tuples_are_normal(self): s = PipelineSettings({"FOO_ARGUMENTS": ("explicit", "with", "args")}) - self.assertEqual(s.FOO_ARGUMENTS, ('explicit', 'with', 'args')) + self.assertEqual(s.FOO_ARGUMENTS, ("explicit", "with", "args")) diff --git a/tests/tests/test_forms.py b/tests/tests/test_forms.py index 9a290e5b..2343347f 100644 --- a/tests/tests/test_forms.py +++ b/tests/tests/test_forms.py @@ -10,147 +10,139 @@ @pipeline_settings( PIPELINE_COLLECTOR_ENABLED=False, STYLESHEETS={ - 'styles1': { - 'source_filenames': ( - 'pipeline/css/first.css', - 'pipeline/css/second.css', + "styles1": { + "source_filenames": ( + "pipeline/css/first.css", + "pipeline/css/second.css", ), - 'output_filename': 'styles1.min.css', + "output_filename": "styles1.min.css", }, - 'styles2': { - 'source_filenames': ( - 'pipeline/css/unicode.css', - ), - 'output_filename': 'styles2.min.css', + "styles2": { + "source_filenames": ("pipeline/css/unicode.css",), + "output_filename": "styles2.min.css", }, - 'print': { - 'source_filenames': ( - 'pipeline/css/urls.css', - ), - 'output_filename': 'print.min.css', + "print": { + "source_filenames": ("pipeline/css/urls.css",), + "output_filename": "print.min.css", }, }, JAVASCRIPT={ - 'scripts1': { - 'source_filenames': ( - 'pipeline/js/first.js', - 'pipeline/js/second.js', + "scripts1": { + "source_filenames": ( + "pipeline/js/first.js", + "pipeline/js/second.js", ), - 'output_filename': 'scripts1.min.js', + "output_filename": "scripts1.min.js", }, - 'scripts2': { - 'source_filenames': ( - 'pipeline/js/application.js', - ), - 'output_filename': 'scripts2.min.js', + "scripts2": { + "source_filenames": ("pipeline/js/application.js",), + "output_filename": "scripts2.min.js", }, - }) + }, +) class PipelineFormMediaTests(TestCase): """Unit tests for pipeline.forms.PipelineFormMedia.""" @pipeline_settings(PIPELINE_ENABLED=True) def test_css_packages_with_pipeline_enabled(self): """Testing PipelineFormMedia.css_packages with PIPELINE_ENABLED=True""" + class MyMedia(PipelineFormMedia): css_packages = { - 'all': ('styles1', 'styles2'), - 'print': ('print',), + "all": ("styles1", "styles2"), + "print": ("print",), } - css = { - 'all': ('extra1.css', 'extra2.css') - } + css = {"all": ("extra1.css", "extra2.css")} media = Media(MyMedia) self.assertEqual( MyMedia.css, { - 'all': [ - 'extra1.css', - 'extra2.css', - '/static/styles1.min.css', - '/static/styles2.min.css', + "all": [ + "extra1.css", + "extra2.css", + "/static/styles1.min.css", + "/static/styles2.min.css", ], - 'print': ['/static/print.min.css'], - }) + "print": ["/static/print.min.css"], + }, + ) self.assertEqual(MyMedia.css, media._css) expected_regex = [ r'' % path for path in ( - '/static/extra1.css', - '/static/extra2.css', - '/static/styles1.min.css', - '/static/styles2.min.css', + "/static/extra1.css", + "/static/extra2.css", + "/static/styles1.min.css", + "/static/styles2.min.css", ) ] + [ r'' ] - for rendered_node, expected_node in zip( - media.render_css(), expected_regex - ): + for rendered_node, expected_node in zip(media.render_css(), expected_regex): self.assertRegex(rendered_node, expected_node) @pipeline_settings(PIPELINE_ENABLED=False) def test_css_packages_with_pipeline_disabled(self): """Testing PipelineFormMedia.css_packages with PIPELINE_ENABLED=False""" + class MyMedia(PipelineFormMedia): css_packages = { - 'all': ('styles1', 'styles2'), - 'print': ('print',), + "all": ("styles1", "styles2"), + "print": ("print",), } - css = { - 'all': ('extra1.css', 'extra2.css') - } + css = {"all": ("extra1.css", "extra2.css")} media = Media(MyMedia) self.assertEqual( MyMedia.css, { - 'all': [ - 'extra1.css', - 'extra2.css', - 'pipeline/css/first.css', - 'pipeline/css/second.css', - 'pipeline/css/unicode.css', + "all": [ + "extra1.css", + "extra2.css", + "pipeline/css/first.css", + "pipeline/css/second.css", + "pipeline/css/unicode.css", ], - 'print': ['pipeline/css/urls.css'], - }) + "print": ["pipeline/css/urls.css"], + }, + ) self.assertEqual(MyMedia.css, media._css) expected_regex = [ '' % path for path in ( - '/static/extra1.css', - '/static/extra2.css', - '/static/pipeline/css/first.css', - '/static/pipeline/css/second.css', - '/static/pipeline/css/unicode.css', + "/static/extra1.css", + "/static/extra2.css", + "/static/pipeline/css/first.css", + "/static/pipeline/css/second.css", + "/static/pipeline/css/unicode.css", ) ] + [ '' ] - for rendered_node, expected_node in zip( - media.render_css(), expected_regex - ): + for rendered_node, expected_node in zip(media.render_css(), expected_regex): self.assertRegex(rendered_node, expected_node) @pipeline_settings(PIPELINE_ENABLED=True) def test_js_packages_with_pipeline_enabled(self): """Testing PipelineFormMedia.js_packages with PIPELINE_ENABLED=True""" + class MyMedia(PipelineFormMedia): - js_packages = ('scripts1', 'scripts2') - js = ('extra1.js', 'extra2.js') + js_packages = ("scripts1", "scripts2") + js = ("extra1.js", "extra2.js") media = Media(MyMedia) - if django_version() < '3.1': + if django_version() < "3.1": script_tag = '' else: script_tag = '' @@ -158,34 +150,37 @@ class MyMedia(PipelineFormMedia): self.assertEqual( MyMedia.js, [ - 'extra1.js', - 'extra2.js', - '/static/scripts1.min.js', - '/static/scripts2.min.js', - ]) + "extra1.js", + "extra2.js", + "/static/scripts1.min.js", + "/static/scripts2.min.js", + ], + ) self.assertEqual(MyMedia.js, media._js) self.assertEqual( media.render_js(), [ script_tag % path for path in ( - '/static/extra1.js', - '/static/extra2.js', - '/static/scripts1.min.js', - '/static/scripts2.min.js', + "/static/extra1.js", + "/static/extra2.js", + "/static/scripts1.min.js", + "/static/scripts2.min.js", ) - ]) + ], + ) @pipeline_settings(PIPELINE_ENABLED=False) def test_js_packages_with_pipeline_disabled(self): """Testing PipelineFormMedia.js_packages with PIPELINE_ENABLED=False""" + class MyMedia(PipelineFormMedia): - js_packages = ('scripts1', 'scripts2') - js = ('extra1.js', 'extra2.js') + js_packages = ("scripts1", "scripts2") + js = ("extra1.js", "extra2.js") media = Media(MyMedia) - if django_version() < '3.1': + if django_version() < "3.1": script_tag = '' else: script_tag = '' @@ -193,22 +188,24 @@ class MyMedia(PipelineFormMedia): self.assertEqual( MyMedia.js, [ - 'extra1.js', - 'extra2.js', - 'pipeline/js/first.js', - 'pipeline/js/second.js', - 'pipeline/js/application.js', - ]) + "extra1.js", + "extra2.js", + "pipeline/js/first.js", + "pipeline/js/second.js", + "pipeline/js/application.js", + ], + ) self.assertEqual(MyMedia.js, media._js) self.assertEqual( media.render_js(), [ script_tag % path for path in ( - '/static/extra1.js', - '/static/extra2.js', - '/static/pipeline/js/first.js', - '/static/pipeline/js/second.js', - '/static/pipeline/js/application.js', + "/static/extra1.js", + "/static/extra2.js", + "/static/pipeline/js/first.js", + "/static/pipeline/js/second.js", + "/static/pipeline/js/application.js", ) - ]) + ], + ) diff --git a/tests/tests/test_glob.py b/tests/tests/test_glob.py index bd484842..8283ffd2 100644 --- a/tests/tests/test_glob.py +++ b/tests/tests/test_glob.py @@ -28,15 +28,15 @@ def assertSequenceEqual(self, l1, l2): self.assertEqual(set(l1), set(l2)) def setUp(self): - self.storage = FileSystemStorage(local_path('glob_dir')) + self.storage = FileSystemStorage(local_path("glob_dir")) self.old_storage = glob.staticfiles_storage glob.staticfiles_storage = self.storage - self.mktemp('a', 'D') - self.mktemp('aab', 'F') - self.mktemp('aaa', 'zzzF') - self.mktemp('ZZZ') - self.mktemp('a', 'bcd', 'EF') - self.mktemp('a', 'bcd', 'efg', 'ha') + self.mktemp("a", "D") + self.mktemp("aab", "F") + self.mktemp("aaa", "zzzF") + self.mktemp("ZZZ") + self.mktemp("a", "bcd", "EF") + self.mktemp("a", "bcd", "efg", "ha") def glob(self, *parts): if len(parts) == 1: @@ -50,50 +50,51 @@ def tearDown(self): glob.staticfiles_storage = self.old_storage def test_glob_literal(self): - self.assertSequenceEqual(self.glob('a'), [self.normpath('a')]) - self.assertSequenceEqual(self.glob('a', 'D'), [self.normpath('a', 'D')]) - self.assertSequenceEqual(self.glob('aab'), [self.normpath('aab')]) + self.assertSequenceEqual(self.glob("a"), [self.normpath("a")]) + self.assertSequenceEqual(self.glob("a", "D"), [self.normpath("a", "D")]) + self.assertSequenceEqual(self.glob("aab"), [self.normpath("aab")]) def test_glob_one_directory(self): self.assertSequenceEqual( - self.glob('a*'), map(self.normpath, ['a', 'aab', 'aaa'])) + self.glob("a*"), map(self.normpath, ["a", "aab", "aaa"]) + ) + self.assertSequenceEqual(self.glob("*a"), map(self.normpath, ["a", "aaa"])) + self.assertSequenceEqual(self.glob("aa?"), map(self.normpath, ["aaa", "aab"])) self.assertSequenceEqual( - self.glob('*a'), map(self.normpath, ['a', 'aaa'])) - self.assertSequenceEqual( - self.glob('aa?'), map(self.normpath, ['aaa', 'aab'])) - self.assertSequenceEqual( - self.glob('aa[ab]'), map(self.normpath, ['aaa', 'aab'])) - self.assertSequenceEqual(self.glob('*q'), []) + self.glob("aa[ab]"), map(self.normpath, ["aaa", "aab"]) + ) + self.assertSequenceEqual(self.glob("*q"), []) def test_glob_nested_directory(self): if os.path.normcase("abCD") == "abCD": # case-sensitive filesystem self.assertSequenceEqual( - self.glob('a', 'bcd', 'E*'), [self.normpath('a', 'bcd', 'EF')]) + self.glob("a", "bcd", "E*"), [self.normpath("a", "bcd", "EF")] + ) else: # case insensitive filesystem - self.assertSequenceEqual(self.glob('a', 'bcd', 'E*'), [ - self.normpath('a', 'bcd', 'EF'), - self.normpath('a', 'bcd', 'efg') - ]) + self.assertSequenceEqual( + self.glob("a", "bcd", "E*"), + [self.normpath("a", "bcd", "EF"), self.normpath("a", "bcd", "efg")], + ) self.assertSequenceEqual( - self.glob('a', 'bcd', '*g'), [self.normpath('a', 'bcd', 'efg')]) + self.glob("a", "bcd", "*g"), [self.normpath("a", "bcd", "efg")] + ) def test_glob_directory_names(self): + self.assertSequenceEqual(self.glob("*", "D"), [self.normpath("a", "D")]) + self.assertSequenceEqual(self.glob("*", "*a"), []) self.assertSequenceEqual( - self.glob('*', 'D'), [self.normpath('a', 'D')]) - self.assertSequenceEqual(self.glob('*', '*a'), []) - self.assertSequenceEqual( - self.glob('a', '*', '*', '*a'), - [self.normpath('a', 'bcd', 'efg', 'ha')]) + self.glob("a", "*", "*", "*a"), [self.normpath("a", "bcd", "efg", "ha")] + ) self.assertSequenceEqual( - self.glob('?a?', '*F'), - map(self.normpath, [os.path.join('aaa', 'zzzF'), - os.path.join('aab', 'F')])) + self.glob("?a?", "*F"), + map(self.normpath, [os.path.join("aaa", "zzzF"), os.path.join("aab", "F")]), + ) def test_glob_directory_with_trailing_slash(self): # We are verifying that when there is wildcard pattern which # ends with os.sep doesn't blow up. - paths = glob.glob('*' + os.sep) + paths = glob.glob("*" + os.sep) self.assertEqual(len(paths), 4) self.assertTrue(all(os.sep in path for path in paths)) diff --git a/tests/tests/test_middleware.py b/tests/tests/test_middleware.py index ab288779..f4142325 100644 --- a/tests/tests/test_middleware.py +++ b/tests/tests/test_middleware.py @@ -12,13 +12,13 @@ def dummy_get_response(request): class MiddlewareTest(TestCase): - whitespace = b' ' + whitespace = b" " def setUp(self): self.req = HttpRequest() self.req.META = { - 'SERVER_NAME': 'testserver', - 'SERVER_PORT': 80, + "SERVER_NAME": "testserver", + "SERVER_PORT": 80, } self.req.path = self.req.path_info = "/" self.resp = HttpResponse() @@ -26,21 +26,23 @@ def setUp(self): self.resp.content = self.whitespace def test_middleware_html(self): - self.resp['Content-Type'] = 'text/html; charset=UTF-8' + self.resp["Content-Type"] = "text/html; charset=UTF-8" response = MinifyHTMLMiddleware(dummy_get_response).process_response( - self.req, self.resp) - self.assertIn('text/html', response['Content-Type']) + self.req, self.resp + ) + self.assertIn("text/html", response["Content-Type"]) self.assertNotIn(self.whitespace, response.content) def test_middleware_text(self): - self.resp['Content-Type'] = 'text/plain; charset=UTF-8' + self.resp["Content-Type"] = "text/plain; charset=UTF-8" response = MinifyHTMLMiddleware(dummy_get_response).process_response( - self.req, self.resp) - self.assertIn('text/plain', response['Content-Type']) + self.req, self.resp + ) + self.assertIn("text/plain", response["Content-Type"]) self.assertIn(self.whitespace, response.content) - @patch('pipeline.middleware.settings.PIPELINE_ENABLED', False) + @patch("pipeline.middleware.settings.PIPELINE_ENABLED", False) def test_middleware_not_used(self): self.assertRaises(MiddlewareNotUsed, MinifyHTMLMiddleware, dummy_get_response) diff --git a/tests/tests/test_packager.py b/tests/tests/test_packager.py index f451a945..b665d239 100644 --- a/tests/tests/test_packager.py +++ b/tests/tests/test_packager.py @@ -11,37 +11,37 @@ def setUp(self): def test_package_for(self): packager = Packager() - packager.packages['js'] = packager.create_packages({ - 'application': { - 'source_filenames': ( - _('pipeline/js/application.js'), - ), - 'output_filename': 'application.js' + packager.packages["js"] = packager.create_packages( + { + "application": { + "source_filenames": (_("pipeline/js/application.js"),), + "output_filename": "application.js", + } } - }) + ) try: - packager.package_for('js', 'application') + packager.package_for("js", "application") except PackageNotFound: self.fail() try: - packager.package_for('js', 'broken') + packager.package_for("js", "broken") self.fail() except PackageNotFound: pass def test_templates(self): packager = Packager() - packages = packager.create_packages({ - 'templates': { - 'source_filenames': ( - _('pipeline/templates/photo/list.jst'), - ), - 'output_filename': 'templates.js', + packages = packager.create_packages( + { + "templates": { + "source_filenames": (_("pipeline/templates/photo/list.jst"),), + "output_filename": "templates.js", + } } - }) + ) self.assertEqual( - packages['templates'].templates, - [_('pipeline/templates/photo/list.jst')], + packages["templates"].templates, + [_("pipeline/templates/photo/list.jst")], ) def tearDown(self): diff --git a/tests/tests/test_storage.py b/tests/tests/test_storage.py index 1c1a1165..e0b2bf1e 100644 --- a/tests/tests/test_storage.py +++ b/tests/tests/test_storage.py @@ -14,6 +14,7 @@ class PipelineNoPathStorage(PipelineStorage): """Storage without an implemented path method""" + def path(self, *args): raise NotImplementedError() @@ -34,11 +35,12 @@ def listdir(self, *args): class DummyCSSCompiler(DummyCompiler): - """ Handles css files """ - output_extension = 'css' + """Handles css files""" + + output_extension = "css" def match_file(self, path): - return path.endswith('.css') + return path.endswith(".css") class StorageTest(TestCase): @@ -54,22 +56,22 @@ def test_post_process_dry_run(self): @pipeline_settings( JS_COMPRESSOR=None, CSS_COMPRESSOR=None, - COMPILERS=['tests.tests.test_storage.DummyCSSCompiler'], + COMPILERS=["tests.tests.test_storage.DummyCSSCompiler"], ) def test_post_process(self): default_collector.collect() storage = PipelineStorage() processed_files = storage.post_process({}) - self.assertTrue(('screen.css', 'screen.css', True) in processed_files) - self.assertTrue(('scripts.js', 'scripts.js', True) in processed_files) + self.assertTrue(("screen.css", "screen.css", True) in processed_files) + self.assertTrue(("scripts.js", "scripts.js", True) in processed_files) @override_settings( - STATICFILES_STORAGE='tests.tests.test_storage.PipelineNoPathStorage', + STATICFILES_STORAGE="tests.tests.test_storage.PipelineNoPathStorage", ) @pipeline_settings( JS_COMPRESSOR=None, CSS_COMPRESSOR=None, - COMPILERS=['tests.tests.test_storage.DummyCSSCompiler'], + COMPILERS=["tests.tests.test_storage.DummyCSSCompiler"], ) def test_post_process_no_path(self): """ @@ -77,34 +79,30 @@ def test_post_process_no_path(self): """ staticfiles_storage._setup() try: - call_command('collectstatic', verbosity=0, interactive=False) + call_command("collectstatic", verbosity=0, interactive=False) except NotImplementedError: - self.fail('Received an error running collectstatic') + self.fail("Received an error running collectstatic") - @modify_settings(STATICFILES_FINDERS={ - 'append': 'pipeline.finders.PipelineFinder' - }) + @modify_settings(STATICFILES_FINDERS={"append": "pipeline.finders.PipelineFinder"}) def test_nonexistent_file_pipeline_finder(self): - path = finders.find('nothing.css') + path = finders.find("nothing.css") self.assertIsNone(path) - @modify_settings(STATICFILES_FINDERS={ - 'append': 'pipeline.finders.CachedFileFinder' - }) + @modify_settings( + STATICFILES_FINDERS={"append": "pipeline.finders.CachedFileFinder"} + ) def test_nonexistent_file_cached_finder(self): - path = finders.find('nothing.css') + path = finders.find("nothing.css") self.assertIsNone(path) - @modify_settings(STATICFILES_FINDERS={ - 'append': 'pipeline.finders.PipelineFinder' - }) + @modify_settings(STATICFILES_FINDERS={"append": "pipeline.finders.PipelineFinder"}) def test_nonexistent_double_extension_file_pipeline_finder(self): - path = finders.find('app.css.map') + path = finders.find("app.css.map") self.assertIsNone(path) - @modify_settings(STATICFILES_FINDERS={ - 'append': 'pipeline.finders.CachedFileFinder' - }) + @modify_settings( + STATICFILES_FINDERS={"append": "pipeline.finders.CachedFileFinder"} + ) def test_nonexistent_double_extension_file_cached_finder(self): - path = finders.find('app.css.map') + path = finders.find("app.css.map") self.assertIsNone(path) diff --git a/tests/tests/test_template.py b/tests/tests/test_template.py index c5bf962c..f05347b5 100644 --- a/tests/tests/test_template.py +++ b/tests/tests/test_template.py @@ -8,14 +8,16 @@ class JinjaTest(TestCase): def setUp(self): - self.env = Environment(extensions=[PipelineExtension], - loader=PackageLoader('pipeline', 'templates')) + self.env = Environment( + extensions=[PipelineExtension], + loader=PackageLoader("pipeline", "templates"), + ) def test_no_package(self): template = self.env.from_string("""{% stylesheet "unknow" %}""") - self.assertEqual('', template.render()) + self.assertEqual("", template.render()) template = self.env.from_string("""{% javascript "unknow" %}""") - self.assertEqual('', template.render()) + self.assertEqual("", template.render()) def test_package_css(self): template = self.env.from_string("""{% stylesheet "screen" %}""") @@ -27,35 +29,38 @@ def test_package_css(self): @pipeline_settings(PIPELINE_ENABLED=False) def test_package_css_disabled(self): template = self.env.from_string("""{% stylesheet "screen" %}""") - self.assertEqual(''' + self.assertEqual( + """ -''', template.render()) # noqa +""", + template.render(), + ) # noqa def test_package_js(self): template = self.env.from_string("""{% javascript "scripts" %}""") self.assertEqual( - '', # noqa + '', # noqa template.render(), ) def test_package_js_async(self): template = self.env.from_string("""{% javascript "scripts_async" %}""") self.assertEqual( - '', # noqa + '', # noqa template.render(), ) def test_package_js_defer(self): template = self.env.from_string("""{% javascript "scripts_defer" %}""") self.assertEqual( - '', # noqa + '', # noqa template.render(), ) def test_package_js_async_defer(self): template = self.env.from_string("""{% javascript "scripts_async_defer" %}""") self.assertEqual( - '', # noqa + '', # noqa template.render(), ) @@ -68,14 +73,14 @@ def test_compressed_empty(self): rendered = self.render_template( """{% load pipeline %}{% stylesheet "unknow" %}""", ) - self.assertEqual('', rendered) + self.assertEqual("", rendered) def test_compressed_css(self): rendered = self.render_template( """{% load pipeline %}{% stylesheet "screen" %}""", ) self.assertEqual( - '', # noqa + '', # noqa rendered, ) @@ -84,7 +89,7 @@ def test_compressed_css_media(self): """{% load pipeline %}{% stylesheet "screen_media" %}""", ) self.assertEqual( - '', # noqa + '', # noqa rendered, ) @@ -93,7 +98,7 @@ def test_compressed_css_title(self): """{% load pipeline %}{% stylesheet "screen_title" %}""", ) self.assertEqual( - '', # noqa + '', # noqa rendered, ) @@ -102,7 +107,7 @@ def test_compressed_js(self): """{% load pipeline %}{% javascript "scripts" %}""", ) self.assertEqual( - '', # noqa + '', # noqa rendered, ) @@ -111,7 +116,7 @@ def test_compressed_js_async(self): """{% load pipeline %}{% javascript "scripts_async" %}""", ) self.assertEqual( - '', # noqa + '', # noqa rendered, ) @@ -120,7 +125,7 @@ def test_compressed_js_defer(self): """{% load pipeline %}{% javascript "scripts_defer" %}""", ) self.assertEqual( - '', # noqa + '', # noqa rendered, ) @@ -129,6 +134,6 @@ def test_compressed_js_async_defer(self): """{% load pipeline %}{% javascript "scripts_async_defer" %}""", ) self.assertEqual( - '', # noqa + '', # noqa rendered, ) diff --git a/tests/tests/test_utils.py b/tests/tests/test_utils.py index e12a8e76..c3815fb6 100644 --- a/tests/tests/test_utils.py +++ b/tests/tests/test_utils.py @@ -7,9 +7,9 @@ class UtilTest(TestCase): def test_guess_type(self): - self.assertEqual('text/css', guess_type('stylesheet.css')) - self.assertEqual('text/coffeescript', guess_type('application.coffee')) - self.assertEqual('text/less', guess_type('stylesheet.less')) + self.assertEqual("text/css", guess_type("stylesheet.css")) + self.assertEqual("text/coffeescript", guess_type("application.coffee")) + self.assertEqual("text/less", guess_type("stylesheet.less")) def test_mimetypes_are_str(self): for ext, mtype in mimetypes.types_map.items(): diff --git a/tests/tests/test_views.py b/tests/tests/test_views.py index 7bc99189..b05db53c 100644 --- a/tests/tests/test_views.py +++ b/tests/tests/test_views.py @@ -15,9 +15,9 @@ class ServeStaticViewsTest(TestCase): def setUp(self): super().setUp() - self.filename = 'pipeline/js/first.js' + self.filename = "pipeline/js/first.js" self.storage = staticfiles_storage - self.request = RequestFactory().get('/static/%s' % self.filename) + self.request = RequestFactory().get("/static/%s" % self.filename) default_collector.clear() @@ -31,7 +31,7 @@ def test_found(self): self._test_found() def test_not_found(self): - self._test_not_found('missing-file') + self._test_not_found("missing-file") @override_settings(DEBUG=False) def test_debug_false(self): @@ -62,9 +62,9 @@ def test_collector_disabled_and_found(self): def test_collector_disabled_and_not_found(self): self._test_not_found(self.filename) - def _write_content(self, content='abc123'): + def _write_content(self, content="abc123"): """Write sample content to the test static file.""" - with self.storage.open(self.filename, 'w') as f: + with self.storage.open(self.filename, "w") as f: f.write(content) def _test_found(self, **kwargs): @@ -73,8 +73,8 @@ def _test_found(self, **kwargs): self.assertEqual(response.status_code, 200) self.assertTrue(self.storage.exists(self.filename)) - if hasattr(response, 'streaming_content'): - content = b''.join(response.streaming_content) + if hasattr(response, "streaming_content"): + content = b"".join(response.streaming_content) else: content = response.content diff --git a/tests/urls.py b/tests/urls.py index b38d5031..2321afb0 100644 --- a/tests/urls.py +++ b/tests/urls.py @@ -3,7 +3,7 @@ from django.views.generic import TemplateView urlpatterns = [ - path('', TemplateView.as_view(template_name='index.html'), name='index'), - path('empty/', TemplateView.as_view(template_name='empty.html'), name='empty'), - path('admin/', admin.site.urls), + path("", TemplateView.as_view(template_name="index.html"), name="index"), + path("empty/", TemplateView.as_view(template_name="empty.html"), name="empty"), + path("admin/", admin.site.urls), ] diff --git a/tests/utils.py b/tests/utils.py index 5841a8aa..b5de2444 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -6,7 +6,7 @@ def _(path): # Make sure the path contains only the correct separator - return path.replace('/', os.sep).replace('\\', os.sep) + return path.replace("/", os.sep).replace("\\", os.sep) class pipeline_settings(override_settings): @@ -16,4 +16,4 @@ def __init__(self, **kwargs): # and its __init__ method calls its superclass' __init__ method too, # so we must do the same. super().__init__() - self.options = {'PIPELINE': kwargs} + self.options = {"PIPELINE": kwargs}