Skip to content

Commit

Permalink
Switch to setuptools entrypoint based backend registeration
Browse files Browse the repository at this point in the history
  • Loading branch information
noirbizarre committed Mar 10, 2017
1 parent 3d7beaa commit 2ef111b
Show file tree
Hide file tree
Showing 9 changed files with 52 additions and 37 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Current

- Added backend level configuration ``FS_{BACKEND_NAME}_{KEY}``
- Improved backend documentation
- Use setuptools entry points to register backends.

0.3.0 (2017-03-05)
------------------
Expand Down
10 changes: 10 additions & 0 deletions docs/backends.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ Custom backends
Flask-FS allows you to defined your own backend
by extending the :class:`~flask_fs.backends.BaseBackend` class.

You need to register your backend using setuptools entrypoints in your ``setup.py``:

.. code-block:: python
entry_points={
'fs.backend': [
'custom = my.custom.package:CustomBackend',
]
},
Sample configuration
--------------------
Expand Down
4 changes: 2 additions & 2 deletions flask_fs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
try:
from flask import current_app

from .backends import BaseBackend, DEFAULT_BACKEND, BUILTIN_BACKENDS # noqa: Facade pattern
from .backends import BaseBackend, DEFAULT_BACKEND # noqa: Facade pattern
from .errors import * # noqa: Facade pattern
from .files import * # noqa: Facade pattern
from .storage import Storage # noqa: Facade pattern
Expand Down Expand Up @@ -36,7 +36,7 @@ def init_app(app, *storages):
app.config.setdefault('FS_ROOT', join(app.instance_path, 'fs'))
app.config.setdefault('FS_PREFIX', None)
app.config.setdefault('FS_URL', None)
app.config.setdefault('FS_BACKEND', 'local')
app.config.setdefault('FS_BACKEND', DEFAULT_BACKEND)
app.config.setdefault('FS_IMAGES_OPTIMIZE', False)

state = app.extensions['fs'] = app.extensions.get('fs', {})
Expand Down
9 changes: 1 addition & 8 deletions flask_fs/backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,9 @@

import six

__all__ = [i.encode('ascii') for i in ('BaseBackend', 'DEFAULT_BACKEND', 'BUILTIN_BACKENDS')]
__all__ = [i.encode('ascii') for i in ('BaseBackend', 'DEFAULT_BACKEND')]


BUILTIN_BACKENDS = {
'local': 'flask_fs.backends.local.LocalBackend',
's3': 'flask_fs.backends.s3.S3Backend',
'swift': 'flask_fs.backends.swift.SwiftBackend',
'grids': 'flask_fs.backends.gridfs.GridFsBackend',
}

DEFAULT_BACKEND = 'local'


Expand Down
15 changes: 15 additions & 0 deletions flask_fs/backends/mock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import logging

from . import BaseBackend

log = logging.getLogger(__name__)


class MockBackend(BaseBackend):
'''
A backend with only purpose of being mocked
'''
pass
21 changes: 9 additions & 12 deletions flask_fs/storage.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import pkg_resources
import os.path

try:
from urllib.parse import urljoin
except:
from urlparse import urljoin

from flask import current_app, url_for, request, abort
from six.moves.urllib.parse import urljoin
from werkzeug import secure_filename, FileStorage, cached_property
from werkzeug.utils import import_string


from .backends import BUILTIN_BACKENDS
from .errors import UnauthorizedFileType, FileExists, OperationNotSupported, FileNotFound
from .files import DEFAULTS, extension, lower_extension

Expand All @@ -30,6 +24,9 @@
# Config keys that should be overwritten from backend config
BACKEND_EXCLUDED_CONFIG = ('BACKEND', 'URL', 'ROOT')

# Load registered backends
BACKENDS = dict((ep.name, ep) for ep in pkg_resources.iter_entry_points('fs.backend'))


class Config(dict):
'''
Expand Down Expand Up @@ -120,10 +117,10 @@ def configure(self, app):
if key.startswith(prefix):
config[key.replace(prefix, '').lower()] = value

if self.backend_name in BUILTIN_BACKENDS:
backend_class = import_string(BUILTIN_BACKENDS[self.backend_name])
else:
backend_class = import_string(self.backend_name)
if self.backend_name not in BACKENDS:
raise ValueError('Unknown backend "{0}"'.format(self.backend_name))
backend_class = BACKENDS[self.backend_name].load()
backend_class.backend_name = self.backend_name
self.backend = backend_class(self.name, config)
self.config = config

Expand Down
2 changes: 1 addition & 1 deletion requirements/test.pip
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
-r s3.pip
-r gridfs.pip
-r swift.pip
mock
pytest
pytest-faker
pytest-flask
pytest-sugar
pytest-mock
flask-mongoengine
pillow
9 changes: 9 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ def pip(filename):
'ci': ci_require,
'dev': dev_require,
},
entry_points={
'fs.backend': [
'local = flask_fs.backends.local:LocalBackend',
's3 = flask_fs.backends.s3:S3Backend [s3]',
'gridfs = flask_fs.backends.gridfs:GridFsBackend [gridfs]',
'swift = flask_fs.backends.swift:SwiftBackend [swift]',
'mock = flask_fs.backends.mock:MockBackend',
]
},
license='MIT',
use_2to3=True,
zip_safe=False,
Expand Down
18 changes: 4 additions & 14 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@
import io
import os
import six
import mock

from flask import Flask
from werkzeug.datastructures import FileStorage

import flask_fs as fs

import pytest

BIN_FILE = os.path.join(os.path.dirname(__file__), 'flask.png')
Expand Down Expand Up @@ -61,15 +58,8 @@ def utils(faker):
return Utils()


class MockBackend(fs.BaseBackend):
pass


MOCK_BACKEND = '.'.join((__name__, MockBackend.__name__))


@pytest.fixture
def mock_backend(app):
app.config['FS_BACKEND'] = MOCK_BACKEND
patcher = mock.patch(MOCK_BACKEND)
yield patcher.start()
def mock_backend(app, mocker):
app.config['FS_BACKEND'] = 'mock'
mock = mocker.patch('flask_fs.backends.mock.MockBackend')
yield mock

0 comments on commit 2ef111b

Please sign in to comment.