Skip to content

Commit

Permalink
Added/Fixed backend level configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
noirbizarre committed Mar 10, 2017
1 parent 6055238 commit 98bdf1d
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 15 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Changelog
Current
-------

- Added backend level configuration
- Added backend level configuration ``FS_{BACKEND_NAME}_{KEY}``

0.3.0 (2017-03-05)
------------------
Expand Down
9 changes: 8 additions & 1 deletion docs/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Storages configuration
Each storage configuration can be overriden from the application configuration.
The configuration is loaded in the following order:

- ``{BACKEND_NAME}_FS_{KEY}`` (backend specific configuration)
- ``FS_{BACKEND_NAME}_{KEY}`` (backend specific configuration)
- ``{STORAGE_NAME}_FS_{KEY}`` (specific configuration)
- ``FS_{KEY}`` (global configuration)
- default value
Expand All @@ -78,3 +78,10 @@ You can override its root with the following configuration:
.. code-block:: python
AVATARS_FS_ROOT = '/somewhere/on/the/filesystem'
Or you can set a base URL to all storages for a given backend:

.. code-block:: python
FS_S3_URL = 'https://s3.somewhere.com/'
FS_S3_REGION = 'us-east-1'
24 changes: 15 additions & 9 deletions flask_fs/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@

CONF_PREFIX = 'FS_'
PREFIX = '{0}_FS_'
BACKEND_PREFIX = 'FS_{0}_'

# Config keys that should be overwritten from backend config
BACKEND_EXCLUDED_CONFIG = ('BACKEND', 'URL')


class Config(dict):
Expand Down Expand Up @@ -89,36 +93,37 @@ def configure(self, app):
For each storage, the configuration is loaded with the following pattern::
{BACKEND_NAME}_FS_{KEY} then
FS_{BACKEND_NAME}_{KEY} then
{STORAGE_NAME}_FS_{KEY}
If no configuration is set for a given key, global config is taken as default.
'''
config = Config()

prefix = PREFIX.format(self.name.upper())
backend = config.get('backend', app.config['FS_BACKEND'])
backend_prefix = PREFIX.format(backend.upper())

backend_key = '{0}BACKEND'.format(prefix)
self.backend_name = app.config.get(backend_key, app.config['FS_BACKEND'])
self.backend_prefix = BACKEND_PREFIX.format(self.backend_name.upper())
backend_excluded_keys = [''.join((self.backend_prefix, k)) for k in BACKEND_EXCLUDED_CONFIG]

# Set default values
for key, value in DEFAULT_CONFIG.items():
config.setdefault(key, value)

# Set backend level values
for key, value in app.config.items():
if key.startswith(backend_prefix):
config[key.replace(backend_prefix, '').lower()] = value
if key.startswith(self.backend_prefix) and key not in backend_excluded_keys:
config[key.replace(self.backend_prefix, '').lower()] = value

# Set storage level values
for key, value in app.config.items():
if key.startswith(prefix):
config[key.replace(prefix, '').lower()] = value

if backend in BUILTIN_BACKENDS:
backend_class = import_string(BUILTIN_BACKENDS[backend])
if self.backend_name in BUILTIN_BACKENDS:
backend_class = import_string(BUILTIN_BACKENDS[self.backend_name])
else:
backend_class = import_string(backend)
backend_class = import_string(self.backend_name)
self.backend = backend_class(self.name, config)
self.config = config

Expand All @@ -133,6 +138,7 @@ def base_url(self):
if config_value:
return self._clean_url(config_value)
default_url = current_app.config.get('FS_URL')
default_url = current_app.config.get('{0}URL'.format(self.backend_prefix), default_url)
if default_url:
url = urljoin(default_url, self.name)
return self._clean_url(url)
Expand Down
31 changes: 29 additions & 2 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,33 @@ def test_backend_level_configuration(app):
files = Storage('files')
app.configure(files,
FS_URL='http://somewhere.net/test/',
LOCAL_FS_URL='http://somewhere-else.net/local/'
FS_LOCAL_URL='http://somewhere-else.net/local/'
)
assert files.base_url == 'http://somewhere-else.net/local/'
assert isinstance(files.backend, LocalBackend)
assert files.base_url == 'http://somewhere-else.net/local/files/'


def test_configuration_cascading(app):
files = Storage('files')
avatars = Storage('avatars')
images = Storage('images')
app.configure(files, avatars, images,
FS_BACKEND='s3',
FS_S3_ENDPOINT='http://localhost:9000',
FS_S3_REGION='us-east-1',
FS_S3_ACCESS_KEY='ABCDEFGHIJKLMNOQRSTU',
FS_S3_SECRET_KEY='abcdefghiklmnoqrstuvwxyz1234567890abcdef',
FS_URL='http://somewhere.net/test/',
FS_LOCAL_URL='http://somewhere-else.net/local/',
FILES_FS_BACKEND='local',
AVATARS_FS_BACKEND='local',
AVATARS_FS_URL='http://somewhere-else.net/avatars/'
)

assert files.backend_name == 'local'
assert avatars.backend_name == 'local'
assert images.backend_name == 's3'
assert files.base_url == 'http://somewhere-else.net/local/files/'
assert avatars.base_url == 'http://somewhere-else.net/avatars/'
assert images.base_url == 'http://somewhere.net/test/images/'
assert images.config.endpoint == 'http://localhost:9000'
8 changes: 6 additions & 2 deletions tests/test_local_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,9 @@ def test_default_root(self, app):
root = self.test_dir.join('default')
backend = LocalBackend('default', Config({}))
assert backend.root == root
# with app.app_context():
# self.assertEqual(backend.root, root)

def test_backend_root(self, app):
app.config['LOCAL_FS_ROOT'] = str(self.test_dir)
root = self.test_dir.join('default')
backend = LocalBackend('default', Config({}))
assert backend.root == root

0 comments on commit 98bdf1d

Please sign in to comment.