From 2e5142582c9436a480c88b4fa19a3132e13d2f6d Mon Sep 17 00:00:00 2001 From: samwelkanda Date: Tue, 19 Sep 2023 08:50:29 +0300 Subject: [PATCH 1/4] Update base request builder to set raw url when provided --- kiota_abstractions/base_request_builder.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kiota_abstractions/base_request_builder.py b/kiota_abstractions/base_request_builder.py index b601ff3..2bca599 100644 --- a/kiota_abstractions/base_request_builder.py +++ b/kiota_abstractions/base_request_builder.py @@ -6,6 +6,7 @@ from typing import Any, Dict, Union from .request_adapter import RequestAdapter +from .request_information import RequestInformation class BaseRequestBuilder: @@ -18,6 +19,9 @@ def __init__( """Initializes a new instance of the BaseRequestBuilder class.""" if path_parameters is None: path_parameters = {} + elif isinstance(path_parameters, str): + path_parameters = {RequestInformation.RAW_URL_KEY: path_parameters} + if request_adapter is None: raise TypeError("request_adapter cannot be null.") if url_template is None: From 067b9c1c7336732980aabb6e9ecfc3831664d2bc Mon Sep 17 00:00:00 2001 From: samwelkanda Date: Tue, 19 Sep 2023 08:52:10 +0300 Subject: [PATCH 2/4] Add tests for base request builder --- requirements-dev.txt | 2 + tests/conftest.py | 62 ++++++++++++++++++++---------- tests/test_base_request_builder.py | 45 ++++++++++++++++++++++ 3 files changed, 89 insertions(+), 20 deletions(-) create mode 100644 tests/test_base_request_builder.py diff --git a/requirements-dev.txt b/requirements-dev.txt index 0185010..53f261b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -42,6 +42,8 @@ pytest==7.4.2 pytest-asyncio==0.21.1 +pytest-mock==3.11.1 + requests==2.31.0 toml==0.10.2 diff --git a/tests/conftest.py b/tests/conftest.py index 517a658..138d0f8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,39 +5,48 @@ # ------------------------------------------------------------------------------ from __future__ import annotations + from dataclasses import dataclass, field -from typing import Callable, List, Any, Tuple, Dict, Optional +from typing import Any, Callable, Dict, List, Optional, Tuple + import pytest from kiota_abstractions.authentication.access_token_provider import AccessTokenProvider -from kiota_abstractions.authentication.allowed_hosts_validator import ( - AllowedHostsValidator, -) +from kiota_abstractions.authentication.allowed_hosts_validator import AllowedHostsValidator +from kiota_abstractions.request_adapter import RequestAdapter from kiota_abstractions.request_information import RequestInformation -from kiota_abstractions.serialization import AdditionalDataHolder, Parsable, ParseNode, SerializationWriter +from kiota_abstractions.serialization import ( + AdditionalDataHolder, + Parsable, + ParseNode, + SerializationWriter, +) from kiota_abstractions.store import BackedModel, BackingStore, BackingStoreFactorySingleton class MockAccessTokenProvider(AccessTokenProvider): + def __init__(self): self.token = None async def get_authorization_token( - self, - url: str, - additional_authentication_context: Dict[str, Any] = {} + self, url: str, additional_authentication_context: Dict[str, Any] = {} ) -> str: return "SomeToken" def get_allowed_hosts_validator(self) -> AllowedHostsValidator: return AllowedHostsValidator(["example.com"]) + @dataclass class MockEntity(Parsable, AdditionalDataHolder, BackedModel): # Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. additional_data: Dict[str, Any] = field(default_factory=dict) # Stores model information. - backing_store : BackingStore = field(default_factory=BackingStoreFactorySingleton(backing_store_factory=None).backing_store_factory.create_backing_store) + backing_store: BackingStore = field( + default_factory=BackingStoreFactorySingleton(backing_store_factory=None + ).backing_store_factory.create_backing_store + ) # The id property id: Optional[str] = None # The OdataType property @@ -48,7 +57,7 @@ class MockEntity(Parsable, AdditionalDataHolder, BackedModel): manager: Optional[MockEntity] = None # The user or contact that is this user& works with. colleagues: Optional[List[MockEntity]] = None - + @staticmethod def create_from_discriminator_value(parse_node: Optional[ParseNode] = None): """ @@ -60,22 +69,27 @@ def create_from_discriminator_value(parse_node: Optional[ParseNode] = None): if not parse_node: raise TypeError("parse_node cannot be null.") return MockEntity() - - def get_field_deserializers(self,) -> Dict[str, Callable[[ParseNode], None]]: + + def get_field_deserializers(self, ) -> Dict[str, Callable[[ParseNode], None]]: """ The deserialization information for the current model Returns: Dict[str, Callable[[ParseNode], None]] """ fields: Dict[str, Callable[[Any], None]] = { - "@odata.type": lambda n : setattr(self, 'odata_type', n.get_str_value()), - "id": lambda n : setattr(self, 'id', n.get_str_value()), - "businessPhones": lambda n : setattr(self, 'business_phones', n.get_collection_of_primitive_values(str)), - "manager": lambda n : setattr(self, 'manager', n.get_object_value(MockEntity)), - "colleagues": lambda n : setattr(self, 'colleagues', n.get_collection_of_object_values(MockEntity)), + "@odata.type": + lambda n: setattr(self, 'odata_type', n.get_str_value()), + "id": + lambda n: setattr(self, 'id', n.get_str_value()), + "businessPhones": + lambda n: setattr(self, 'business_phones', n.get_collection_of_primitive_values(str)), + "manager": + lambda n: setattr(self, 'manager', n.get_object_value(MockEntity)), + "colleagues": + lambda n: setattr(self, 'colleagues', n.get_collection_of_object_values(MockEntity)), } return fields - - def serialize(self,writer: SerializationWriter) -> None: + + def serialize(self, writer: SerializationWriter) -> None: """ Serializes information the current object Args: @@ -89,7 +103,8 @@ def serialize(self,writer: SerializationWriter) -> None: writer.write_collection_of_primitive_values("businessPhones", self.business_phones) writer.write_object_value("manager", self.manager) writer.write_collection_of_object_values("colleagues", self.colleagues) - + + @pytest.fixture def mock_user(): user = MockEntity() @@ -99,6 +114,7 @@ def mock_user(): user.backing_store.is_initialization_completed = True return user + @pytest.fixture def mock_request_information(): request_info = RequestInformation() @@ -109,3 +125,9 @@ def mock_request_information(): @pytest.fixture def mock_access_token_provider(): return MockAccessTokenProvider() + + +@pytest.fixture +def mock_request_adapter(mocker): + mocker.patch.multiple(RequestAdapter, __abstractmethods__=set()) + return RequestAdapter() diff --git a/tests/test_base_request_builder.py b/tests/test_base_request_builder.py new file mode 100644 index 0000000..1f4a0ca --- /dev/null +++ b/tests/test_base_request_builder.py @@ -0,0 +1,45 @@ +import pytest + +from kiota_abstractions.base_request_builder import BaseRequestBuilder + + +def test_initialization(mock_request_adapter): + request_builder = BaseRequestBuilder(mock_request_adapter, "{+baseurl}", None) + assert request_builder.request_adapter == mock_request_adapter + assert request_builder.url_template == "{+baseurl}" + assert request_builder.path_parameters == {} + + +def test_initialization_with_no_adapter_raises_exception(mock_request_adapter): + with pytest.raises(TypeError) as excinfo: + request_builder = BaseRequestBuilder(None, "{+baseurl}", None) + assert "request_adapter cannot be null." in str(excinfo.value) + + +def test_initialization_with_no_url_template_raises_exception(mock_request_adapter): + with pytest.raises(TypeError) as excinfo: + request_builder = BaseRequestBuilder(mock_request_adapter, None, None) + assert "url_template cannot be null." in str(excinfo.value) + + +def test_initialization_with_empty_url_template_valid(mock_request_adapter): + request_builder = BaseRequestBuilder(mock_request_adapter, "", None) + assert request_builder.request_adapter == mock_request_adapter + assert request_builder.url_template == "" + assert request_builder.path_parameters == {} + + +def test_initialization_with_path_parameters(mock_request_adapter): + request_builder = BaseRequestBuilder( + mock_request_adapter, "{+baseurl}", {"baseurl": "https://example.com"} + ) + assert request_builder.request_adapter == mock_request_adapter + assert request_builder.url_template == "{+baseurl}" + assert request_builder.path_parameters == {"baseurl": "https://example.com"} + + +def test_initialization_with_path_parameters_as_string_sets_raw_url(mock_request_adapter): + request_builder = BaseRequestBuilder(mock_request_adapter, "{+baseurl}", "https://example.com") + assert request_builder.request_adapter == mock_request_adapter + assert request_builder.url_template == "{+baseurl}" + assert request_builder.path_parameters == {"request-raw-url": "https://example.com"} From 931e8a69d3679002273b45cb46f35294125adced Mon Sep 17 00:00:00 2001 From: samwelkanda Date: Tue, 19 Sep 2023 08:53:12 +0300 Subject: [PATCH 3/4] Bump package version --- kiota_abstractions/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kiota_abstractions/_version.py b/kiota_abstractions/_version.py index 78e3245..01c2028 100644 --- a/kiota_abstractions/_version.py +++ b/kiota_abstractions/_version.py @@ -1 +1 @@ -VERSION: str = "0.8.5" +VERSION: str = "0.8.6" From d23708e719ff2ce314757903e82d0c66b798651a Mon Sep 17 00:00:00 2001 From: samwelkanda Date: Tue, 19 Sep 2023 08:55:50 +0300 Subject: [PATCH 4/4] Add CHANGELOG entry --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71b1a62..4b84a79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.8.6] - 2023-09-19 + +### Added + +### Changed +- Updated BaseRequestBuilder to set the raw url value if provided. + ## [0.8.5] - 2023-09-15 ### Added