Skip to content

Commit

Permalink
MAINT: Rework init for query objects
Browse files Browse the repository at this point in the history
Reworks the Query objects to simplify the init chain. Just make copies
where we need them instead of passing around multiple things in big
chains.

Further simplification will appear in a future commit to extract the
factory out
  • Loading branch information
DavidFair committed Sep 15, 2023
1 parent a464d3f commit c1fe218
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 52 deletions.
13 changes: 5 additions & 8 deletions lib/openstack_query/queries/query_wrapper.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
from enums.query.props.prop_enum import PropEnum
from openstack_query.query_output import QueryOutput
from openstack_query.query_builder import QueryBuilder
from openstack_query.query_parser import QueryParser

from openstack_query.query_methods import QueryMethods
from openstack_query.query_base import QueryBase
from openstack_query.runners.query_runner import QueryRunner


# pylint:disable=too-few-public-methods
Expand All @@ -18,18 +16,17 @@ class QueryWrapper(QueryMethods, QueryBase):
QueryWrapper is a base class for all Query<Resource> subclasses
"""

def __init__(self, query_runner: QueryRunner, prop_enum_cls: PropEnum):
self.runner = query_runner
self.output = QueryOutput(prop_enum_cls)
self.parser = QueryParser(prop_enum_cls)
def __init__(self):
self.output = QueryOutput(self.prop_mapping)
self.parser = QueryParser(self.prop_mapping)
self.builder = QueryBuilder(
prop_enum_cls,
self.prop_mapping,
self._get_client_side_handlers().to_list(),
self._get_server_side_handler(),
)
super().__init__(
builder=self.builder,
runner=self.runner,
runner=self.query_runner,
parser=self.parser,
output=self.output,
)
Expand Down
13 changes: 9 additions & 4 deletions lib/openstack_query/queries/server_query.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Type

from structs.query.query_client_side_handlers import QueryClientSideHandlers

from enums.query.props.server_properties import ServerProperties
Expand All @@ -22,17 +24,20 @@

from openstack_query.time_utils import TimeUtils

# pylint:disable=too-few-public-methods


class ServerQuery(QueryWrapper):
"""
Query class for querying Openstack Server objects.
Define property mappings, kwarg mappings and filter function mappings related to servers here
"""

prop_enum_cls = ServerProperties
runner_cls = ServerRunner
@property
def prop_mapping(self) -> Type[ServerProperties]:
return ServerProperties

@property
def query_runner(self) -> ServerRunner:
return ServerRunner(self.prop_mapping)

def _get_server_side_handler(self) -> ServerSideHandler:
"""
Expand Down
25 changes: 14 additions & 11 deletions lib/openstack_query/queries/user_query.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Type

from structs.query.query_client_side_handlers import QueryClientSideHandlers

from enums.query.props.user_properties import UserProperties
Expand All @@ -17,24 +19,25 @@
from openstack_query.runners.user_runner import UserRunner


# pylint:disable=too-few-public-methods


class UserQuery(QueryWrapper):
"""
Query class for querying Openstack User objects.
Define property mappings, kwarg mappings and filter function mappings related to users here
"""

def __init__(
self, prop_enum_cls: UserProperties = None, query_runner: UserRunner = None
):
prop_enum_cls = UserProperties if prop_enum_cls is None else prop_enum_cls
query_runner = (
UserRunner(prop_enum_cls) if query_runner is None else query_runner
)
@property
def prop_mapping(self) -> Type[UserProperties]:
"""
Property enum class for users
"""
return UserProperties

super().__init__(query_runner=query_runner, prop_enum_cls=prop_enum_cls)
@property
def query_runner(self) -> UserRunner:
"""
Constructs a QueryRunner class for users
"""
return UserRunner(self.prop_mapping)

def _get_server_side_handler(self) -> ServerSideHandler:
"""
Expand Down
21 changes: 19 additions & 2 deletions lib/openstack_query/query_base.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from abc import ABC, abstractmethod
from structs.query.query_client_side_handlers import QueryClientSideHandlers
from typing import Type
from typing import TypeVar

from openstack_query.handlers.server_side_handler import ServerSideHandler
from openstack_query.runners.query_runner import QueryRunner
from structs.query.query_client_side_handlers import QueryClientSideHandlers

# pylint:disable=too-few-public-methods
AnyPropEnum = TypeVar("AnyPropEnum", bound=Type["PropEnum"])


class QueryBase(ABC):
Expand All @@ -12,6 +15,20 @@ class QueryBase(ABC):
server-side, client-side and property handlers correctly
"""

@property
@abstractmethod
def prop_mapping(self) -> Type[AnyPropEnum]:
"""
Returns the correct mapping for a given query class
"""

@property
@abstractmethod
def query_runner(self) -> QueryRunner:
"""
Returns an instance for a given query class
"""

