Skip to content

Commit

Permalink
Make singleton decorator explicit
Browse files Browse the repository at this point in the history
  • Loading branch information
c-w committed Nov 26, 2018
1 parent 53639b5 commit c7a1570
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 9 deletions.
11 changes: 6 additions & 5 deletions opwen_email_server/integration/azure.py
Expand Up @@ -8,9 +8,10 @@
from opwen_email_server.services.storage import AzureObjectStorage
from opwen_email_server.services.storage import AzureObjectsStorage
from opwen_email_server.services.storage import AzureTextStorage
from opwen_email_server.utils.collections import singleton


@lru_cache(maxsize=1)
@singleton
def get_auth() -> AzureAuth:
return AzureAuth(
storage=AzureTextStorage(
Expand All @@ -20,7 +21,7 @@ def get_auth() -> AzureAuth:
provider=config.STORAGE_PROVIDER))


@lru_cache(maxsize=1)
@singleton
def get_client_storage() -> AzureObjectsStorage:
return AzureObjectsStorage(
file_storage=AzureFileStorage(
Expand All @@ -30,7 +31,7 @@ def get_client_storage() -> AzureObjectsStorage:
provider=config.STORAGE_PROVIDER))


@lru_cache(maxsize=1)
@singleton
def get_raw_email_storage() -> AzureTextStorage:
return AzureTextStorage(
account=config.BLOBS_ACCOUNT,
Expand All @@ -39,13 +40,13 @@ def get_raw_email_storage() -> AzureTextStorage:
provider=config.STORAGE_PROVIDER)


@lru_cache(maxsize=1)
@singleton
def get_email_sender() -> SendgridEmailSender:
return SendgridEmailSender(
key=config.SENDGRID_KEY)


@lru_cache(maxsize=1)
@singleton
def get_email_storage() -> AzureObjectStorage:
return AzureObjectStorage(
text_storage=AzureTextStorage(
Expand Down
6 changes: 6 additions & 0 deletions opwen_email_server/utils/collections.py
@@ -1,4 +1,6 @@
from functools import lru_cache
from itertools import islice
from typing import Callable
from typing import Iterable
from typing import Optional
from typing import TypeVar
Expand All @@ -18,3 +20,7 @@ def chunks(iterable: Iterable[T], chunk_size: int) -> Iterable[Iterable[T]]:
if not chunk:
return
yield chunk


def singleton(func: Callable) -> Callable:
return lru_cache(maxsize=1)(func)
8 changes: 4 additions & 4 deletions opwen_email_server/utils/log.py
@@ -1,4 +1,3 @@
from functools import lru_cache
from logging import Formatter
from logging import Handler
from logging import Logger
Expand All @@ -17,16 +16,17 @@
from opwen_email_server.constants.logging import STDERR
from opwen_email_server.constants.logging import TELEMETRY_QUEUE_ITEMS
from opwen_email_server.constants.logging import TELEMETRY_QUEUE_SECONDS
from opwen_email_server.utils.collections import singleton


@lru_cache(maxsize=1)
@singleton
def _get_log_handlers() -> Iterable[Handler]:
stderr = StreamHandler()
stderr.setFormatter(Formatter(STDERR))
return [stderr]


@lru_cache(maxsize=1)
@singleton
def _get_logger() -> Logger:
log = getLogger()
for handler in _get_log_handlers():
Expand All @@ -35,7 +35,7 @@ def _get_logger() -> Logger:
return log


@lru_cache(maxsize=1)
@singleton
def _get_telemetry_client() -> Optional[TelemetryClient]:
if not APPINSIGHTS_KEY:
return None
Expand Down
28 changes: 28 additions & 0 deletions tests/opwen_email_server/utils/test_collections.py
@@ -1,3 +1,4 @@
from collections import Counter
from unittest import TestCase

from opwen_email_server.utils import collections
Expand Down Expand Up @@ -29,3 +30,30 @@ def test_creates_nonfull_chunks(self):
chunks = collections.chunks([1, 2, 3, 4], 3)

self.assertEqual(list(chunks), [(1, 2, 3), (4, )])


class SingletonTests(TestCase):
def test_creates_object_only_once(self):
value1 = self.function1()
value2 = self.function1()
value3 = self.function2()
value4 = self.function2()

self.assertIs(value1, value2)
self.assertIs(value3, value4)
self.assertIsNot(value1, value3)
self.assertEqual(self.call_counts['function1'], 1)
self.assertEqual(self.call_counts['function2'], 1)

def setUp(self):
self.call_counts = Counter()

@collections.singleton
def function1(self):
self.call_counts['function1'] += 1
return 'some-value'

@collections.singleton
def function2(self):
self.call_counts['function2'] += 1
return 'some-other-value'

0 comments on commit c7a1570

Please sign in to comment.