From 113977b19fda792a409cbee7e7dbc79ce15362ed Mon Sep 17 00:00:00 2001 From: Ariel Rin Date: Sat, 18 Jun 2022 13:07:36 +1000 Subject: [PATCH 1/4] Version Bump 2.13.0 --- allianceauth/__init__.py | 2 +- docker/.env.example | 2 +- docker/Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/allianceauth/__init__.py b/allianceauth/__init__.py index ff092fe9..7e26ff5a 100644 --- a/allianceauth/__init__.py +++ b/allianceauth/__init__.py @@ -1,7 +1,7 @@ # This will make sure the app is always imported when # Django starts so that shared_task will use this app. -__version__ = '2.12.1' +__version__ = '2.13.0' __title__ = 'Alliance Auth' __url__ = 'https://gitlab.com/allianceauth/allianceauth' NAME = f'{__title__} v{__version__}' diff --git a/docker/.env.example b/docker/.env.example index 3bc907cf..c8b8556c 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -1,7 +1,7 @@ PROTOCOL=https:// AUTH_SUBDOMAIN=%AUTH_SUBDOMAIN% DOMAIN=%DOMAIN% -AA_DOCKER_TAG=registry.gitlab.com/allianceauth/allianceauth/auth:v2.11 +AA_DOCKER_TAG=registry.gitlab.com/allianceauth/allianceauth/auth:v2.13 # Nginx Proxy Manager PROXY_HTTP_PORT=80 diff --git a/docker/Dockerfile b/docker/Dockerfile index 71fae64d..4ca457e5 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,5 +1,5 @@ FROM python:3.9-slim -ARG AUTH_VERSION=2.12.1 +ARG AUTH_VERSION=2.13.0 ARG AUTH_PACKAGE=allianceauth==${AUTH_VERSION} ENV VIRTUAL_ENV=/opt/venv ENV AUTH_USER=allianceauth From 091a2637ea3eb8581a85427bb3ff03b76ff59175 Mon Sep 17 00:00:00 2001 From: ErikKalkoken Date: Mon, 27 Jun 2022 13:41:15 +0200 Subject: [PATCH 2/4] Add extension to improve autodocs for Django models & enable source links --- docs/conf.py | 2 ++ docs/development/tech_docu/api/eveonline.rst | 3 +-- docs/development/tech_docu/api/notifications.rst | 3 ++- docs/requirements.txt | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 64cb80f0..71e699df 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -44,6 +44,8 @@ extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.napoleon', 'recommonmark', + 'sphinxcontrib_django2', + 'sphinx.ext.viewcode', ] # Add any paths that contain templates here, relative to this directory. diff --git a/docs/development/tech_docu/api/eveonline.rst b/docs/development/tech_docu/api/eveonline.rst index 054f7cb6..c09f76e7 100644 --- a/docs/development/tech_docu/api/eveonline.rst +++ b/docs/development/tech_docu/api/eveonline.rst @@ -11,5 +11,4 @@ models .. automodule:: allianceauth.eveonline.models :members: - :exclude-members: objects, provider - :undoc-members: + :exclude-members: DoesNotExist, MultipleObjectsReturned diff --git a/docs/development/tech_docu/api/notifications.rst b/docs/development/tech_docu/api/notifications.rst index be324576..7a4fc75b 100644 --- a/docs/development/tech_docu/api/notifications.rst +++ b/docs/development/tech_docu/api/notifications.rst @@ -13,7 +13,8 @@ models =========== .. autoclass:: allianceauth.notifications.models.Notification - :members: Level, mark_viewed, set_level + :members: + :exclude-members: DoesNotExist, MultipleObjectsReturned, save managers =========== diff --git a/docs/requirements.txt b/docs/requirements.txt index 8b49539b..a804dcf2 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -3,6 +3,7 @@ sphinx>=3.2.1,<4.0.0 sphinx_rtd_theme==0.5.0 recommonmark==0.6.0 Jinja2<3.1 +sphinxcontrib-django2 # Autodoc dependencies django>=3.2,<4.0.0 From 2ff200c566e07436aa13eb68fd2263ec4ce2e456 Mon Sep 17 00:00:00 2001 From: ErikKalkoken Date: Mon, 27 Jun 2022 13:43:45 +0200 Subject: [PATCH 3/4] Refer to django-esi docs --- docs/development/tech_docu/api/esi.rst | 34 +------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/docs/development/tech_docu/api/esi.rst b/docs/development/tech_docu/api/esi.rst index a6942e69..e9bedd8e 100644 --- a/docs/development/tech_docu/api/esi.rst +++ b/docs/development/tech_docu/api/esi.rst @@ -4,36 +4,4 @@ django-esi The django-esi package provides an interface for easy access to the ESI. -Location: ``esi`` - -This is an external package. Please also see `here `_ for it's official documentation. - -clients -=========== - -.. automodule:: esi.clients - :members: esi_client_factory - :undoc-members: - -decorators -=========== - -.. automodule:: esi.decorators - :members: - :undoc-members: - -errors -=========== - -.. automodule:: esi.errors - :members: - :undoc-members: - - -models -=========== - -.. automodule:: esi.models - :members: Scope, Token - :exclude-members: objects, provider - :undoc-members: +This is an external package. Please see `here `_ for it's documentation. From 8dec242a9388ed6f9708a2cdad34fd82a4309d08 Mon Sep 17 00:00:00 2001 From: Erik Kalkoken Date: Thu, 7 Jul 2022 07:37:21 +0000 Subject: [PATCH 4/4] Ensure backwards compatibility when fetching a redis client --- .../task_statistics/event_series.py | 4 +- .../tests/test_event_series.py | 6 +-- .../modules/discord/discord_client/client.py | 5 +-- .../discord_client/tests/test_client.py | 25 ++++-------- .../modules/discord/tests/piloting_tasks.py | 6 +-- .../modules/discord/tests/test_integration.py | 6 +-- allianceauth/utils/__init__.py | 0 allianceauth/utils/cache.py | 21 ++++++++++ allianceauth/utils/tests/__init__.py | 0 allianceauth/utils/tests/test_cache.py | 39 +++++++++++++++++++ docs/development/tech_docu/api/index.md | 1 + docs/development/tech_docu/api/utils.rst | 14 +++++++ 12 files changed, 94 insertions(+), 33 deletions(-) create mode 100644 allianceauth/utils/__init__.py create mode 100644 allianceauth/utils/cache.py create mode 100644 allianceauth/utils/tests/__init__.py create mode 100644 allianceauth/utils/tests/test_cache.py create mode 100644 docs/development/tech_docu/api/utils.rst diff --git a/allianceauth/authentication/task_statistics/event_series.py b/allianceauth/authentication/task_statistics/event_series.py index d1a222db..aead7c6a 100644 --- a/allianceauth/authentication/task_statistics/event_series.py +++ b/allianceauth/authentication/task_statistics/event_series.py @@ -5,7 +5,7 @@ from typing import List, Optional from pytz import utc from redis import Redis, RedisError -from django.core.cache import cache +from allianceauth.utils.cache import get_redis_client logger = logging.getLogger(__name__) @@ -39,7 +39,7 @@ class EventSeries: _ROOT_KEY = "ALLIANCEAUTH_EVENT_SERIES" def __init__(self, key_id: str, redis: Redis = None) -> None: - self._redis = cache.get_master_client() if not redis else redis + self._redis = get_redis_client() if not redis else redis try: if not self._redis.ping(): raise RuntimeError() diff --git a/allianceauth/authentication/task_statistics/tests/test_event_series.py b/allianceauth/authentication/task_statistics/tests/test_event_series.py index 30b61465..70804cf4 100644 --- a/allianceauth/authentication/task_statistics/tests/test_event_series.py +++ b/allianceauth/authentication/task_statistics/tests/test_event_series.py @@ -18,7 +18,7 @@ MODULE_PATH = "allianceauth.authentication.task_statistics.event_series" class TestEventSeries(TestCase): def test_should_abort_without_redis_client(self): # when - with patch(MODULE_PATH + ".cache.get_master_client") as mock: + with patch(MODULE_PATH + ".get_redis_client") as mock: mock.return_value = None events = EventSeries("dummy") # then @@ -27,7 +27,7 @@ class TestEventSeries(TestCase): def test_should_disable_itself_if_redis_not_available_1(self): # when - with patch(MODULE_PATH + ".cache.get_master_client") as mock_get_master_client: + with patch(MODULE_PATH + ".get_redis_client") as mock_get_master_client: mock_get_master_client.return_value.ping.side_effect = RedisError events = EventSeries("dummy") # then @@ -36,7 +36,7 @@ class TestEventSeries(TestCase): def test_should_disable_itself_if_redis_not_available_2(self): # when - with patch(MODULE_PATH + ".cache.get_master_client") as mock_get_master_client: + with patch(MODULE_PATH + ".get_redis_client") as mock_get_master_client: mock_get_master_client.return_value.ping.return_value = False events = EventSeries("dummy") # then diff --git a/allianceauth/services/modules/discord/discord_client/client.py b/allianceauth/services/modules/discord/discord_client/client.py index bbe62720..c4923504 100644 --- a/allianceauth/services/modules/discord/discord_client/client.py +++ b/allianceauth/services/modules/discord/discord_client/client.py @@ -8,7 +8,7 @@ from uuid import uuid1 from redis import Redis import requests -from django.core.cache import caches +from allianceauth.utils.cache import get_redis_client from allianceauth import __title__ as AUTH_TITLE, __url__, __version__ @@ -103,8 +103,7 @@ class DiscordClient: self._access_token = str(access_token) self._is_rate_limited = bool(is_rate_limited) if not redis: - default_cache = caches['default'] - self._redis = default_cache.get_master_client() + self._redis = get_redis_client() if not isinstance(self._redis, Redis): raise RuntimeError( 'This class requires a Redis client, but none was provided ' diff --git a/allianceauth/services/modules/discord/discord_client/tests/test_client.py b/allianceauth/services/modules/discord/discord_client/tests/test_client.py index acc57fac..d9e16649 100644 --- a/allianceauth/services/modules/discord/discord_client/tests/test_client.py +++ b/allianceauth/services/modules/discord/discord_client/tests/test_client.py @@ -85,29 +85,18 @@ class TestBasicsAndHelpers(TestCase): client = DiscordClient(TEST_BOT_TOKEN, mock_redis, is_rate_limited=True) self.assertTrue(client.is_rate_limited) - @patch(MODULE_PATH + '.caches') - def test_use_default_redis_if_none_provided(self, mock_caches): - my_redis = MagicMock(spec=Redis) - mock_default_cache = MagicMock(**{'get_master_client.return_value': my_redis}) - my_dict = {'default': mock_default_cache} - mock_caches.__getitem__.side_effect = my_dict.__getitem__ - + def test_use_default_redis_if_none_provided(self): client = DiscordClient(TEST_BOT_TOKEN) - self.assertTrue(mock_default_cache.get_master_client.called) - self.assertEqual(client._redis, my_redis) - - @patch(MODULE_PATH + '.caches') - def test_raise_exception_if_default_cache_is_not_redis(self, mock_caches): - my_redis = MagicMock() - mock_default_cache = MagicMock(**{'get_master_client.return_value': my_redis}) - my_dict = {'default': mock_default_cache} - mock_caches.__getitem__.side_effect = my_dict.__getitem__ + self.assertIsInstance(client._redis, Redis) + @patch(MODULE_PATH + '.get_redis_client') + def test_raise_exception_if_redis_client_not_found(self, mock_get_redis_client): + # given + mock_get_redis_client.return_value = None + # when with self.assertRaises(RuntimeError): DiscordClient(TEST_BOT_TOKEN) - self.assertTrue(mock_default_cache.get_master_client.called) - @requests_mock.Mocker() class TestOtherMethods(TestCase): diff --git a/allianceauth/services/modules/discord/tests/piloting_tasks.py b/allianceauth/services/modules/discord/tests/piloting_tasks.py index 15ee6d0e..4b1d0c7b 100755 --- a/allianceauth/services/modules/discord/tests/piloting_tasks.py +++ b/allianceauth/services/modules/discord/tests/piloting_tasks.py @@ -35,17 +35,17 @@ import logging from uuid import uuid1 import random -from django.core.cache import caches from django.contrib.auth.models import User, Group from allianceauth.services.modules.discord.models import DiscordUser +from allianceauth.utils.cache import get_redis_client logger = logging.getLogger('allianceauth') MAX_RUNS = 3 + def clear_cache(): - default_cache = caches['default'] - redis = default_cache.get_master_client() + redis = get_redis_client() redis.flushall() logger.info('Cache flushed') diff --git a/allianceauth/services/modules/discord/tests/test_integration.py b/allianceauth/services/modules/discord/tests/test_integration.py index e69f6a4d..fe8fb6fb 100644 --- a/allianceauth/services/modules/discord/tests/test_integration.py +++ b/allianceauth/services/modules/discord/tests/test_integration.py @@ -14,7 +14,6 @@ from requests.exceptions import HTTPError import requests_mock from django.contrib.auth.models import Group, User -from django.core.cache import caches from django.shortcuts import reverse from django.test import TransactionTestCase, TestCase from django.test.utils import override_settings @@ -23,6 +22,7 @@ from allianceauth.authentication.models import State from allianceauth.eveonline.models import EveCharacter from allianceauth.notifications.models import Notification from allianceauth.tests.auth_utils import AuthUtils +from allianceauth.utils.cache import get_redis_client from . import ( TEST_GUILD_ID, @@ -87,8 +87,7 @@ remove_guild_member_request = DiscordRequest( def clear_cache(): - default_cache = caches['default'] - redis = default_cache.get_master_client() + redis = get_redis_client() redis.flushall() logger.info('Cache flushed') @@ -109,7 +108,6 @@ def reset_testdata(): class TestServiceFeatures(TransactionTestCase): fixtures = ['disable_analytics.json'] - @classmethod def setUpClass(cls): super().setUpClass() diff --git a/allianceauth/utils/__init__.py b/allianceauth/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/allianceauth/utils/cache.py b/allianceauth/utils/cache.py new file mode 100644 index 00000000..6605cd7a --- /dev/null +++ b/allianceauth/utils/cache.py @@ -0,0 +1,21 @@ +from redis import Redis + +from django.core.cache import caches + +try: + import django_redis +except ImportError: + django_redis = None + + +def get_redis_client() -> Redis: + """Get the configured redis client used by Django for caching. + + This function is a wrapper designed to work for both AA2 and AA3 + and should always be used to ensure backwards compatibility. + """ + try: + return django_redis.get_redis_connection("default") + except AttributeError: + default_cache = caches["default"] + return default_cache.get_master_client() diff --git a/allianceauth/utils/tests/__init__.py b/allianceauth/utils/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/allianceauth/utils/tests/test_cache.py b/allianceauth/utils/tests/test_cache.py new file mode 100644 index 00000000..b023eaa0 --- /dev/null +++ b/allianceauth/utils/tests/test_cache.py @@ -0,0 +1,39 @@ +from unittest.mock import MagicMock, patch + +from django.test import TestCase + +from allianceauth.utils.cache import get_redis_client + +MODULE_PATH = "allianceauth.utils.cache" + + +class RedisClientStub: + """Substitute for a Redis client.""" + + pass + + +class TestGetRedisClient(TestCase): + def test_should_work_with_aa2_api(self): + # given + mock_django_cache = MagicMock() + mock_django_cache.get_master_client.return_value = RedisClientStub() + # when + with patch(MODULE_PATH + ".django_redis", None), patch.dict( + MODULE_PATH + ".caches", {"default": mock_django_cache} + ): + client = get_redis_client() + # then + self.assertIsInstance(client, RedisClientStub) + + def test_should_work_with_aa3_api(self): + # given + mock_django_redis = MagicMock() + mock_django_redis.get_redis_connection.return_value = RedisClientStub() + # when + with patch(MODULE_PATH + ".django_redis", mock_django_redis), patch.dict( + MODULE_PATH + ".caches", {"default": None} + ): + client = get_redis_client() + # then + self.assertIsInstance(client, RedisClientStub) diff --git a/docs/development/tech_docu/api/index.md b/docs/development/tech_docu/api/index.md index be231fec..b1773beb 100644 --- a/docs/development/tech_docu/api/index.md +++ b/docs/development/tech_docu/api/index.md @@ -11,4 +11,5 @@ To reduce redundancy and help speed up development we encourage developers to ut eveonline notifications testutils + utils ``` diff --git a/docs/development/tech_docu/api/utils.rst b/docs/development/tech_docu/api/utils.rst new file mode 100644 index 00000000..c27fa9fa --- /dev/null +++ b/docs/development/tech_docu/api/utils.rst @@ -0,0 +1,14 @@ +============================= +utils +============================= + +Utilities and helper functions. + +Location: ``allianceauth.utils`` + +cache +=========== + +.. automodule:: allianceauth.utils.cache + :members: + :undoc-members: