Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2a2b2d2
chore: bump kiota dependencies
Ndiritu Dec 5, 2024
7b0c51b
enable static checks for missing imports
Ndiritu Dec 10, 2024
33bdf40
Expose error mappings in page iterator and ignore errors due to undef…
Ndiritu Dec 11, 2024
0621804
Resolve large file upload type issues
Ndiritu Dec 11, 2024
d678554
Fix typing issue in auth provider
Ndiritu Dec 11, 2024
b9b704f
Resolve errors in graph client factory
Ndiritu Dec 11, 2024
9d48700
Fix batch request item type hint issues
Ndiritu Dec 13, 2024
3c1d998
Fix batch request content issues
Ndiritu Dec 13, 2024
2e77ff7
fix batch response item issues
Ndiritu Dec 13, 2024
ec2cc7e
Fix batch response content type issues
Ndiritu Dec 13, 2024
5b0e0e7
fix batch response content collection
Ndiritu Dec 13, 2024
210c174
undo changes to batch request content remove()
Ndiritu Dec 13, 2024
d83c1dd
fix issues in batch request content collection
Ndiritu Dec 13, 2024
85e8935
fix: Fixes type hints and failing mypy checks
Ndiritu Dec 13, 2024
e861019
Undo breaking type changes in LFU and fix errors
Ndiritu Dec 13, 2024
f3632a9
clean up page iterator fixes
Ndiritu Dec 13, 2024
92efc9c
fix formatting issues
Ndiritu Dec 13, 2024
e1c575f
Fix page iterator type var
Ndiritu Dec 13, 2024
9800f11
Fix pylint errors
Ndiritu Dec 13, 2024
defda71
Fix Sonarcloud issues
Ndiritu Dec 13, 2024
68e5263
Mark StreamInterface type as deprecated
Ndiritu Dec 16, 2024
3b46699
Add missing pytest asyncio plugin causing pytest failure
Ndiritu Dec 16, 2024
1d0eacc
Fix formatting
Ndiritu Dec 16, 2024
4cfef9d
import deprecated package and its type stubs
Ndiritu Dec 16, 2024
40b35dc
Fix wrong test assertions
Ndiritu Dec 16, 2024
eb27bdd
Merge branch 'main' into fix/failing-static-checks
Ndiritu Dec 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ documentation = "https://github.com/microsoftgraph/msgraph-sdk-python-core/docs"
[tool.mypy]
warn_unused_configs = true
files = "src"
ignore_missing_imports = true

[tool.yapf]
based_on_style = "pep8"
Expand Down
12 changes: 9 additions & 3 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ python-dotenv==1.0.1

pytest-trio==0.8.0

pytest-asyncio==0.24.0

pywin32==308 ; platform_system == 'Windows'

requests==2.32.3 ; python_version >= '3.7'
Expand Down Expand Up @@ -143,14 +145,18 @@ httpx[http2]==0.28.1

hyperframe==6.0.1 ; python_full_version >= '3.6.1'

microsoft-kiota-abstractions==1.3.3
microsoft-kiota-abstractions==1.6.6

microsoft-kiota-authentication-azure==1.1.0
microsoft-kiota-authentication-azure==1.6.6

microsoft-kiota-http==1.3.3
microsoft-kiota-http==1.6.6

multidict==6.1.0 ; python_version >= '3.7'

uritemplate==4.1.1 ; python_version >= '3.6'

yarl==1.15.2 ; python_version >= '3.7'

deprecated==1.2.15

types-Deprecated==1.2.15.20241117
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def __init__(
credentials: Union["TokenCredential", "AsyncTokenCredential"],
options: Optional[Dict] = {},
scopes: List[str] = [],
allowed_hosts: Optional[List[str]] = [nc.value for nc in NationalClouds]
allowed_hosts: List[str] = [nc.value for nc in NationalClouds]
) -> None:
"""[summary]

Expand Down
10 changes: 7 additions & 3 deletions src/msgraph_core/graph_client_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ class GraphClientFactory(KiotaClientFactory):
"""