@abstractmethod
def _get_server_side_handler(self) -> ServerSideHandler:
"""
Expand Down
21 changes: 10 additions & 11 deletions lib/openstack_query/runners/query_runner.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
from abc import abstractmethod
import time
import logging
from typing import Optional, List, Any, Dict, Callable

from enums.cloud_domains import CloudDomains
import time
from abc import abstractmethod
from typing import Optional, List, Any, Dict, Callable, Type

from openstack_api.openstack_wrapper_base import OpenstackWrapperBase
from openstack_api.openstack_connection import OpenstackConnection
from custom_types.openstack_query.aliases import (
PropFunc,
ServerSideFilters,
ClientSideFilterFunc,
OpenstackResourceObj,
)
from enums.cloud_domains import CloudDomains
from enums.query.props.prop_enum import PropEnum
from openstack_api.openstack_connection import OpenstackConnection
from openstack_api.openstack_wrapper_base import OpenstackWrapperBase

logger = logging.getLogger(__name__)

Expand All @@ -29,9 +28,9 @@ class QueryRunner(OpenstackWrapperBase):
_LIMIT_FOR_PAGINATION = 1000
_PAGINATION_CALL_LIMIT = 1000

def __init__(self, marker_prop_func: PropFunc, connection_cls=OpenstackConnection):
def __init__(self, prop_enum: Type[PropEnum], connection_cls=OpenstackConnection):
OpenstackWrapperBase.__init__(self, connection_cls)
self._page_marker_prop_func = marker_prop_func
self._prop_enum = prop_enum

def run(
self,
Expand Down Expand Up @@ -155,7 +154,7 @@ def _run_paginated_query(
if i == self._LIMIT_FOR_PAGINATION - 1:
# restart the for loop with marker set
paginated_filters.update(
{"marker": self._page_marker_prop_func(resource)}
{"marker": self._prop_enum.get_prop_mapping(resource)}
)
logger.debug(
"page limit reached: %s - setting new marker: %s",
Expand Down
9 changes: 0 additions & 9 deletions lib/openstack_query/runners/user_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from exceptions.parse_query_error import ParseQueryError
from exceptions.enum_mapping_error import EnumMappingError

from enums.query.props.user_properties import UserProperties
from enums.user_domains import UserDomains

logger = logging.getLogger(__name__)
Expand All @@ -25,14 +24,6 @@ class UserRunner(QueryRunner):

DEFAULT_DOMAIN = UserDomains.STFC

@staticmethod
def _get_marker(obj: User) -> str:
"""
This method returns the marker value for a User object, required for pagination
:param obj: An Server object to get the marker property for
"""
return UserProperties.get_prop_mapping("id")(obj)

def _parse_meta_params(
self, conn: OpenstackConnection, from_domain: Optional[UserDomains] = None
) -> Dict:
Expand Down
23 changes: 23 additions & 0 deletions tests/lib/openstack_query/queries/test_server_query.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from unittest.mock import patch

from enums.query.props.server_properties import ServerProperties
from openstack_query.queries.server_query import ServerQuery


def test_server_query_enum_type():
"""
Checks that server query returns the correct PropEnum type
"""
assert ServerQuery().prop_mapping == ServerProperties


def test_server_query_runner_is_initialized():
"""
Checks that server query runner is initialized
with the correct prop_mapping
"""
with patch("openstack_query.queries.server_query.ServerRunner") as constructor:
runner = ServerQuery().query_runner

constructor.assert_called_with(ServerProperties)
assert runner == constructor.return_value
23 changes: 23 additions & 0 deletions tests/lib/openstack_query/queries/test_user_query.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from unittest.mock import patch

from enums.query.props.user_properties import UserProperties
from openstack_query.queries.user_query import UserQuery


def test_user_query_enum_type():
"""
Checks that server query returns the correct PropEnum type
"""
assert UserQuery().prop_mapping == UserProperties


def test_user_query_runner_is_initialized():
"""
Checks that server query runner is initialized
with the correct prop_mapping
"""
with patch("openstack_query.queries.user_query.UserRunner") as constructor:
runner = UserQuery().query_runner

constructor.assert_called_with(UserProperties)
assert runner == constructor.return_value
11 changes: 4 additions & 7 deletions tests/lib/openstack_query/runners/test_query_runner.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import unittest
from unittest.mock import MagicMock, patch
from unittest.mock import MagicMock, patch, Mock
from parameterized import parameterized

from openstack_query.runners.query_runner import QueryRunner
Expand All @@ -15,16 +15,13 @@ def setUp(self):
"""
super().setUp()
self.mocked_connection = MagicMock()
self.mock_page_func = self._mock_page_func
self.mock_prop_enum = Mock()
self.mock_prop_enum.get_prop_mapping = lambda mock_obj: mock_obj["id"]
self.instance = QueryRunner(
marker_prop_func=self.mock_page_func, connection_cls=self.mocked_connection
prop_enum=self.mock_prop_enum, connection_cls=self.mocked_connection
)
self.conn = self.mocked_connection.return_value.__enter__.return_value

def _mock_page_func(self, mock_obj):
"""simple mock func which returns "id" key from given dict"""
return mock_obj["id"]

@patch("openstack_query.runners.query_runner.QueryRunner._apply_client_side_filter")
@patch("openstack_query.runners.query_runner.QueryRunner._run_query")
@patch("openstack_query.runners.query_runner.QueryRunner._parse_meta_params")
Expand Down

0 comments on commit c1fe218

Please sign in to comment.