Skip to content
Browse files

Settle use of webassets load_path/directory.

Mostly, when the webassets load_path system should be used, when webassets
Environment.directory and Environment.url should be used, and when to use
the Flask static folder system is now put in writing.

The actual implementation and behaviour has changed slightly and subtly to
follow what the design sets out to do.

Various tests needed to be updated along the way.

Closes #30.
  • Loading branch information...
1 parent ad83bdf commit c916d3159981b2260a9cdee09e2da04af009e6a7 @miracle2k committed
Showing with 83 additions and 34 deletions.
  1. +46 −10 src/flask_assets.py
  2. +3 −7 tests/test_env.py
  3. +34 −17 tests/test_integration.py
View
56 src/flask_assets.py
@@ -119,7 +119,24 @@ def get_static_folder(app_or_blueprint):
class FlaskResolver(Resolver):
- """Support Flask blueprints."""
+ """Adds support for Flask blueprints.
+
+ This resolver is designed to use the Flask staticfile system to
+ locate files, by looking at directory prefixes (``foo/bar.png``
+ looks in the static folder of the ``foo`` blueprint. ``url_for``
+ is used to generate urls to these files.
+
+ This default behaviour changes when you start setting certain
+ standard *webassets* path and url configuration values:
+
+ If a :attr:`Environment.directory` is set, output files will
+ always be written there, while source files still use the Flask
+ system.
+
+ If a :attr:`Environment.load_path` is set, it is used to look
+ up source files, replacing the Flask system. Blueprint prefixes
+ are no longer resolved.
+ """
def split_prefix(self, item):
"""See if ``item`` has blueprint prefix, return (directory, rel_path).
@@ -139,11 +156,23 @@ def split_prefix(self, item):
return directory, item
+ @property
+ def use_webassets_system_for_output(self):
+ return self.env.config.get('directory') is not None or \
+ self.env.config.get('url') is not None
+
+ @property
+ def use_webassets_system_for_sources(self):
+ return bool(self.env.load_path)
+
def search_for_source(self, item):
- if self.env.load_path:
- # Note: With only env.directory set, we don't go to default;
- # Setting env.directory only makes the output directory fixed.
+ # If a load_path is set, use it instead of the Flask static system.
+ #
+ # Note: With only env.directory set, we don't go to default;
+ # Setting env.directory only makes the output directory fixed.
+ if self.use_webassets_system_for_sources:
return Resolver.search_for_source(self, item)
+
# Look in correct blueprint's directory
directory, item = self.split_prefix(item)
try:
@@ -154,21 +183,24 @@ def search_for_source(self, item):
return path.normpath(path.join(directory, item))
def resolve_output_to_path(self, target, bundle):
- if self.env.config.get('directory'):
+ # If a directory/url pair is set, always use it for output files
+ if self.use_webassets_system_for_output:
return Resolver.resolve_output_to_path(self, target, bundle)
+
# Allow targeting blueprint static folders
directory, rel_path = self.split_prefix(target)
return path.normpath(path.join(directory, rel_path))
def resolve_source_to_url(self, filepath, item):
- if self.env.config.get('url'):
- return url_prefix_join(self.env.url, item)
+ # If a load path is set, use it instead of the Flask static system.
+ if self.use_webassets_system_for_sources:
+ return super(FlaskResolver, self).resolve_source_to_url(filepath, item)
filename = item
if hasattr(self.env._app, 'blueprints'):
try:
blueprint, name = item.split('/', 1)
- self.env._app.blueprints[blueprint] # keyerror if no module
+ self.env._app.blueprints[blueprint] # keyerror if no module
endpoint = '%s.static' % blueprint
filename = name
except (ValueError, KeyError):
@@ -177,7 +209,7 @@ def resolve_source_to_url(self, filepath, item):
# Module support for Flask < 0.7
try:
module, name = item.split('/', 1)
- self.env._app.modules[module] # keyerror if no module
+ self.env._app.modules[module] # keyerror if no module
endpoint = '%s.static' % module
filename = name
except (ValueError, KeyError):
@@ -194,7 +226,11 @@ def resolve_source_to_url(self, filepath, item):
ctx.pop()
def resolve_output_to_url(self, target):
- # Behaves like the source directory
+ # With a directory/url pair set, use it for output files.
+ if self.use_webassets_system_for_output:
+ return Resolver.resolve_output_to_url(self, target)
+
+ # Otherwise, behaves like generating urls to a source file.
return self.resolve_source_to_url(None, target)
View
10 tests/test_env.py
@@ -10,17 +10,13 @@ def setup(self):
self.app = Flask(__name__)
self.env = Environment(self.app)
self.env.debug = True
- self.app.config.update({
- 'ASSETS_DIRECTORY': '',
- 'ASSETS_URL': '/foo',
- })
self.env.register('test', 'file1', 'file2')
def test_tag_available(self):
"""Jinja tag has been made available.
"""
t = self.app.jinja_env.from_string('{% assets "test" %}{{ASSET_URL}};{% endassets %}')
- assert t.render() == '/foo/file1;/foo/file2;'
+ assert t.render() == '/static/file1;/static/file2;'
def test_from_yaml(self):
"""YAML configuration gets loaded
@@ -37,7 +33,7 @@ def test_from_yaml(self):
self.env.from_yaml('test.yaml')
t = self.app.jinja_env.from_string('{% assets "yamltest" %}{{ASSET_URL}};{% endassets %}')
- assert t.render() == '/foo/yamlfile1;/foo/yamlfile2;'
+ assert t.render() == '/static/yamlfile1;/static/yamlfile2;'
os.remove('test.yaml')
@@ -51,4 +47,4 @@ def test_from_python_module(self):
self.env.from_module(module)
t = self.app.jinja_env.from_string('{% assets "pytest" %}{{ASSET_URL}};{% endassets %}')
- assert t.render() == '/foo/pyfile1;/foo/pyfile2;'
+ assert t.render() == '/static/pyfile1;/static/pyfile2;'
View
51 tests/test_integration.py
@@ -48,8 +48,9 @@ def test_config_values_not_set_by_default(self):
assert_raises(KeyError, self.env.config.__getitem__, 'url')
def test_directory_auto(self):
- """Test how we handle file references if no root 'directory' is
- configured manually.
+ """Test how we resolve file references through the Flask static
+ system by default (if no custom 'env.directory' etc. values
+ have been configured manually).
"""
assert not 'directory' in self.env.config
root = self.app.root_path
@@ -67,17 +68,10 @@ def test_directory_auto(self):
self.app.static_folder = '/'
assert get_all_bundle_files(Bundle('foo'), self.env) == ['/foo']
- def test_directory_custom(self):
- """A custom root directory is configured."""
- self.env.load_path = [self.tempdir]
- self.create_files(['foo', 'module/bar'])
- print get_all_bundle_files(Bundle('foo'), self.env)
- assert get_all_bundle_files(Bundle('foo'), self.env) == [self.path('foo')]
- # We do not recognize references to modules.
- assert get_all_bundle_files(Bundle('module/bar'), self.env) == [self.path('module/bar')]
-
def test_url_auto(self):
- """Test how urls are generated if no 'url' is configured manually.
+ """Test how urls are generated via the Flask static system
+ by default (if no custom 'env.url' etc. values have been
+ configured manually).
"""
assert not 'url' in self.env.config
@@ -92,12 +86,35 @@ def test_url_auto(self):
from flask import _request_ctx_stack
assert _request_ctx_stack.top is None
- def test_url_custom(self):
- """A custom root url is configured."""
- self.env.url = '/media'
- assert Bundle('foo').urls(self.env) == ['/media/foo']
+ def test_custom_load_path(self):
+ """A custom load_path is configured - this will affect how
+ we deal with source files.
+ """
+ self.env.append_path(self.tempdir, '/custom/')
+ self.create_files(['foo', 'module/bar'])
+ assert get_all_bundle_files(Bundle('foo'), self.env) == [self.path('foo')]
+ # We do not recognize references to modules.
+ assert get_all_bundle_files(Bundle('module/bar'), self.env) == [self.path('module/bar')]
+
+ assert Bundle('foo').urls(self.env) == ['/custom/foo']
+ assert Bundle('module/bar').urls(self.env) == ['/custom/module/bar']
+
+ def test_custom_directory_and_url(self):
+ """Custom directory/url are configured - this will affect how
+ we deal with output files."""
+ # Create source source file, make it findable (by default,
+ # static_folder) is set to a fixed subfolder of the test dir (why?)
+ self.create_files({'a': ''})
+ self.app.static_folder = self.tempdir
+ # Setup custom directory/url pair for output
+ self.env.directory = self.tempdir
+ self.env.url = '/custom'
+ self.env.debug = False # Return build urls
+ self.env.expire = False # No query strings
+
+ assert Bundle('a', output='foo').urls(self.env) == ['/custom/foo']
# We do not recognize references to modules.
- assert Bundle('module/bar').urls(self.env) == ['/media/module/bar']
+ assert Bundle('a', output='module/bar').urls(self.env) == ['/custom/module/bar']
def test_existing_request_object_used(self):
"""[Regression] Check for a bug where the url generation code of

0 comments on commit c916d31

Please sign in to comment.
Something went wrong with that request. Please try again.