Skip to content

Commit

Permalink
Merge pull request #37 from percipient/override-settings
Browse files Browse the repository at this point in the history
Allow settings to be overridden.
  • Loading branch information
lamby committed Mar 10, 2016
2 parents 9166161 + 590a24d commit f2d6c57
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 24 deletions.
11 changes: 6 additions & 5 deletions django_slack/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@

from django.conf import settings
from django.template.loader import render_to_string
from django.utils.module_loading import import_string

from . import app_settings
from .utils import get_backend
from .app_settings import app_settings

backend = import_string(app_settings.BACKEND)()

def slack_message(template, context=None, attachments=None, fail_silently=app_settings.FAIL_SILENTLY):
def slack_message(template, context=None, attachments=None, fail_silently=None):
backend = get_backend()
data = {}
context = dict(context or {}, settings=settings)
if fail_silently is None:
fail_silently = app_settings.FAIL_SILENTLY

for k, v in {
'text': {
Expand Down
34 changes: 20 additions & 14 deletions django_slack/app_settings.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
from django.conf import settings

DEFAULT_ENDPOINT_URL = 'https://slack.com/api/chat.postMessage'
class AppSettings(object):
# Lazily obtain settings to support ``override_settings`` decorator
def get(suffix, default):
def setting(self):
return getattr(settings, 'SLACK_%s' % suffix, default)
return setting

def setting(suffix, default):
return getattr(settings, 'SLACK_%s' % suffix, default)
TOKEN = property(get('TOKEN', None))
CHANNEL = property(get('CHANNEL', '#general'))
USERNAME = property(get('USERNAME', 'bot'))
ICON_URL = property(get('ICON_URL', None))
ICON_EMOJI = property(get('ICON_EMOJI', None))

TOKEN = setting('TOKEN', None)
CHANNEL = setting('CHANNEL', '#general')
USERNAME = setting('USERNAME', 'bot')
ICON_URL = setting('ICON_URL', None)
ICON_EMOJI = setting('ICON_EMOJI', None)
ENDPOINT_URL = setting('ENDPOINT_URL', DEFAULT_ENDPOINT_URL)
DEFAULT_ENDPOINT_URL = 'https://slack.com/api/chat.postMessage'
ENDPOINT_URL = property(get('ENDPOINT_URL', DEFAULT_ENDPOINT_URL))

_BACKEND = 'django_slack.backends.DisabledBackend' if settings.DEBUG else \
'django_slack.backends.UrllibBackend'
BACKEND = setting('BACKEND', _BACKEND)
BACKEND_FOR_QUEUE = setting('BACKEND_FOR_QUEUE', _BACKEND)
_DEFAULT_BACKEND = 'django_slack.backends.DisabledBackend' if settings.DEBUG else \
'django_slack.backends.UrllibBackend'
BACKEND = property(get('BACKEND', _DEFAULT_BACKEND))
BACKEND_FOR_QUEUE = property(get('BACKEND_FOR_QUEUE', _DEFAULT_BACKEND))

FAIL_SILENTLY = setting('FAIL_SILENTLY', False)
FAIL_SILENTLY = property(get('FAIL_SILENTLY', False))

app_settings = AppSettings()
2 changes: 1 addition & 1 deletion django_slack/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

from django.utils.module_loading import import_string

from . import app_settings
from .utils import Backend
from .app_settings import app_settings

class UrllibBackend(Backend):
def send(self, url, data):
Expand Down
14 changes: 14 additions & 0 deletions django_slack/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import json

from django.utils.module_loading import import_string

from .app_settings import app_settings

class Backend(object):
def send(self, url, data):
raise NotImplementedError()
Expand All @@ -13,3 +17,13 @@ def validate(self, content_type, content):

elif content != 'ok':
raise ValueError(content)

def get_backend():
"""
Wrap the backend in a function to not load it at import time.
get_backend() caches the backend on first call.
"""
if get_backend.backend is None:
get_backend.backend = import_string(app_settings.BACKEND)()
return get_backend.backend
get_backend.backend = None
10 changes: 10 additions & 0 deletions tests/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,13 @@ def send(self, url, data):
'url': url,
'data': data,
})

class RaisingBackend(Backend):
"""
A backend which raises when asked to send a message.
"""
class RaisedException(Exception):
pass

def send(self, url, data):
raise RaisingBackend.RaisedException(url, data)
7 changes: 7 additions & 0 deletions tests/settings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
SECRET_KEY = 'not_empty'

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
}
}

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
Expand Down
9 changes: 5 additions & 4 deletions tests/test_escaping.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import unittest

from django_slack import slack_message
from django_slack.api import backend
from django_slack.utils import get_backend

class SlackTestCase(unittest.TestCase):
def setUp(self):
backend.reset()
self.backend = get_backend()
self.backend.reset()

def assertMessageCount(self, count):
self.assertEqual(len(backend.messages), count)
self.assertEqual(len(self.backend.messages), count)

def assertMessage(self, url=None, **kwargs):
"""
Ensure there was only one message sent with a URL and data values.
"""

self.assertMessageCount(1)
message = backend.messages[0]
message = self.backend.messages[0]

# Optionally ensure the URL.
if url is not None:
Expand Down
47 changes: 47 additions & 0 deletions tests/test_override.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from django.conf import settings
from django.test import TestCase, override_settings

from django_slack import slack_message
from django_slack.utils import get_backend
from django_slack.app_settings import app_settings

from tests.backends import RaisingBackend

class TestOverride(TestCase):
def setUp(self):
# Fake the backend not having been initialized yet.
get_backend.backend = None

def test_override(self):
"""
Ensure that accessing a setting in an override works.
"""
DISABLED_BACKEND = 'django_slack.backends.DisabledBackend'
with override_settings(SLACK_BACKEND=DISABLED_BACKEND):
self.assertEqual(settings.SLACK_BACKEND, DISABLED_BACKEND)
self.assertEqual(app_settings.BACKEND, DISABLED_BACKEND)

def test_backend_cache(self):
"""
Ensure that the backend is cached once it is called once.
"""
self.assertEqual(id(get_backend()), id(get_backend()))

def test_backend_override(self):
"""
Ensure the backend can be overridden.
"""
with override_settings(SLACK_BACKEND='tests.backends.RaisingBackend'):
with self.assertRaises(RaisingBackend.RaisedException):
slack_message('test.slack', {'text': 'test'})

def test_fail_silently(self):
"""
Ensure fail silently can be overridden.
"""
# Note that this will fail if test_backend_override ever fails.
with override_settings(
SLACK_FAIL_SILENTLY=True,
SLACK_BACKEND='tests.backends.RaisingBackend',
):
slack_message('test.slack', {'text': 'test'})

0 comments on commit f2d6c57

Please sign in to comment.