From 3592f33f7feff135f4aab05e2a727a3c65b301c6 Mon Sep 17 00:00:00 2001 From: Douglas Rioux Date: Wed, 17 May 2023 16:39:39 -0400 Subject: [PATCH 1/4] Propagate request._stats and refactor a bit --- snovault/embed.py | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/snovault/embed.py b/snovault/embed.py index 176438b4d..3ce0eda9b 100644 --- a/snovault/embed.py +++ b/snovault/embed.py @@ -1,12 +1,14 @@ import logging from copy import deepcopy from posixpath import join +from typing import Union from pyramid.compat import ( native_, unquote_bytes_to_wsgi, ) from pyramid.httpexceptions import HTTPNotFound +from pyramid.request import Request from .interfaces import CONNECTION @@ -164,16 +166,7 @@ def _embed(request, path, as_user='EMBED'): """ # Carl: the subrequest is 'built' here, but not actually invoked subreq = make_subrequest(request, path) - # these attributes are propogated across the subrequest - subreq.override_renderer = 'null_renderer' - subreq._indexing_view = request._indexing_view - subreq._aggregate_for = request._aggregate_for - subreq._aggregated_items = request._aggregated_items - subreq._sid_cache = request._sid_cache - if as_user is not True: - if 'HTTP_COOKIE' in subreq.environ: - del subreq.environ['HTTP_COOKIE'] - subreq.remote_user = as_user + _set_subrequest_attributes(subreq, request, as_user=as_user) # _linked_uuids are populated in item_view_object of resource_views.py try: result = request.invoke_subrequest(subreq) @@ -190,6 +183,34 @@ def _embed(request, path, as_user='EMBED'): '_sid_cache': subreq._sid_cache} +def _set_subrequest_attributes( + subrequest: Request, request: Request, as_user: Union[str, bool] = False +) -> None: + subrequest.override_renderer = 'null_renderer' + _add_propagated_attributes(subrequest, request) + if as_user is not True: + _remove_http_cookie_and_set_user(subrequest, as_user) + + +def _add_propagated_attributes(subrequest: Request, request: Request) -> None: + subrequest._indexing_view = request._indexing_view + subrequest._aggregate_for = request._aggregate_for + subrequest._aggregated_items = request._aggregated_items + subrequest._sid_cache = request._sid_cache + try: + subrequest._stats = request._stats + except AttributeError: + subrequest._stats = {} + + +def _remove_http_cookie_and_set_user( + subrequest: Request, remote_user: Union[str, bool] +) -> None: + if 'HTTP_COOKIE' in subrequest.environ: + del subrequest.environ['HTTP_COOKIE'] + subrequest.remote_user = remote_user + + class NullRenderer: '''Sets result value directly as response. ''' From 8f1da008d1dd0676fca202bc843e75bbc7ac71ac Mon Sep 17 00:00:00 2001 From: Douglas Rioux Date: Wed, 17 May 2023 16:40:43 -0400 Subject: [PATCH 2/4] Bump beta version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index aa60a92ef..c0ca9df73 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "dcicsnovault" -version = "8.0.1" +version = "8.0.2b0" description = "Storage support for 4DN Data Portals." authors = ["4DN-DCIC Team "] license = "MIT" From 2ee0953bfccd3b2360ddee3bf946cef4358d068f Mon Sep 17 00:00:00 2001 From: Douglas Rioux Date: Wed, 17 May 2023 16:51:21 -0400 Subject: [PATCH 3/4] Change function name for consistency --- snovault/embed.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/snovault/embed.py b/snovault/embed.py index 3ce0eda9b..8ab3c5f8c 100644 --- a/snovault/embed.py +++ b/snovault/embed.py @@ -187,12 +187,12 @@ def _set_subrequest_attributes( subrequest: Request, request: Request, as_user: Union[str, bool] = False ) -> None: subrequest.override_renderer = 'null_renderer' - _add_propagated_attributes(subrequest, request) + _set_propagated_attributes(subrequest, request) if as_user is not True: _remove_http_cookie_and_set_user(subrequest, as_user) -def _add_propagated_attributes(subrequest: Request, request: Request) -> None: +def _set_propagated_attributes(subrequest: Request, request: Request) -> None: subrequest._indexing_view = request._indexing_view subrequest._aggregate_for = request._aggregate_for subrequest._aggregated_items = request._aggregated_items From 6a5ae02a86666b3f331b19853025febbbfda5af3 Mon Sep 17 00:00:00 2001 From: Douglas Rioux Date: Wed, 17 May 2023 17:46:05 -0400 Subject: [PATCH 4/4] Add tests for new functions --- snovault/tests/test_embed.py | 84 ++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 snovault/tests/test_embed.py diff --git a/snovault/tests/test_embed.py b/snovault/tests/test_embed.py new file mode 100644 index 000000000..0e969d479 --- /dev/null +++ b/snovault/tests/test_embed.py @@ -0,0 +1,84 @@ +from typing import Any, Dict, Optional, Union +from unittest.mock import create_autospec, Mock + +import pytest +from pyramid.request import Request + +from ..embed import _set_subrequest_attributes + + +DEFAULT_PARENT_REQUEST_ATTRIBUTES = { + "_indexing_view": "foo", + "_aggregate_for": "bar", + "_aggregated_items": "something", + "_sid_cache": "else", +} +DEFAULT_SUBREQUEST_ATTRIBUTES = {"environ": {"HTTP_COOKIE": "foobar", "fu": "bur"}} +DEFAULT_PROPAGATED_ATTRIBUTES = { + "override_renderer": "null_renderer", + "_stats": {}, + **DEFAULT_PARENT_REQUEST_ATTRIBUTES, +} + + +def _make_mock_request(attributes_to_set: Dict[str, Any]) -> Mock: + mock_request = create_autospec(Request, instance=True) + for attribute_name, attribute_value in attributes_to_set.items(): + setattr(mock_request, attribute_name, attribute_value) + return mock_request + + +def _make_mock_parent_request( + attributes_to_set: Optional[Dict[str, Any]] = None +) -> Mock: + if attributes_to_set is None: + attributes_to_set = {} + attributes_to_set.update(DEFAULT_PARENT_REQUEST_ATTRIBUTES) + return _make_mock_request(attributes_to_set) + + +def _make_mock_subrequest() -> Mock: + return _make_mock_request(DEFAULT_SUBREQUEST_ATTRIBUTES) + + +@pytest.mark.parametrize( + "subrequest,parent_request,as_user,expected_attributes", + [ + ( + _make_mock_subrequest(), + _make_mock_parent_request(), + True, + {**DEFAULT_PROPAGATED_ATTRIBUTES, **DEFAULT_SUBREQUEST_ATTRIBUTES}, + ), + ( + _make_mock_subrequest(), + _make_mock_parent_request({"_stats": "some_stats"}), + True, + { + **DEFAULT_PROPAGATED_ATTRIBUTES, + **DEFAULT_SUBREQUEST_ATTRIBUTES, + "_stats": "some_stats", + }, + ), + ( + _make_mock_subrequest(), + _make_mock_parent_request(), + False, + { + **DEFAULT_PROPAGATED_ATTRIBUTES, + **DEFAULT_SUBREQUEST_ATTRIBUTES, + "environ": {"fu": "bur"}, + "remote_user": False, + }, + ), + ], +) +def test_set_subrequest_attributes( + subrequest: Mock, + parent_request: Mock, + as_user: Union[bool, str], + expected_attributes: Dict[str, Any], +) -> None: + _set_subrequest_attributes(subrequest, parent_request, as_user=as_user) + for attribute_name, attribute_value in expected_attributes.items(): + assert getattr(subrequest, attribute_name) == attribute_value