def test_output_moved(self): class Filter(ExternalTool): pass self.popen.return_value.returncode = 0 self.popen.return_value.communicate.return_value = ["stdout", "stderr"] # {output} creates an output # this test *moves* the file into the target location, and # tests the fix to issue #286 intercepted = {} def fake_output_file(argv, **kw): intercepted["filename"] = argv[0] with open(argv[0] + ".tmp", "w") as f: f.write("bat") import shutil shutil.move(argv[0] + ".tmp", argv[0]) return DEFAULT self.popen.side_effect = fake_output_file # We get the result we generated in the hook above out = StringIO() Filter.subprocess(["{output}"], out) assert out.getvalue() == "bat" # File has been deleted assert not os.path.exists(intercepted["filename"])
def test_output_moved(self): class Filter(ExternalTool): pass self.popen.return_value.returncode = 0 self.popen.return_value.communicate.return_value = ['stdout', 'stderr'] # {output} creates an output # this test *moves* the file into the target location, and # tests the fix to issue #286 intercepted = {} def fake_output_file(argv, **kw): intercepted['filename'] = argv[0] with open(argv[0] + '.tmp', 'w') as f: f.write('bat') import shutil shutil.move(argv[0] + '.tmp', argv[0]) return DEFAULT self.popen.side_effect = fake_output_file # We get the result we generated in the hook above out = StringIO() Filter.subprocess(['{output}'], out) assert out.getvalue() == 'bat' # File has been deleted assert not os.path.exists(intercepted['filename'])
def test_input_var(self): """Test {input} variable.""" class Filter(ExternalTool): pass self.popen.return_value.returncode = 0 self.popen.return_value.communicate.return_value = [ b'stdout', b'stderr' ] # {input} creates an input file intercepted = {} def check_input_file(argv, **kw): intercepted['filename'] = argv[0] with open(argv[0], 'r') as f: # File has been generated with input data assert f.read().decode('utf-8') == u'fooñ' return DEFAULT self.popen.side_effect = check_input_file Filter.subprocess(['{input}'], StringIO(), data=u'fooñ') # No stdin was passed self.popen.return_value.communicate.assert_called_with(None) # File has been deleted assert not os.path.exists(intercepted['filename']) # {input} requires input data assert_raises(ValueError, Filter.subprocess, ['{input}'], StringIO())
def test_method_output(self): """The method=output.""" class Filter(self.MockTool): method = 'output' assert getattr(Filter, 'input') is None assert getattr(Filter, 'open') is None Filter().output(StringIO('bla'), StringIO()) assert Filter.result == ([], 'bla')
def test_argv_variables(self): """In argv, a number of placeholders can be used. Ensure they work.""" class Filter(self.MockTool): argv = [ # The filter instance '{self.__class__.__name__}', # Keyword and positional args to filter method '{kwarg}', '{0.closed}', # Special placeholders that are passed through '{input}', '{output}'] Filter().output(StringIO('content'), StringIO(), kwarg='value') assert Filter.result == ( ["Filter", 'value', 'False', '{input}', '{output}'], 'content')
def test_method_open(self): """The method=open.""" class Filter(self.MockTool): method = 'open' assert getattr(Filter, 'output') is None assert getattr(Filter, 'input') is None Filter().open(StringIO(), 'filename') assert Filter.result == ([], None)
def test_subprocess(self): """Instead of the ``argv`` shortcut, subclasses can also use the ``subprocess`` helper manually. """ class Filter(ExternalTool): pass # Without stdin data self.popen.return_value.returncode = 0 self.popen.return_value.communicate.return_value = [b'stdout', b'stderr'] out = StringIO() Filter.subprocess(['test'], out) assert out.getvalue() == 'stdout' self.popen.return_value.communicate.assert_called_with(None) # With stdin data self.popen.reset_mock() self.popen.return_value.returncode = 0 self.popen.return_value.communicate.return_value = [b'stdout', b'stderr'] out = StringIO() Filter.subprocess(['test'], out, data='data') assert out.getvalue() == 'stdout' self.popen.return_value.communicate.assert_called_with(b'data') # With error self.popen.return_value.returncode = 1 self.popen.return_value.communicate.return_value = [b'stdout', b'stderr'] assert_raises(FilterError, Filter.subprocess, ['test'], StringIO())
def test_output_var(self): class Filter(ExternalTool): pass self.popen.return_value.returncode = 0 self.popen.return_value.communicate.return_value = ['stdout', 'stderr'] # {input} creates an input file intercepted = {} def fake_output_file(argv, **kw): intercepted['filename'] = argv[0] with open(argv[0], 'w') as f: f.write('bat') return DEFAULT self.popen.side_effect = fake_output_file # We get the result we generated in the hook above out = StringIO() Filter.subprocess(['{output}'], out) assert out.getvalue() == 'bat' # File has been deleted assert not os.path.exists(intercepted['filename'])
def test_output_var(self): class Filter(ExternalTool): pass self.popen.return_value.returncode = 0 self.popen.return_value.communicate.return_value = ["stdout", "stderr"] # {output} creates an output file intercepted = {} def fake_output_file(argv, **kw): intercepted["filename"] = argv[0] with open(argv[0], "w") as f: f.write("bat") return DEFAULT self.popen.side_effect = fake_output_file # We get the result we generated in the hook above out = StringIO() Filter.subprocess(["{output}"], out) assert out.getvalue() == "bat" # File has been deleted assert not os.path.exists(intercepted["filename"])
def test_assets(self): try: import PIL # Travis does not support PNG files, see # https://github.com/travis-ci/travis-ci/issues/746 from PIL import Image Image.new('RGB', (10,10)).save(StringIO(), 'png') except (ImportError, IOError): raise SkipTest() self.create_files({'noise.scss': 'h1 {background: background-noise()}'}) self.mkbundle('noise.scss', filters='pyscss', output='out.css').build() assert doctest_match( 'h1 {\n background: url("...png");\n}\n', self.get('out.css'),)
def loader(self, text, filename=None): io = StringIO(textwrap.dedent(text)) if filename: io.name = filename return YAMLLoader(io)
def __call__(self, bundles=None, output=None, directory=None, no_cache=None, manifest=None, production=None): """Build assets. ``bundles`` A list of bundle names. If given, only this list of bundles should be built. ``output`` List of (bundle, filename) 2-tuples. If given, only these bundles will be built, using the custom output filenames. Cannot be used with ``bundles``. ``directory`` Custom output directory to use for the bundles. The original basenames defined in the bundle ``output`` attribute will be used. If the ``output`` of the bundles are pointing to different directories, they will be offset by their common prefix. Cannot be used with ``output``. ``no_cache`` If set, a cache (if one is configured) will not be used. ``manifest`` If set, the given manifest instance will be used, instead of any that might have been configured in the Environment. The value passed will be resolved through ``get_manifest()``. If this fails, a file-based manifest will be used using the given value as the filename. ``production`` If set to ``True``, then :attr:`Environment.debug`` will forcibly be disabled (set to ``False``) during the build. """ # Validate arguments if bundles and output: raise CommandError( 'When specifying explicit output filenames you must ' 'do so for all bundles you want to build.') if directory and output: raise CommandError('A custom output directory cannot be ' 'combined with explicit output filenames ' 'for individual bundles.') if production: # TODO: Reset again (refactor commands to be classes) self.environment.debug = False # TODO: Oh how nice it would be to use the future options stack. if manifest is not None: try: manifest = get_manifest(manifest, env=self.environment) except ValueError: manifest = get_manifest( # abspath() is important, or this will be considered # relative to Environment.directory. "file:%s" % os.path.abspath(manifest), env=self.environment) self.environment.manifest = manifest # Use output as a dict. if output: output = dict(output) # Validate bundle names bundle_names = bundles if bundles else (output.keys() if output else []) for name in bundle_names: if not name in self.environment: raise CommandError( 'I do not know a bundle name named "%s".' % name) # Make a list of bundles to build, and the filename to write to. if bundle_names: # TODO: It's not ok to use an internal property here. bundles = [(n,b) for n, b in self.environment._named_bundles.items() if n in bundle_names] else: # Includes unnamed bundles as well. bundles = [(None, b) for b in self.environment] # Determine common prefix for use with ``directory`` option. if directory: prefix = os.path.commonprefix( [os.path.normpath(b.resolve_output(self.environment)) for _, b in bundles if b.output]) # dirname() gives the right value for a single file. prefix = os.path.dirname(prefix) to_build = [] for name, bundle in bundles: # TODO: We really should support this. This error here # is just in place of a less understandable error that would # otherwise occur. if bundle.is_container and directory: raise CommandError( 'A custom output directory cannot currently be ' 'used with container bundles.') # Determine which filename to use, if not the default. overwrite_filename = None if output: overwrite_filename = output[name] elif directory: offset = os.path.normpath( bundle.resolve_output(self.environment))[len(prefix)+1:] overwrite_filename = os.path.join(directory, offset) to_build.append((bundle, overwrite_filename, name,)) # Build. built = [] for bundle, overwrite_filename, name in to_build: if name: # A name is not necessary available of the bundle was # registered without one. self.log.info("Building bundle: %s (to %s)" % ( name, overwrite_filename or bundle.output)) else: self.log.info("Building bundle: %s" % bundle.output) try: if not overwrite_filename: bundle.build(force=True, env=self.environment, disable_cache=no_cache) else: # TODO: Rethink how we deal with container bundles here. # As it currently stands, we write all child bundles # to the target output, merged (which is also why we # create and force writing to a StringIO instead of just # using the ``Hunk`` objects that build() would return # anyway. output = StringIO() bundle.build(force=True, env=self.environment, output=output, disable_cache=no_cache) if directory: # Only auto-create directories in this mode. output_dir = os.path.dirname(overwrite_filename) if not os.path.exists(output_dir): os.makedirs(output_dir) MemoryHunk(output.getvalue()).save(overwrite_filename) built.append(bundle) except BuildError as e: self.log.error("Failed, error was: %s" % e) if len(built): self.event_handlers['post_build']() if len(built) != len(to_build): return 2