@staticmethod
def create_with_default_middleware(
def create_with_default_middleware( # type: ignore
# Breaking change to remove KiotaClientFactory as base class
api_version: APIVersion = APIVersion.v1,
client: Optional[httpx.AsyncClient] = None,
host: NationalClouds = NationalClouds.Global,
Expand Down Expand Up @@ -53,7 +54,8 @@ def create_with_default_middleware(
return GraphClientFactory._load_middleware_to_client(client, middleware)

@staticmethod
def create_with_custom_middleware(
def create_with_custom_middleware( # type: ignore
# Breaking change to remove Kiota client factory as base class
middleware: Optional[List[BaseMiddleware]],
api_version: APIVersion = APIVersion.v1,
client: Optional[httpx.AsyncClient] = None,
Expand Down Expand Up @@ -91,7 +93,9 @@ def _get_telemetry_handler(
options"""

if options:
graph_telemetry_options = options.get(GraphTelemetryHandlerOption().get_key())
graph_telemetry_options: GraphTelemetryHandlerOption = options.get(
GraphTelemetryHandlerOption().get_key()
) # type: ignore # Unable to down cast type
if graph_telemetry_options:
return GraphTelemetryHandler(options=graph_telemetry_options)
return GraphTelemetryHandler()
Expand Down
4 changes: 2 additions & 2 deletions src/msgraph_core/models/large_file_upload_session.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from __future__ import annotations
from typing import Any, Callable, Dict, List, Optional, TYPE_CHECKING, Union
from typing import Any, Callable, Dict, List, Optional
import datetime
from dataclasses import dataclass, field

Expand All @@ -25,7 +25,7 @@ def create_from_discriminator_value(
) -> LargeFileUploadSession:
"""
Creates a new instance of the appropriate class based
on discriminator value param parse_node: The parse node
on discriminator value param parse_node: The parse node
to use to read the discriminator value and create the object
Returns: UploadSession
"""
Expand Down
13 changes: 11 additions & 2 deletions src/msgraph_core/models/page_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,17 @@ def get_field_deserializers(self) -> Dict[str, Callable[[ParseNode], None]]:
object where each entry is a property key with its deserialization callback.
"""
return {
"@odata.nextLink": lambda x: setattr(self, "odata_next_link", x.get_str_value()),
"value": lambda x: setattr(self, "value", x.get_collection_of_object_values(Parsable))
"@odata.nextLink":
lambda x: setattr(self, "odata_next_link", x.get_str_value()),
"value":
lambda x: setattr(
self,
"value",
x.get_collection_of_object_values(
Parsable # type: ignore
# Bug. Should get a collection of primitive dictionary objects
)
)
}

def serialize(self, writer: SerializationWriter) -> None:
Expand Down
38 changes: 16 additions & 22 deletions src/msgraph_core/requests/batch_request_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from kiota_abstractions.request_adapter import RequestAdapter
from kiota_abstractions.request_information import RequestInformation
from kiota_abstractions.method import Method
from kiota_abstractions.serialization import Parsable
from kiota_abstractions.serialization import Parsable, ParsableFactory
from kiota_abstractions.headers_collection import HeadersCollection
from kiota_abstractions.api_error import APIError

Expand All @@ -26,7 +26,7 @@ class BatchRequestBuilder:
def __init__(
self,
request_adapter: RequestAdapter,
error_map: Optional[Dict[str, Type[Parsable]]] = None
error_map: Optional[Dict[str, Type[ParsableFactory]]] = None
):
if request_adapter is None:
raise ValueError("request_adapter cannot be Null.")
Expand All @@ -37,20 +37,19 @@ def __init__(
async def post(
self,
batch_request_content: Union[BatchRequestContent, BatchRequestContentCollection],
error_map: Optional[Dict[str, Type[Parsable]]] = None,
) -> Union[T, BatchResponseContentCollection]:
error_map: Optional[Dict[str, Type[ParsableFactory]]] = None,
) -> Union[BatchResponseContent, BatchResponseContentCollection]:
"""
Sends a batch request and returns the batch response content.

Args:
batch_request_content (Union[BatchRequestContent,
batch_request_content (Union[BatchRequestContent,
BatchRequestContentCollection]): The batch request content.
response_type: Optional[Type[T]] : The type to deserialize the response into.
Optional[Dict[str, Type[Parsable]]] = None:
Optional[Dict[str, Type[ParsableFactory]]] = None:
Error mappings for response handling.

Returns:
Union[T, BatchResponseContentCollection]: The batch response content
Union[BatchResponseContent, BatchResponseContentCollection]: The batch response content
or the specified response type.

"""
Expand All @@ -60,11 +59,6 @@ async def post(

if isinstance(batch_request_content, BatchRequestContent):
request_info = await self.to_post_request_information(batch_request_content)
bytes_content = request_info.content
json_content = bytes_content.decode("utf-8")
updated_str = '{"requests":' + json_content + '}'
updated_bytes = updated_str.encode("utf-8")
request_info.content = updated_bytes
error_map = error_map or self.error_map
response = None
try:
Expand All @@ -87,15 +81,15 @@ async def post(
async def _post_batch_collection(
self,
batch_request_content_collection: BatchRequestContentCollection,
error_map: Optional[Dict[str, Type[Parsable]]] = None,
error_map: Optional[Dict[str, Type[ParsableFactory]]] = None,
) -> BatchResponseContentCollection:
"""
Sends a collection of batch requests and returns a collection of batch response contents.

Args:
batch_request_content_collection (BatchRequestContentCollection): The
batch_request_content_collection (BatchRequestContentCollection): The
collection of batch request contents.
Optional[Dict[str, Type[Parsable]]] = None:
Optional[Dict[str, Type[ParsableFactory]]] = None:
Error mappings for response handling.

Returns:
Expand All @@ -108,7 +102,8 @@ async def _post_batch_collection(
batch_requests = batch_request_content_collection.get_batch_requests_for_execution()
for batch_request_content in batch_requests:
response = await self.post(batch_request_content, error_map)
batch_responses.add_response(response)
if isinstance(response, BatchResponseContent):
batch_responses.add_response(response)

return batch_responses

Expand All @@ -117,7 +112,7 @@ async def to_post_request_information(
) -> RequestInformation:
"""
Creates request information for a batch POST request.

Args:
batch_request_content (BatchRequestContent): The batch request content.

Expand All @@ -127,15 +122,14 @@ async def to_post_request_information(

if batch_request_content is None:
raise ValueError("batch_request_content cannot be Null.")
batch_request_items = list(batch_request_content.requests.values())

request_info = RequestInformation()
request_info.http_method = Method.POST
request_info.url_template = self.url_template
request_info.headers = HeadersCollection()
request_info.headers.try_add("Content-Type", APPLICATION_JSON)
request_info.set_content_from_parsable(
self._request_adapter, APPLICATION_JSON, batch_request_items
self._request_adapter, APPLICATION_JSON, batch_request_content
)

return request_info
59 changes: 41 additions & 18 deletions src/msgraph_core/requests/batch_request_content.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import uuid
from typing import List, Dict, Union, Optional
from urllib.request import Request

from kiota_abstractions.request_information import RequestInformation
from kiota_abstractions.serialization import Parsable, ParseNode
Expand All @@ -15,27 +16,36 @@ class BatchRequestContent(Parsable):

MAX_REQUESTS = 20

def __init__(self, requests: Dict[str, Union['BatchRequestItem', 'RequestInformation']] = {}):
def __init__(self, requests: Dict[str, Union[BatchRequestItem, RequestInformation]] = {}):
"""
Initializes a new instance of the BatchRequestContent class.
Args:
Requests (Dict[str, Union[BatchRequestItem, RequestInformation]]): The requests to add.
"""
self._requests: Dict[str, Union[BatchRequestItem, 'RequestInformation']] = requests or {}
self._requests: Dict[str, BatchRequestItem] = {}

self.is_finalized = False
for request_id, request in requests.items():
if isinstance(request, RequestInformation):
self.add_request_information(request, request_id)
continue
self.add_request(request_id, request)

@property
def requests(self) -> Dict:
def requests(self) -> Dict[str, BatchRequestItem]:
"""
Gets the requests.
Returns:
Dict[str, BatchRequestItem]: requests in the batch request content.
"""
return self._requests

@requests.setter
def requests(self, requests: List[BatchRequestItem]) -> None:
"""
Sets the requests.
Args:
requests (List[BatchRequestItem]): The requests to set.
"""
if len(requests) >= BatchRequestContent.MAX_REQUESTS:
raise ValueError(f"Maximum number of requests is {BatchRequestContent.MAX_REQUESTS}")
Expand All @@ -45,43 +55,56 @@ def requests(self, requests: List[BatchRequestItem]) -> None:
def add_request(self, request_id: Optional[str], request: BatchRequestItem) -> None:
"""
Adds a request to the batch request content.
Args:
request_id (Optional[str]): The request id to add.
request (BatchRequestItem): The request to add.
"""
if len(self.requests) >= BatchRequestContent.MAX_REQUESTS:
raise RuntimeError(f"Maximum number of requests is {BatchRequestContent.MAX_REQUESTS}")
if not request.id:
request.id = str(uuid.uuid4())
request.id = request_id if request_id else str(uuid.uuid4())
if hasattr(request, 'depends_on') and request.depends_on:
for dependent_id in request.depends_on:
if dependent_id not in self.requests:
dependent_request = self._request_by_id(dependent_id)
if dependent_request:
self._requests[dependent_id] = dependent_request
if not self._request_by_id(dependent_id):
raise ValueError(
f"""
Request depends on request id: {dependent_id}
which was not found in requests. Add request id: {dependent_id} first"""
)
self._requests[request.id] = request

def add_request_information(self, request_information: RequestInformation) -> None:
"""
def add_request_information(
self, request_information: RequestInformation, request_id: Optional[str] = None
) -> None:
"""
Adds a request to the batch request content.
Args:
request_information (RequestInformation): The request information to add.
request_id: Optional[str]: The request id to add.
"""
request_id = str(uuid.uuid4())
request_id = request_id if request_id else str(uuid.uuid4())
self.add_request(request_id, BatchRequestItem(request_information))

def add_urllib_request(self, request) -> None:
def add_urllib_request(self, request: Request, request_id: Optional[str] = None) -> None:
"""
Adds a request to the batch request content.
Args:
request (Request): The request to add.
request_id: Optional[str]: The request id to add.
"""
request_id = str(uuid.uuid4())
request_id = request_id if request_id else str(uuid.uuid4())
self.add_request(request_id, BatchRequestItem.create_with_urllib_request(request))

def remove(self, request_id: str) -> None:
"""
Removes a request from the batch request content.
Also removes the request from the depends_on list of
Also removes the request from the depends_on list of
other requests.
Args:
request_id (str): The request id to remove.
"""
request_to_remove = None
for request in self.requests:
for request in self.requests.values():
if request.id == request_id:
request_to_remove = request
if hasattr(request, 'depends_on') and request.depends_on:
Expand All @@ -108,12 +131,12 @@ def finalize(self):
def _request_by_id(self, request_id: str) -> Optional[BatchRequestItem]:
"""
Finds a request by its ID.

Args:
request_id (str): The ID of the request to find.

Returns:
The request with the given ID, or None if not found.
Optional[BatchRequestItem]: The request with the given ID, or None if not found.
"""
return self._requests.get(request_id)

Expand All @@ -137,4 +160,4 @@ def serialize(self, writer: SerializationWriter) -> None:
Args:
writer: Serialization writer to use to serialize this model
"""
writer.write_collection_of_object_values("requests", self.requests)
writer.write_collection_of_object_values("requests", list(self.requests.values()))
Loading
Loading