From ff138f24f1695f97988356c46fc2f4c4774019a1 Mon Sep 17 00:00:00 2001 From: Robert Raposa Date: Wed, 23 Sep 2020 16:36:14 -0400 Subject: [PATCH] rename custom metric to custom attribute Rename of "custom metric" to "custom attribute" was based on a decision (ADR) captured in edx-django-utils: https://github.com/edx/edx-django-utils/blob/master/edx_django_utils/monitoring/docs/decisions/0002-custom-monitoring-language.rst Deprecated RequestMetricsMiddleware due to rename. Use RequestCustomAttributesMiddleware instead. ARCHBOM-1495 --- CHANGELOG.rst | 11 ++ edx_rest_framework_extensions/__init__.py | 2 +- .../auth/bearer/authentication.py | 12 +- .../auth/jwt/middleware.py | 18 +-- .../auth/jwt/tests/test_middleware.py | 26 ++-- edx_rest_framework_extensions/middleware.py | 78 ++++++----- .../tests/test_middleware.py | 125 +++++++++++------- requirements/base.in | 2 +- requirements/base.txt | 30 ++--- requirements/dev.txt | 61 ++++----- requirements/docs.txt | 8 +- requirements/pip-tools.txt | 2 +- requirements/test.txt | 53 ++++---- 13 files changed, 240 insertions(+), 188 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d26eae96..92b59332 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,17 @@ Change Log Unreleased ---------- +[6.2.0] - 2020-08-24 +-------------------- + +Updated +~~~~~~~ + +* Renamed "custom metric" to "custom attribute" throughout the repo. This was based on a `decision (ADR) captured in edx-django-utils`_. + + * Deprecated RequestMetricsMiddleware due to rename. Use RequestCustomAttributesMiddleware instead. + +.. _`decision (ADR) captured in edx-django-utils`: https://github.com/edx/edx-django-utils/blob/master/edx_django_utils/monitoring/docs/decisions/0002-custom-monitoring-language.rst [6.1.2] - 2020-07-19 -------------------- diff --git a/edx_rest_framework_extensions/__init__.py b/edx_rest_framework_extensions/__init__.py index 2029aea1..fc650f5a 100644 --- a/edx_rest_framework_extensions/__init__.py +++ b/edx_rest_framework_extensions/__init__.py @@ -1,3 +1,3 @@ """ edx Django REST Framework extensions. """ -__version__ = '6.1.2' # pragma: no cover +__version__ = '6.2.0' # pragma: no cover diff --git a/edx_rest_framework_extensions/auth/bearer/authentication.py b/edx_rest_framework_extensions/auth/bearer/authentication.py index 340c2ade..0525e65f 100644 --- a/edx_rest_framework_extensions/auth/bearer/authentication.py +++ b/edx_rest_framework_extensions/auth/bearer/authentication.py @@ -4,7 +4,7 @@ import requests from django.contrib.auth import get_user_model -from edx_django_utils.monitoring import set_custom_metric +from edx_django_utils.monitoring import set_custom_attribute from rest_framework import exceptions from rest_framework.authentication import BaseAuthentication, get_authorization_header @@ -37,16 +37,16 @@ def get_user_info_url(self): return get_setting('OAUTH2_USER_INFO_URL') def authenticate(self, request): - set_custom_metric("BearerAuthentication", "Failed") # default value + set_custom_attribute("BearerAuthentication", "Failed") # default value if not self.get_user_info_url(): logger.warning('The setting OAUTH2_USER_INFO_URL is invalid!') - set_custom_metric("BearerAuthentication", "NoURL") + set_custom_attribute("BearerAuthentication", "NoURL") return None - set_custom_metric("BearerAuthentication_user_info_url", self.get_user_info_url()) + set_custom_attribute("BearerAuthentication_user_info_url", self.get_user_info_url()) auth = get_authorization_header(request).split() if not auth or auth[0].lower() != b'bearer': - set_custom_metric("BearerAuthentication", "None") + set_custom_attribute("BearerAuthentication", "None") return None if len(auth) == 1: @@ -55,7 +55,7 @@ def authenticate(self, request): raise exceptions.AuthenticationFailed('Invalid token header. Token string should not contain spaces.') output = self.authenticate_credentials(auth[1].decode('utf8')) - set_custom_metric("BearerAuthentication", "Success") + set_custom_attribute("BearerAuthentication", "Success") return output def authenticate_credentials(self, token): diff --git a/edx_rest_framework_extensions/auth/jwt/middleware.py b/edx_rest_framework_extensions/auth/jwt/middleware.py index be4479d7..6754629a 100644 --- a/edx_rest_framework_extensions/auth/jwt/middleware.py +++ b/edx_rest_framework_extensions/auth/jwt/middleware.py @@ -175,7 +175,7 @@ class JwtAuthCookieMiddleware(MiddlewareMixin): See the full decision here: https://github.com/edx/edx-platform/blob/master/openedx/core/djangoapps/oauth_dispatch/docs/decisions/0009-jwt-in-session-cookie.rst - Also, sets the metric 'request_jwt_cookie' with one of the following values: + Also, sets the custom attribute 'request_jwt_cookie' with one of the following values: 'success': Value when reconstitution is successful. 'not-requested': Value when jwt cookie authentication was not requested by the client. 'missing-both': Value when both cookies are missing and reconstitution is not possible. @@ -192,8 +192,8 @@ class JwtAuthCookieMiddleware(MiddlewareMixin): """ - def _get_missing_cookie_message_and_metric(self, cookie_name): - """ Returns tuple with missing cookie (log_message, metric_value) """ + def _get_missing_cookie_message_and_attribute(self, cookie_name): + """ Returns tuple with missing cookie (log_message, custom_attribute_value) """ cookie_missing_message = '{} cookie is missing. JWT auth cookies will not be reconstituted.'.format( cookie_name ) @@ -219,7 +219,7 @@ def process_view(self, request, view_func, view_args, view_kwargs): # pylint: d request.user = SimpleLazyObject(lambda: _get_user_from_jwt(request, view_func)) if not use_jwt_cookie_requested: - metric_value = 'not-requested' + attribute_value = 'not-requested' elif header_payload_cookie and signature_cookie: # Reconstitute JWT auth cookie if split cookies are available and jwt cookie # authentication was requested by the client. @@ -228,23 +228,23 @@ def process_view(self, request, view_func, view_args, view_kwargs): # pylint: d JWT_DELIMITER, signature_cookie, ) - metric_value = 'success' + attribute_value = 'success' elif header_payload_cookie or signature_cookie: # Log unexpected case of only finding one cookie. if not header_payload_cookie: - log_message, metric_value = self._get_missing_cookie_message_and_metric( + log_message, attribute_value = self._get_missing_cookie_message_and_attribute( jwt_cookie_header_payload_name() ) if not signature_cookie: - log_message, metric_value = self._get_missing_cookie_message_and_metric( + log_message, attribute_value = self._get_missing_cookie_message_and_attribute( jwt_cookie_signature_name() ) log.warning(log_message) else: - metric_value = 'missing-both' + attribute_value = 'missing-both' log.warning('Both JWT auth cookies missing. JWT auth cookies will not be reconstituted.') - monitoring.set_custom_metric('request_jwt_cookie', metric_value) + monitoring.set_custom_attribute('request_jwt_cookie', attribute_value) def _get_user_from_jwt(request, view_func): diff --git a/edx_rest_framework_extensions/auth/jwt/tests/test_middleware.py b/edx_rest_framework_extensions/auth/jwt/tests/test_middleware.py index fa988b27..41d79ea6 100644 --- a/edx_rest_framework_extensions/auth/jwt/tests/test_middleware.py +++ b/edx_rest_framework_extensions/auth/jwt/tests/test_middleware.py @@ -364,11 +364,11 @@ def setUp(self): self.request.session = 'mock session' self.middleware = JwtAuthCookieMiddleware() - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_do_not_use_jwt_cookies(self, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_do_not_use_jwt_cookies(self, mock_set_custom_attribute): self.middleware.process_view(self.request, None, None, None) self.assertIsNone(self.request.COOKIES.get(jwt_cookie_name())) - mock_set_custom_metric.assert_called_once_with('request_jwt_cookie', 'not-requested') + mock_set_custom_attribute.assert_called_once_with('request_jwt_cookie', 'not-requested') @ddt.data( (jwt_cookie_header_payload_name(), jwt_cookie_signature_name()), @@ -376,9 +376,9 @@ def test_do_not_use_jwt_cookies(self, mock_set_custom_metric): ) @ddt.unpack @patch('edx_rest_framework_extensions.auth.jwt.middleware.log') - @patch('edx_django_utils.monitoring.set_custom_metric') + @patch('edx_django_utils.monitoring.set_custom_attribute') def test_missing_cookies( - self, set_cookie_name, missing_cookie_name, mock_set_custom_metric, mock_log + self, set_cookie_name, missing_cookie_name, mock_set_custom_attribute, mock_log ): self.request.META[USE_JWT_COOKIE_HEADER] = 'true' self.request.COOKIES[set_cookie_name] = 'test' @@ -388,23 +388,25 @@ def test_missing_cookies( '%s cookie is missing. JWT auth cookies will not be reconstituted.' % missing_cookie_name ) - mock_set_custom_metric.assert_called_once_with('request_jwt_cookie', 'missing-{}'.format(missing_cookie_name)) + mock_set_custom_attribute.assert_called_once_with( + 'request_jwt_cookie', 'missing-{}'.format(missing_cookie_name) + ) - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_no_cookies(self, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_no_cookies(self, mock_set_custom_attribute): self.request.META[USE_JWT_COOKIE_HEADER] = 'true' self.middleware.process_view(self.request, None, None, None) self.assertIsNone(self.request.COOKIES.get(jwt_cookie_name())) - mock_set_custom_metric.assert_called_once_with('request_jwt_cookie', 'missing-both') + mock_set_custom_attribute.assert_called_once_with('request_jwt_cookie', 'missing-both') - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_success(self, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_success(self, mock_set_custom_attribute): self.request.META[USE_JWT_COOKIE_HEADER] = 'true' self.request.COOKIES[jwt_cookie_header_payload_name()] = 'header.payload' self.request.COOKIES[jwt_cookie_signature_name()] = 'signature' self.middleware.process_view(self.request, None, None, None) self.assertEqual(self.request.COOKIES[jwt_cookie_name()], 'header.payload.signature') - mock_set_custom_metric.assert_called_once_with('request_jwt_cookie', 'success') + mock_set_custom_attribute.assert_called_once_with('request_jwt_cookie', 'success') _LOG_WARN_AUTHENTICATION_FAILED = 0 _LOG_WARN_MISSING_JWT_AUTHENTICATION_CLASS = 1 diff --git a/edx_rest_framework_extensions/middleware.py b/edx_rest_framework_extensions/middleware.py index b73213d7..ae678d09 100644 --- a/edx_rest_framework_extensions/middleware.py +++ b/edx_rest_framework_extensions/middleware.py @@ -1,6 +1,8 @@ """ Middleware to ensure best practices of DRF and other endpoints. """ +import warnings + from django.utils.deprecation import MiddlewareMixin from edx_django_utils import monitoring from edx_django_utils.cache import DEFAULT_REQUEST_CACHE @@ -9,14 +11,14 @@ from edx_rest_framework_extensions.auth.jwt.cookies import jwt_cookie_name -class RequestMetricsMiddleware(MiddlewareMixin): +class RequestCustomAttributesMiddleware(MiddlewareMixin): """ - Adds various request related metrics. + Adds various request related custom attributes. - Possible metrics include: + Possible custom attributes include: request_authenticated_user_set_in_middleware: Example values: 'process_request', 'process_view', 'process_response', - or 'process_exception'. Metric won't exist if user is not authenticated. + or 'process_exception'. Attribute won't exist if user is not authenticated. request_auth_type_guess: Example values include: no-user, unauthenticated, jwt, bearer, other-token-type, jwt-cookie, or session-or-other Note: These are just guesses because if a token was expired, for example, @@ -31,7 +33,7 @@ class RequestMetricsMiddleware(MiddlewareMixin): MIDDLEWARE = ( 'edx_django_utils.cache.middleware.RequestCacheMiddleware', - 'edx_rest_framework_extensions.middleware.RequestMetricsMiddleware', + 'edx_rest_framework_extensions.middleware.RequestCustomAttributesMiddleware', ) This middleware should also appear after any authentication middleware. @@ -51,10 +53,10 @@ def process_view(self, request, view_func, view_args, view_kwargs): # pylint: d def process_response(self, request, response): """ - Add metrics for various details of the request. + Add custom attributes for various details of the request. """ self._cache_if_authenticated_user_found_in_middleware(request, 'process_response') - self._set_all_request_metrics(request) + self._set_all_request_attributes(request) return response def process_exception(self, request, exception): # pylint: disable=unused-argument @@ -62,57 +64,57 @@ def process_exception(self, request, exception): # pylint: disable=unused-argum Django middleware handler to process an exception """ self._cache_if_authenticated_user_found_in_middleware(request, 'process_exception') - self._set_all_request_metrics(request) + self._set_all_request_attributes(request) - def _set_all_request_metrics(self, request): + def _set_all_request_attributes(self, request): """ - Sets all the request metrics + Sets all the request custom attributes """ - self._set_request_auth_type_guess_metric(request) - self._set_request_user_agent_metrics(request) - self._set_request_referer_metric(request) - self._set_request_user_id_metric(request) - self._set_request_authenticated_user_found_in_middleware_metric() + self._set_request_auth_type_guess_attribute(request) + self._set_request_user_agent_attributes(request) + self._set_request_referer_attribute(request) + self._set_request_user_id_attribute(request) + self._set_request_authenticated_user_found_in_middleware_attribute() - def _set_request_user_id_metric(self, request): + def _set_request_user_id_attribute(self, request): """ - Add request_user_id metric + Add request_user_id custom attribute - Metrics: + Custom Attributes: request_user_id """ if hasattr(request, 'user') and hasattr(request.user, 'id') and request.user.id: - monitoring.set_custom_metric('request_user_id', request.user.id) + monitoring.set_custom_attribute('request_user_id', request.user.id) - def _set_request_referer_metric(self, request): + def _set_request_referer_attribute(self, request): """ - Add metric 'request_referer' for http referer. + Add custom attribute 'request_referer' for http referer. """ if 'HTTP_REFERER' in request.META and request.META['HTTP_REFERER']: - monitoring.set_custom_metric('request_referer', request.META['HTTP_REFERER']) + monitoring.set_custom_attribute('request_referer', request.META['HTTP_REFERER']) - def _set_request_user_agent_metrics(self, request): + def _set_request_user_agent_attributes(self, request): """ - Add metrics for user agent for python. + Add custom attributes for user agent for python. - Metrics: + Custom Attributes: request_user_agent request_client_name: The client name from edx-rest-api-client calls. """ if 'HTTP_USER_AGENT' in request.META and request.META['HTTP_USER_AGENT']: user_agent = request.META['HTTP_USER_AGENT'] - monitoring.set_custom_metric('request_user_agent', user_agent) + monitoring.set_custom_attribute('request_user_agent', user_agent) if user_agent: # Example agent string from edx-rest-api-client: # python-requests/2.9.1 edx-rest-api-client/1.7.2 ecommerce # See https://github.com/edx/edx-rest-api-client/commit/692903c30b157f7a4edabc2f53aae1742db3a019 user_agent_parts = user_agent.split() if len(user_agent_parts) == 3 and user_agent_parts[1].startswith('edx-rest-api-client/'): - monitoring.set_custom_metric('request_client_name', user_agent_parts[2]) + monitoring.set_custom_attribute('request_client_name', user_agent_parts[2]) - def _set_request_auth_type_guess_metric(self, request): + def _set_request_auth_type_guess_attribute(self, request): """ - Add metric 'request_auth_type_guess' for the authentication type used. + Add custom attribute 'request_auth_type_guess' for the authentication type used. NOTE: This is a best guess at this point. Possible values include: no-user @@ -137,17 +139,17 @@ def _set_request_auth_type_guess_metric(self, request): auth_type = 'jwt-cookie' else: auth_type = 'session-or-other' - monitoring.set_custom_metric('request_auth_type_guess', auth_type) + monitoring.set_custom_attribute('request_auth_type_guess', auth_type) AUTHENTICATED_USER_FOUND_CACHE_KEY = 'edx-drf-extensions.authenticated_user_found_in_middleware' - def _set_request_authenticated_user_found_in_middleware_metric(self): + def _set_request_authenticated_user_found_in_middleware_attribute(self): """ - Add metric 'request_authenticated_user_found_in_middleware' if authenticated user was found. + Add custom attribute 'request_authenticated_user_found_in_middleware' if authenticated user was found. """ cached_response = DEFAULT_REQUEST_CACHE.get_cached_response(self.AUTHENTICATED_USER_FOUND_CACHE_KEY) if cached_response.is_found: - monitoring.set_custom_metric( + monitoring.set_custom_attribute( 'request_authenticated_user_found_in_middleware', cached_response.value ) @@ -164,3 +166,13 @@ def _cache_if_authenticated_user_found_in_middleware(self, request, value): if hasattr(request, 'user') and request.user and request.user.is_authenticated: DEFAULT_REQUEST_CACHE.set(self.AUTHENTICATED_USER_FOUND_CACHE_KEY, value) + + +class RequestMetricsMiddleware(RequestCustomAttributesMiddleware): + """ + Deprecated class for handling middleware. Class has been renamed to RequestCustomAttributesMiddleware. + """ + def __init__(self, *args, **kwargs): + super(RequestMetricsMiddleware, self).__init__(*args, **kwargs) + msg = "Use 'RequestCustomAttributesMiddleware' in place of 'RequestMetricsMiddleware'." + warnings.warn(msg, DeprecationWarning) diff --git a/edx_rest_framework_extensions/tests/test_middleware.py b/edx_rest_framework_extensions/tests/test_middleware.py index 3d79c509..1e4d941e 100644 --- a/edx_rest_framework_extensions/tests/test_middleware.py +++ b/edx_rest_framework_extensions/tests/test_middleware.py @@ -9,42 +9,45 @@ from edx_rest_framework_extensions.auth.jwt.constants import USE_JWT_COOKIE_HEADER from edx_rest_framework_extensions.auth.jwt.cookies import jwt_cookie_name -from edx_rest_framework_extensions.middleware import RequestMetricsMiddleware +from edx_rest_framework_extensions.middleware import ( + RequestCustomAttributesMiddleware, + RequestMetricsMiddleware, +) from edx_rest_framework_extensions.tests.factories import UserFactory @ddt.ddt -class TestRequestMetricsMiddleware(TestCase): +class TestRequestCustomAttributesMiddleware(TestCase): def setUp(self): - super(TestRequestMetricsMiddleware, self).setUp() + super(TestRequestCustomAttributesMiddleware, self).setUp() RequestCache.clear_all_namespaces() self.request = RequestFactory().get('/') - self.middleware = RequestMetricsMiddleware() + self.middleware = RequestCustomAttributesMiddleware() - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_request_auth_type_guess_anonymous_metric(self, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_request_auth_type_guess_anonymous_attribute(self, mock_set_custom_attribute): self.request.user = AnonymousUser() self.middleware.process_response(self.request, None) - mock_set_custom_metric.assert_called_once_with('request_auth_type_guess', 'unauthenticated') + mock_set_custom_attribute.assert_called_once_with('request_auth_type_guess', 'unauthenticated') - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_request_no_headers(self, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_request_no_headers(self, mock_set_custom_attribute): self.request.user = None self.middleware.process_response(self.request, None) - mock_set_custom_metric.assert_called_once_with('request_auth_type_guess', 'no-user') + mock_set_custom_attribute.assert_called_once_with('request_auth_type_guess', 'no-user') - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_request_blank_headers(self, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_request_blank_headers(self, mock_set_custom_attribute): self.request.META['HTTP_USER_AGENT'] = '' self.request.META['HTTP_REFERER'] = '' self.request.META['HTTP_AUTHORIZATION'] = '' self.middleware.process_response(self.request, None) - mock_set_custom_metric.assert_called_once_with('request_auth_type_guess', 'no-user') + mock_set_custom_attribute.assert_called_once_with('request_auth_type_guess', 'no-user') - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_request_referer_metric(self, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_request_referer_attribute(self, mock_set_custom_attribute): self.request.META['HTTP_REFERER'] = 'test-http-referer' self.middleware.process_response(self.request, None) @@ -52,10 +55,10 @@ def test_request_referer_metric(self, mock_set_custom_metric): call('request_referer', 'test-http-referer'), call('request_auth_type_guess', 'no-user'), ] - mock_set_custom_metric.assert_has_calls(expected_calls, any_order=True) + mock_set_custom_attribute.assert_has_calls(expected_calls, any_order=True) - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_request_rest_client_user_agent_metrics(self, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_request_rest_client_user_agent_attributes(self, mock_set_custom_attribute): self.request.META['HTTP_USER_AGENT'] = 'python-requests/2.9.1 edx-rest-api-client/1.7.2 test-client' self.middleware.process_response(self.request, None) @@ -64,10 +67,10 @@ def test_request_rest_client_user_agent_metrics(self, mock_set_custom_metric): call('request_client_name', 'test-client'), call('request_auth_type_guess', 'no-user'), ] - mock_set_custom_metric.assert_has_calls(expected_calls, any_order=True) + mock_set_custom_attribute.assert_has_calls(expected_calls, any_order=True) - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_request_standard_user_agent_metrics(self, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_request_standard_user_agent_attributes(self, mock_set_custom_attribute): self.request.META['HTTP_USER_AGENT'] = 'test-user-agent' self.middleware.process_response(self.request, None) @@ -75,7 +78,7 @@ def test_request_standard_user_agent_metrics(self, mock_set_custom_metric): call('request_user_agent', 'test-user-agent'), call('request_auth_type_guess', 'no-user'), ] - mock_set_custom_metric.assert_has_calls(expected_calls, any_order=True) + mock_set_custom_attribute.assert_has_calls(expected_calls, any_order=True) @ddt.data( ('jwt abcdefg', 'jwt'), @@ -83,88 +86,110 @@ def test_request_standard_user_agent_metrics(self, mock_set_custom_metric): ('abcdefg', 'other-token-type'), ) @ddt.unpack - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_request_auth_type_guess_token_metric(self, token, expected_token_type, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_request_auth_type_guess_token_attribute(self, token, expected_token_type, mock_set_custom_attribute): self.request.user = UserFactory() self.request.META['HTTP_AUTHORIZATION'] = token self.middleware.process_response(self.request, None) - mock_set_custom_metric.assert_any_call('request_auth_type_guess', expected_token_type) + mock_set_custom_attribute.assert_any_call('request_auth_type_guess', expected_token_type) - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_request_auth_type_guess_jwt_cookie_metric(self, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_request_auth_type_guess_jwt_cookie_attribute(self, mock_set_custom_attribute): self.request.user = UserFactory() self.request.META[USE_JWT_COOKIE_HEADER] = True self.request.COOKIES[jwt_cookie_name()] = 'reconstituted-jwt-cookie' self.middleware.process_response(self.request, None) - mock_set_custom_metric.assert_any_call('request_auth_type_guess', 'jwt-cookie') + mock_set_custom_attribute.assert_any_call('request_auth_type_guess', 'jwt-cookie') - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_request_auth_type_guess_session_metric(self, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_request_auth_type_guess_session_attribute(self, mock_set_custom_attribute): self.request.user = UserFactory() self.middleware.process_response(self.request, None) - mock_set_custom_metric.assert_any_call('request_auth_type_guess', 'session-or-other') + mock_set_custom_attribute.assert_any_call('request_auth_type_guess', 'session-or-other') - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_request_user_id_metric(self, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_request_user_id_attribute(self, mock_set_custom_attribute): self.request.user = UserFactory() self.middleware.process_response(self.request, None) - mock_set_custom_metric.assert_any_call('request_user_id', self.request.user.id) - mock_set_custom_metric.assert_any_call( + mock_set_custom_attribute.assert_any_call('request_user_id', self.request.user.id) + mock_set_custom_attribute.assert_any_call( 'request_authenticated_user_found_in_middleware', 'process_response' ) - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_request_user_id_metric_with_exception(self, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_request_user_id_attribute_with_exception(self, mock_set_custom_attribute): self.request.user = UserFactory() self.middleware.process_exception(self.request, None) - mock_set_custom_metric.assert_any_call('request_user_id', self.request.user.id) - mock_set_custom_metric.assert_any_call( + mock_set_custom_attribute.assert_any_call('request_user_id', self.request.user.id) + mock_set_custom_attribute.assert_any_call( 'request_authenticated_user_found_in_middleware', 'process_exception' ) - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_authenticated_user_found_in_process_request(self, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_authenticated_user_found_in_process_request(self, mock_set_custom_attribute): self.request.user = UserFactory() self.middleware.process_request(self.request) self.middleware.process_response(self.request, None) - mock_set_custom_metric.assert_any_call( + mock_set_custom_attribute.assert_any_call( 'request_authenticated_user_found_in_middleware', 'process_request' ) - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_authenticated_user_found_in_process_view(self, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_authenticated_user_found_in_process_view(self, mock_set_custom_attribute): self.request.user = UserFactory() self.middleware.process_view(self.request, None, None, None) self.middleware.process_response(self.request, None) - mock_set_custom_metric.assert_any_call( + mock_set_custom_attribute.assert_any_call( 'request_authenticated_user_found_in_middleware', 'process_view' ) - @patch('edx_django_utils.monitoring.set_custom_metric') - def test_authenticated_user_found_is_properly_reset(self, mock_set_custom_metric): + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_authenticated_user_found_is_properly_reset(self, mock_set_custom_attribute): # set user before process_request self.request.user = UserFactory() self.middleware.process_request(self.request) self.middleware.process_response(self.request, None) - mock_set_custom_metric.assert_any_call( + mock_set_custom_attribute.assert_any_call( 'request_authenticated_user_found_in_middleware', 'process_request' ) # set up new request and set user before process_response - mock_set_custom_metric.reset_mock() + mock_set_custom_attribute.reset_mock() RequestCache.clear_all_namespaces() self.request = RequestFactory().get('/') self.request.user = UserFactory() self.middleware.process_response(self.request, None) - mock_set_custom_metric.assert_any_call( + mock_set_custom_attribute.assert_any_call( 'request_authenticated_user_found_in_middleware', 'process_response' ) + + +@ddt.ddt +class TestRequestMetricsMiddleware(TestCase): + """ + Temporary smoke test of deprecated RequestMetricsMiddleware. + + The deprecated class is a subclass of RequestCustomAttributesMiddleware, + which is more fully tested. + """ + def setUp(self): + super(TestRequestMetricsMiddleware, self).setUp() + RequestCache.clear_all_namespaces() + self.request = RequestFactory().get('/') + self.middleware = RequestMetricsMiddleware() + + @patch('edx_django_utils.monitoring.set_custom_attribute') + def test_request_auth_type_guess_anonymous_attribute(self, mock_set_custom_attribute): + self.request.user = AnonymousUser() + + self.middleware.process_response(self.request, None) + mock_set_custom_attribute.assert_called_once_with('request_auth_type_guess', 'unauthenticated') diff --git a/requirements/base.in b/requirements/base.in index e97b8752..d8ac7428 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -4,7 +4,7 @@ Django>=2.2 djangorestframework>=3.2.0 drf-jwt django-waffle -edx-django-utils +edx-django-utils>=3.8.0 # using new set_custom_attribute method edx-opaque-keys pyjwkest python-dateutil>=2.0 diff --git a/requirements/base.txt b/requirements/base.txt index 81f778ac..7453ef01 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -5,25 +5,25 @@ # make upgrade # certifi==2020.6.20 # via requests -cffi==1.14.0 # via cryptography +cffi==1.14.3 # via cryptography chardet==3.0.4 # via requests -cryptography==2.9.2 # via pyjwt -django-waffle==1.0.0 # via -r requirements/base.in, edx-django-utils -django==2.2.13 # via -c requirements/constraints.txt, -r requirements/base.in, djangorestframework, drf-jwt, edx-django-utils, rest-condition -djangorestframework==3.11.0 # via -r requirements/base.in, drf-jwt, rest-condition -drf-jwt==1.16.2 # via -r requirements/base.in -edx-django-utils==3.2.3 # via -r requirements/base.in -edx-opaque-keys==2.1.0 # via -r requirements/base.in +cryptography==3.1.1 # via pyjwt +django-waffle==2.0.0 # via -r requirements/base.in, edx-django-utils +django==2.2.16 # via -c requirements/constraints.txt, -r requirements/base.in, djangorestframework, drf-jwt, edx-django-utils, rest-condition +djangorestframework==3.11.1 # via -r requirements/base.in, drf-jwt, rest-condition +drf-jwt==1.17.2 # via -r requirements/base.in +edx-django-utils==3.8.0 # via -r requirements/base.in +edx-opaque-keys==2.1.1 # via -r requirements/base.in future==0.18.2 # via pyjwkest -idna==2.9 # via requests -newrelic==5.14.1.144 # via edx-django-utils -pbr==5.4.5 # via stevedore -psutil==1.2.1 # via edx-django-utils +idna==2.10 # via requests +newrelic==5.20.0.149 # via edx-django-utils +pbr==5.5.0 # via stevedore +psutil==5.7.2 # via edx-django-utils pycparser==2.20 # via cffi pycryptodomex==3.9.8 # via pyjwkest pyjwkest==1.4.2 # via -r requirements/base.in pyjwt[crypto]==1.7.1 # via drf-jwt -pymongo==3.10.1 # via edx-opaque-keys +pymongo==3.11.0 # via edx-opaque-keys python-dateutil==2.8.1 # via -r requirements/base.in pytz==2020.1 # via django requests==2.24.0 # via -r requirements/base.in, pyjwkest @@ -31,5 +31,5 @@ rest-condition==1.0.3 # via -r requirements/base.in semantic-version==2.8.5 # via -r requirements/base.in six==1.15.0 # via -r requirements/base.in, cryptography, edx-opaque-keys, pyjwkest, python-dateutil, stevedore sqlparse==0.3.1 # via django -stevedore==1.32.0 # via edx-opaque-keys -urllib3==1.25.9 # via requests +stevedore==1.32.0 # via edx-django-utils, edx-opaque-keys +urllib3==1.25.10 # via requests diff --git a/requirements/dev.txt b/requirements/dev.txt index e8723c85..84a6491b 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -7,63 +7,64 @@ alabaster==0.7.12 # via -r requirements/docs.txt, sphinx appdirs==1.4.4 # via -r requirements/test.txt, virtualenv astroid==2.3.3 # via -r requirements/test.txt, pylint, pylint-celery -attrs==19.3.0 # via -r requirements/test.txt, pytest +attrs==20.2.0 # via -r requirements/test.txt, pytest babel==2.8.0 # via -r requirements/docs.txt, sphinx certifi==2020.6.20 # via -r requirements/base.txt, -r requirements/docs.txt, -r requirements/test.txt, requests -cffi==1.14.0 # via -r requirements/base.txt, -r requirements/test.txt, cryptography +cffi==1.14.3 # via -r requirements/base.txt, -r requirements/test.txt, cryptography chardet==3.0.4 # via -r requirements/base.txt, -r requirements/docs.txt, -r requirements/test.txt, requests click-log==0.3.2 # via -r requirements/test.txt, edx-lint click==7.1.2 # via -r requirements/test.txt, click-log, edx-lint coverage==4.5.4 # via -r requirements/test.txt, pytest-cov -cryptography==2.9.2 # via -r requirements/base.txt, -r requirements/test.txt, pyjwt +cryptography==3.1.1 # via -r requirements/base.txt, -r requirements/test.txt, pyjwt ddt==1.4.1 # via -r requirements/test.txt -distlib==0.3.0 # via -r requirements/test.txt, virtualenv -django-waffle==1.0.0 # via -r requirements/base.txt, -r requirements/test.txt, edx-django-utils -django==2.2.13 # via -c requirements/constraints.txt, -r requirements/base.txt, -r requirements/test.txt, djangorestframework, drf-jwt, edx-django-utils, rest-condition -djangorestframework==3.11.0 # via -r requirements/base.txt, -r requirements/test.txt, drf-jwt, rest-condition +distlib==0.3.1 # via -r requirements/test.txt, virtualenv +django-waffle==2.0.0 # via -r requirements/base.txt, -r requirements/test.txt, edx-django-utils +django==2.2.16 # via -c requirements/constraints.txt, -r requirements/base.txt, -r requirements/test.txt, djangorestframework, drf-jwt, edx-django-utils, rest-condition +djangorestframework==3.11.1 # via -r requirements/base.txt, -r requirements/test.txt, drf-jwt, rest-condition docutils==0.16 # via -r requirements/docs.txt, sphinx -drf-jwt==1.16.2 # via -r requirements/base.txt, -r requirements/test.txt -edx-django-utils==3.2.3 # via -r requirements/base.txt, -r requirements/test.txt -edx-lint==1.4.1 # via -r requirements/test.txt -edx-opaque-keys==2.1.0 # via -r requirements/base.txt, -r requirements/test.txt +drf-jwt==1.17.2 # via -r requirements/base.txt, -r requirements/test.txt +edx-django-utils==3.8.0 # via -r requirements/base.txt, -r requirements/test.txt +edx-lint==1.5.2 # via -r requirements/test.txt +edx-opaque-keys==2.1.1 # via -r requirements/base.txt, -r requirements/test.txt factory-boy==2.12.0 # via -r requirements/test.txt -faker==4.1.1 # via -r requirements/test.txt, factory-boy +faker==4.1.3 # via -r requirements/test.txt, factory-boy filelock==3.0.12 # via -r requirements/test.txt, virtualenv future==0.18.2 # via -r requirements/base.txt, -r requirements/test.txt, pyjwkest httpretty==0.9.7 # via -r requirements/test.txt -idna==2.9 # via -r requirements/base.txt, -r requirements/docs.txt, -r requirements/test.txt, requests +idna==2.10 # via -r requirements/base.txt, -r requirements/docs.txt, -r requirements/test.txt, requests imagesize==1.2.0 # via -r requirements/docs.txt, sphinx -importlib-metadata==1.6.1 # via -r requirements/test.txt, importlib-resources, pluggy, pytest, virtualenv -importlib-resources==2.0.1 # via -r requirements/test.txt, virtualenv +importlib-metadata==1.7.0 # via -r requirements/test.txt, pluggy, pytest, virtualenv +importlib-resources==3.0.0 # via -r requirements/test.txt, virtualenv +iniconfig==1.0.1 # via -r requirements/test.txt, pytest isort==4.3.21 # via -r requirements/test.txt, pylint jinja2==2.11.2 # via -r requirements/docs.txt, sphinx lazy-object-proxy==1.4.3 # via -r requirements/test.txt, astroid markupsafe==1.1.1 # via -r requirements/docs.txt, jinja2 mccabe==0.6.1 # via -r requirements/test.txt, pylint mock==1.3.0 # via -r requirements/test.txt -more-itertools==8.4.0 # via -r requirements/test.txt, pytest -newrelic==5.14.1.144 # via -r requirements/base.txt, -r requirements/test.txt, edx-django-utils +more-itertools==8.5.0 # via -r requirements/test.txt, pytest +newrelic==5.20.0.149 # via -r requirements/base.txt, -r requirements/test.txt, edx-django-utils packaging==20.4 # via -r requirements/docs.txt, -r requirements/test.txt, pytest, sphinx pathlib2==2.3.5 # via -r requirements/test.txt, pytest -pbr==5.4.5 # via -r requirements/base.txt, -r requirements/test.txt, mock, stevedore +pbr==5.5.0 # via -r requirements/base.txt, -r requirements/test.txt, mock, stevedore pluggy==0.13.1 # via -r requirements/test.txt, pytest, tox -psutil==1.2.1 # via -r requirements/base.txt, -r requirements/test.txt, edx-django-utils +psutil==5.7.2 # via -r requirements/base.txt, -r requirements/test.txt, edx-django-utils py==1.9.0 # via -r requirements/test.txt, pytest, tox pycodestyle==2.6.0 # via -r requirements/test.txt pycparser==2.20 # via -r requirements/base.txt, -r requirements/test.txt, cffi pycryptodomex==3.9.8 # via -r requirements/base.txt, -r requirements/test.txt, pyjwkest -pygments==2.6.1 # via -r requirements/docs.txt, sphinx +pygments==2.7.1 # via -r requirements/docs.txt, sphinx pyjwkest==1.4.2 # via -r requirements/base.txt, -r requirements/test.txt pyjwt[crypto]==1.7.1 # via -r requirements/base.txt, -r requirements/test.txt, drf-jwt pylint-celery==0.3 # via -r requirements/test.txt, edx-lint pylint-django==2.0.11 # via -r requirements/test.txt, edx-lint pylint-plugin-utils==0.6 # via -r requirements/test.txt, pylint-celery, pylint-django -pylint==2.4.2 # via -r requirements/test.txt, edx-lint, pylint-celery, pylint-django, pylint-plugin-utils -pymongo==3.10.1 # via -r requirements/base.txt, -r requirements/test.txt, edx-opaque-keys +pylint==2.4.4 # via -r requirements/test.txt, edx-lint, pylint-celery, pylint-django, pylint-plugin-utils +pymongo==3.11.0 # via -r requirements/base.txt, -r requirements/test.txt, edx-opaque-keys pyparsing==2.4.7 # via -r requirements/docs.txt, -r requirements/test.txt, packaging -pytest-cov==2.10.0 # via -r requirements/test.txt -pytest-django==3.9.0 # via -r requirements/test.txt -pytest==5.4.3 # via -r requirements/test.txt, pytest-cov, pytest-django +pytest-cov==2.10.1 # via -r requirements/test.txt +pytest-django==3.10.0 # via -r requirements/test.txt +pytest==6.0.2 # via -r requirements/test.txt, pytest-cov, pytest-django python-dateutil==2.8.1 # via -r requirements/base.txt, -r requirements/test.txt, faker pytz==2020.1 # via -r requirements/base.txt, -r requirements/docs.txt, -r requirements/test.txt, babel, django requests==2.24.0 # via -r requirements/base.txt, -r requirements/docs.txt, -r requirements/test.txt, pyjwkest, sphinx @@ -72,7 +73,7 @@ semantic-version==2.8.5 # via -r requirements/base.txt, -r requirements/test.t six==1.15.0 # via -r requirements/base.txt, -r requirements/docs.txt, -r requirements/test.txt, astroid, cryptography, edx-lint, edx-opaque-keys, httpretty, mock, packaging, pathlib2, pyjwkest, python-dateutil, stevedore, tox, virtualenv snowballstemmer==2.0.0 # via -r requirements/docs.txt, sphinx sphinx-rtd-theme==0.5.0 # via -r requirements/docs.txt -sphinx==3.1.1 # via -r requirements/docs.txt, sphinx-rtd-theme +sphinx==3.2.1 # via -r requirements/docs.txt, sphinx-rtd-theme sphinxcontrib-applehelp==1.0.2 # via -r requirements/docs.txt, sphinx sphinxcontrib-devhelp==1.0.2 # via -r requirements/docs.txt, sphinx sphinxcontrib-htmlhelp==1.0.3 # via -r requirements/docs.txt, sphinx @@ -80,13 +81,13 @@ sphinxcontrib-jsmath==1.0.1 # via -r requirements/docs.txt, sphinx sphinxcontrib-qthelp==1.0.3 # via -r requirements/docs.txt, sphinx sphinxcontrib-serializinghtml==1.1.4 # via -r requirements/docs.txt, sphinx sqlparse==0.3.1 # via -r requirements/base.txt, -r requirements/test.txt, django -stevedore==1.32.0 # via -r requirements/base.txt, -r requirements/test.txt, edx-opaque-keys +stevedore==1.32.0 # via -r requirements/base.txt, -r requirements/test.txt, edx-django-utils, edx-opaque-keys text-unidecode==1.3 # via -r requirements/test.txt, faker +toml==0.10.1 # via -r requirements/test.txt, pytest tox==2.9.1 # via -r requirements/test.txt typed-ast==1.4.1 # via -r requirements/test.txt, astroid -urllib3==1.25.9 # via -r requirements/base.txt, -r requirements/docs.txt, -r requirements/test.txt, requests -virtualenv==20.0.25 # via -r requirements/test.txt, tox -wcwidth==0.2.5 # via -r requirements/test.txt, pytest +urllib3==1.25.10 # via -r requirements/base.txt, -r requirements/docs.txt, -r requirements/test.txt, requests +virtualenv==20.0.31 # via -r requirements/test.txt, tox wrapt==1.11.2 # via -r requirements/test.txt, astroid zipp==1.2.0 # via -r requirements/test.txt, importlib-metadata, importlib-resources diff --git a/requirements/docs.txt b/requirements/docs.txt index 89675974..a4a94140 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -9,26 +9,26 @@ babel==2.8.0 # via sphinx certifi==2020.6.20 # via -c requirements/test.txt, requests chardet==3.0.4 # via -c requirements/test.txt, requests docutils==0.16 # via sphinx -idna==2.9 # via -c requirements/test.txt, requests +idna==2.10 # via -c requirements/test.txt, requests imagesize==1.2.0 # via sphinx jinja2==2.11.2 # via sphinx markupsafe==1.1.1 # via jinja2 packaging==20.4 # via -c requirements/test.txt, sphinx -pygments==2.6.1 # via sphinx +pygments==2.7.1 # via sphinx pyparsing==2.4.7 # via -c requirements/test.txt, packaging pytz==2020.1 # via -c requirements/test.txt, babel requests==2.24.0 # via -c requirements/test.txt, sphinx six==1.15.0 # via -c requirements/test.txt, packaging snowballstemmer==2.0.0 # via sphinx sphinx-rtd-theme==0.5.0 # via -r requirements/docs.in -sphinx==3.1.1 # via -r requirements/docs.in, sphinx-rtd-theme +sphinx==3.2.1 # via -r requirements/docs.in, sphinx-rtd-theme sphinxcontrib-applehelp==1.0.2 # via sphinx sphinxcontrib-devhelp==1.0.2 # via sphinx sphinxcontrib-htmlhelp==1.0.3 # via sphinx sphinxcontrib-jsmath==1.0.1 # via sphinx sphinxcontrib-qthelp==1.0.3 # via sphinx sphinxcontrib-serializinghtml==1.1.4 # via sphinx -urllib3==1.25.9 # via -c requirements/test.txt, requests +urllib3==1.25.10 # via -c requirements/test.txt, requests # The following packages are considered to be unsafe in a requirements file: # setuptools diff --git a/requirements/pip-tools.txt b/requirements/pip-tools.txt index 1ae2c19f..4b50eae7 100644 --- a/requirements/pip-tools.txt +++ b/requirements/pip-tools.txt @@ -5,7 +5,7 @@ # make upgrade # click==7.1.2 # via pip-tools -pip-tools==5.2.1 # via -r requirements/pip-tools.in +pip-tools==5.3.1 # via -r requirements/pip-tools.in six==1.15.0 # via pip-tools # The following packages are considered to be unsafe in a requirements file: diff --git a/requirements/test.txt b/requirements/test.txt index bd1c1039..25a2d26e 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -6,40 +6,41 @@ # appdirs==1.4.4 # via virtualenv astroid==2.3.3 # via pylint, pylint-celery -attrs==19.3.0 # via pytest +attrs==20.2.0 # via pytest certifi==2020.6.20 # via -r requirements/base.txt, requests -cffi==1.14.0 # via -r requirements/base.txt, cryptography +cffi==1.14.3 # via -r requirements/base.txt, cryptography chardet==3.0.4 # via -r requirements/base.txt, requests click-log==0.3.2 # via edx-lint click==7.1.2 # via click-log, edx-lint coverage==4.5.4 # via -r requirements/test.in, pytest-cov -cryptography==2.9.2 # via -r requirements/base.txt, pyjwt +cryptography==3.1.1 # via -r requirements/base.txt, pyjwt ddt==1.4.1 # via -r requirements/test.in -distlib==0.3.0 # via virtualenv -django-waffle==1.0.0 # via -r requirements/base.txt, edx-django-utils -drf-jwt==1.16.2 # via -r requirements/base.txt -edx-django-utils==3.2.3 # via -r requirements/base.txt -edx-lint==1.4.1 # via -r requirements/test.in -edx-opaque-keys==2.1.0 # via -r requirements/base.txt +distlib==0.3.1 # via virtualenv +django-waffle==2.0.0 # via -r requirements/base.txt, edx-django-utils +drf-jwt==1.17.2 # via -r requirements/base.txt +edx-django-utils==3.8.0 # via -r requirements/base.txt +edx-lint==1.5.2 # via -r requirements/test.in +edx-opaque-keys==2.1.1 # via -r requirements/base.txt factory-boy==2.12.0 # via -r requirements/test.in -faker==4.1.1 # via factory-boy +faker==4.1.3 # via factory-boy filelock==3.0.12 # via virtualenv future==0.18.2 # via -r requirements/base.txt, pyjwkest httpretty==0.9.7 # via -r requirements/test.in -idna==2.9 # via -r requirements/base.txt, requests -importlib-metadata==1.6.1 # via importlib-resources, pluggy, pytest, virtualenv -importlib-resources==2.0.1 # via virtualenv +idna==2.10 # via -r requirements/base.txt, requests +importlib-metadata==1.7.0 # via pluggy, pytest, virtualenv +importlib-resources==3.0.0 # via virtualenv +iniconfig==1.0.1 # via pytest isort==4.3.21 # via -r requirements/test.in, pylint lazy-object-proxy==1.4.3 # via astroid mccabe==0.6.1 # via pylint mock==1.3.0 # via -r requirements/test.in -more-itertools==8.4.0 # via pytest -newrelic==5.14.1.144 # via -r requirements/base.txt, edx-django-utils +more-itertools==8.5.0 # via pytest +newrelic==5.20.0.149 # via -r requirements/base.txt, edx-django-utils packaging==20.4 # via pytest pathlib2==2.3.5 # via pytest -pbr==5.4.5 # via -r requirements/base.txt, mock, stevedore +pbr==5.5.0 # via -r requirements/base.txt, mock, stevedore pluggy==0.13.1 # via pytest, tox -psutil==1.2.1 # via -r requirements/base.txt, edx-django-utils +psutil==5.7.2 # via -r requirements/base.txt, edx-django-utils py==1.9.0 # via pytest, tox pycodestyle==2.6.0 # via -r requirements/test.in pycparser==2.20 # via -r requirements/base.txt, cffi @@ -49,12 +50,12 @@ pyjwt[crypto]==1.7.1 # via -r requirements/base.txt, drf-jwt pylint-celery==0.3 # via edx-lint pylint-django==2.0.11 # via edx-lint pylint-plugin-utils==0.6 # via pylint-celery, pylint-django -pylint==2.4.2 # via edx-lint, pylint-celery, pylint-django, pylint-plugin-utils -pymongo==3.10.1 # via -r requirements/base.txt, edx-opaque-keys +pylint==2.4.4 # via edx-lint, pylint-celery, pylint-django, pylint-plugin-utils +pymongo==3.11.0 # via -r requirements/base.txt, edx-opaque-keys pyparsing==2.4.7 # via packaging -pytest-cov==2.10.0 # via -r requirements/test.in -pytest-django==3.9.0 # via -r requirements/test.in -pytest==5.4.3 # via pytest-cov, pytest-django +pytest-cov==2.10.1 # via -r requirements/test.in +pytest-django==3.10.0 # via -r requirements/test.in +pytest==6.0.2 # via pytest-cov, pytest-django python-dateutil==2.8.1 # via -r requirements/base.txt, faker pytz==2020.1 # via -r requirements/base.txt, django requests==2.24.0 # via -r requirements/base.txt, pyjwkest @@ -62,12 +63,12 @@ rest-condition==1.0.3 # via -r requirements/base.txt semantic-version==2.8.5 # via -r requirements/base.txt six==1.15.0 # via -r requirements/base.txt, astroid, cryptography, edx-lint, edx-opaque-keys, httpretty, mock, packaging, pathlib2, pyjwkest, python-dateutil, stevedore, tox, virtualenv sqlparse==0.3.1 # via -r requirements/base.txt, django -stevedore==1.32.0 # via -r requirements/base.txt, edx-opaque-keys +stevedore==1.32.0 # via -r requirements/base.txt, edx-django-utils, edx-opaque-keys text-unidecode==1.3 # via faker +toml==0.10.1 # via pytest tox==2.9.1 # via -r requirements/test.in typed-ast==1.4.1 # via astroid -urllib3==1.25.9 # via -r requirements/base.txt, requests -virtualenv==20.0.25 # via tox -wcwidth==0.2.5 # via pytest +urllib3==1.25.10 # via -r requirements/base.txt, requests +virtualenv==20.0.31 # via tox wrapt==1.11.2 # via astroid zipp==1.2.0 # via importlib-metadata, importlib-resources