Giter Club home page Giter Club logo

kiota-http-python's Introduction

Microsoft Kiota HTTP library

PyPI version CI Actions Status Downloads

The Microsoft Kiota HTTP Library is a python HTTP implementation with HTTPX library.

A Kiota generated project will need a reference to a http package to to make HTTP requests to an API endpoint.

Read more about Kiota here.

Using the Microsoft Kiota HTTP library

In order to use this library, install the package by running:

pip install microsoft-kiota-http

Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.

kiota-http-python's People

Contributors

andrueastman avatar baywet avatar dependabot[bot] avatar github-actions[bot] avatar ladycarbonfiber avatar microsoft-github-operations[bot] avatar microsoftopensource avatar musale avatar ndiritu avatar pokop avatar samwelkanda avatar shemogumbe avatar silaskenneth avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kiota-http-python's Issues

Kiota python generator produces methods that fail on error responses

Using the Kiota Python generator as described in microsoft/kiota#1996, after fixing the indentation problems manually, I'm getting exceptions from the Kiota httpx_request_adapter.py when the service returns a non-success response. Here's the traceback:

>>> tests = asyncio.run(client.loadtests().sort_and_filter().get(config))
Headers({'host': '6e856190-1a06-44bd-b3eb-4b51ec508b2f.southcentralus.cnt-prod.loadtesting.azure.com', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive', 'user-agent': 'python-httpx/0.23.1', 'accept': 'application/json', 'authorization': '[secure]', 'request_options': '{}'})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/homebrew/Cellar/[email protected]/3.11.0/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.11.0/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.11.0/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py", line 650, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/Users/mikekistler/Projects/mikekistler/kiota/client/loadtests/sort_and_filter/sort_and_filter_request_builder.py", line 67, in get
    return await self.request_adapter.send_async(request_info, test_model_resource_list.TestModelResourceList, response_handler, None)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/lib/python3.11/site-packages/kiota_http/httpx_request_adapter.py", line 118, in send_async
    await self.throw_failed_responses(response, error_map)
  File "/opt/homebrew/lib/python3.11/site-packages/kiota_http/httpx_request_adapter.py", line 290, in throw_failed_responses
    in error_map) and not (400 <= status_code < 500 and error_map['4XX']
                                                        ~~~~~~~~~^^^^^^^
TypeError: 'NoneType' object is not subscriptable
>>> 

It shows that the problem is an attempt to subscript error_map which is None.

Here's the msort_and_filter().get() method that Kiota generated:

async def get(self,request_configuration: Optional[SortAndFilterRequestBuilderGetRequestConfiguration] = None, response_handler: Optional[ResponseHandler] = None) -> Optional[test_model_resource_list.TestModelResourceList]:
    request_info = self.create_get_request_information(
        request_configuration
    )
    if not self.request_adapter:
        raise Exception("Http core is null") 
    return await self.request_adapter.send_async(request_info, test_model_resource_list.TestModelResourceList, response_handler, None)

The final None in the send_async call is the error_map.

The responses for this operation in the REST API definition are:

        "responses": {
          "200": {
            "description": "The requested load tests",
            "schema": {
              "$ref": "#/definitions/TestModelResourceList"
            }
          },
          "default": {
            "description": "Load Testing service error response.",
            "schema": {
              "$ref": "#/definitions/ErrorResponseBody"
            },
            "headers": {
              "x-ms-error-code": {
                "description": "The error code for specific error that occurred.",
                "type": "string"
              }
            }
          }
        },

I suspect that the problem here is that Kiota is looking for 400 or 500 class responses and finding none, so passes an None as the error map. But Azure uses default to describe error responses.

`ParametersNameDecodingHandler` middleware affects values, adds new keys

It seems like ParametersNameDecodingHandler middleware is a workaround that should only affect query parameter names, without replacing values and adding new parameters.
However, the code below is corrupting all parameter values that contain escaped meaningful URL symbols like +, =, ?, & - the latter may add extra parameter names into the URL

updated_url: str = str(request.url) #type: ignore
if all(
[
current_options, current_options.enabled, '%' in updated_url,
current_options.characters_to_decode
]
):
updated_url = unquote(updated_url)
request.url = httpx.URL(updated_url)

from urllib.parse import unquote
from httpx import URL

original = URL("https://google.com?q=1%2b2") # search for "1+2"
updated = URL(unquote(str(original)))
assert updated ==  URL('https://google.com?q=1+2')  # corrupted, now searches for "1 2" !

original = URL("https://google.com/?q=M%26A")  # search for "M&A"
updated = URL(unquote(str(original)))  # corrupted, now searches for "M", adds separate A parameter !

This was extremely hard to find when it was resulting in SDK API errors with Invalid continuation token <TOKEN> passed where actually valid TOKEN that had + in the middle and also ends with =.

Underlying HTTP client is closed after first request, causing subsequent requests to fail

Using the Python Graph SDK, I found this issue. The first request sent through the GraphServiceClient succeeds, but subsequent requests throw an exception:

Traceback (most recent call last):
  File "/home/jasonjoh/repos/msgraph-training-python/demo/graphtutorial/repro.py", line 17, in <module>
    users2 = asyncio.run(client.users().get())
  File "/usr/lib/python3.10/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.10/asyncio/base_events.py", line 646, in run_until_complete
    return future.result()
  File "/home/jasonjoh/.local/lib/python3.10/site-packages/msgraph/generated/users/users_request_builder.py", line 129, in get
    return await self.request_adapter.send_async(request_info, user_collection_response.UserCollectionResponse, response_handler, error_mapping)
  File "/home/jasonjoh/.local/lib/python3.10/site-packages/kiota_http/httpx_request_adapter.py", line 114, in send_async
    response = await self.get_http_response_message(request_info)
  File "/home/jasonjoh/.local/lib/python3.10/site-packages/kiota_http/httpx_request_adapter.py", line 329, in get_http_response_message
    resp = await self._http_client.send(request)
  File "/home/jasonjoh/.local/lib/python3.10/site-packages/httpx/_client.py", line 1609, in send
    raise RuntimeError("Cannot send a request, as the client has been closed.")
RuntimeError: Cannot send a request, as the client has been closed.

This seems to be caused by the following line:

await self._http_client.aclose()

This script can reproduce the problem:

import asyncio
from azure.identity.aio import ClientSecretCredential
from kiota_authentication_azure.azure_identity_authentication_provider import AzureIdentityAuthenticationProvider
from msgraph import GraphRequestAdapter, GraphServiceClient

credential = ClientSecretCredential(
    'TENANT_ID',
    'CLIENT_ID',
    'CLIENT_SECRET')
auth_provider = AzureIdentityAuthenticationProvider(credential)
adapter = GraphRequestAdapter(auth_provider)
client = GraphServiceClient(adapter)

users = asyncio.run(client.users().get())
print('got users')

users2 = asyncio.run(client.users().get())
print('got users again')

map XXX error status code

related to microsoft/kiota#4025
add a 3rd case in the error handling of the request adapter for XXX (must be the 3rd in the order, first sepcific code, then 4XX or 5XX depending on the first number, then XXX)

python - adds product to user agent

related microsoft/kiota#2056, add kiota-lang/http-lib-version as a product to the user agent request header to help with telemetry. The implementation should not overwrite existing values, just add to it. If possible read the version from the package information at runtime, otherwise read a constant.

Kiota transport bypassed when using proxy

When using a proxy e.g

 proxies = {
     "http://": "http://localhost:8030",
     "https://": "http://localhost:8031",
}
custom_client = httpx.AsyncClient(proxies=proxies) 

The client uses the default httpx.AsyncHTTPTransport instead of the AsycKiotaTransport. This is due to the internal implementation of how to create clients with a proxy and results in our middleware pipeline not applying

RedirectHandler maintains `max_redirect` state across requests

When using RedirectHandler for multiple requests without specifying custom options, we encounter an issue where the max_redirect counter is shared across all requests handled by a single RedirectHandler instance. This is problematic when downloading drive items using the Microsoft Graph API, which respond with a 302 Found redirect to a preauthenticated download URL.

After 5 successive downloads, the handler raises Too many redirects exception due to the shared counter reaching its default limit, effectively preventing further downloads.

Exception: ValueError: not enough values to unpack (expected 2, got 1)

I am following the guide on: https://github.com/microsoftgraph/msgraph-sdk-python to build a Python package that can pull all my devices from Azure AD (Entra). I have confirmed good working API credentials and that they have the right permissions:

async def get_AADdevices(): MScredential = ClientSecretCredential( tenant_id=os.environ['MSGraphTenantID'], client_id=os.environ['MSGraphClientID'], client_secret=os.environ['MSGraphClientSecret'] ) scopes = ['https://graph.microsoft.com/.default'] client = GraphServiceClient(credentials=MScredential, scopes=scopes) devices = await client.devices.get()

I am getting the following error when it calls the await client.devices.get():

Executed 'Functions.MachineReconciliation' (Failed, Id=d6a7b205-25fc-4dfa-ad22-3621ed0b4144, Duration=9ms) System.Private.CoreLib: Exception while executing function: Functions.MachineReconciliation. System.Private.CoreLib: Result: Failure Exception: ValueError: not enough values to unpack (expected 2, got 1) Stack: File "C:\Program Files\Microsoft\Azure Functions Core Tools\workers\python\3.10/WINDOWS/X64\azure_functions_worker\dispatcher.py", line 479, in _handle__invocation_request call_result = await self._loop.run_in_executor( File "C:\Users\<user>\AppData\Local\Programs\Python\Python310\lib\concurrent\futures\thread.py", line 58, in run result = self.fn(*self.args, **self.kwargs) File "C:\Program Files\Microsoft\Azure Functions Core Tools\workers\python\3.10/WINDOWS/X64\azure_functions_worker\dispatcher.py", line 752, in _run_sync_func return ExtensionManager.get_sync_invocation_wrapper(context, File "C:\Program Files\Microsoft\Azure Functions Core Tools\workers\python\3.10/WINDOWS/X64\azure_functions_worker\extension.py", line 215, in _raw_invocation_wrapper result = function(**args) File "C:\Users\<path>\function_app.py", line 17, in MachineReconciliation asyncio.run(get_AADdevices()) File "C:\Users\<user>\AppData\Local\Programs\Python\Python310\lib\asyncio\runners.py", line 44, in run return loop.run_until_complete(main) File "C:\Users\<user>\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 649, in run_until_complete return future.result() File "C:\Users\<path>\function_app.py", line 40, in get_AADdevices devices = await client.devices.get() File "C:\Users\<path>\.venv\lib\site-packages\msgraph\generated\devices\devices_request_builder.py", line 70, in get return await self.request_adapter.send_async(request_info, DeviceCollectionResponse, error_mapping) File "C:\Users\<path>\.venv\lib\site-packages\kiota_http\httpx_request_adapter.py", line 162, in send_async parent_span = self.start_tracing_span(request_info, "send_async") File "C:\Users\<path>\.venv\lib\site-packages\kiota_http\httpx_request_adapter.py", line 131, in start_tracing_span uri_template = ParametersNameDecodingHandler.decode_uri_encoded_string( File "C:\Users\<path>\.venv\lib\site-packages\kiota_http\middleware\parameters_name_decoding_handler.py", line 92, in decode_uri_encoded_string name, value = name_value.split('=')

Python - move graph related authentication defaults to graph core

related microsoft/kiota#1063. Graph default scope and default valid host names are present in the authentication library, which makes it more complex to use it against non-graph but MIP protected APIs.

  • check that allowed host validator returns true when no hosts are provided (abstractions)
  • change the default scope to be set in the get access token method to scheme://host/.default if no scopes have been provided
  • remove the default hosts in the authentication library
  • create derived authentication and access providers in microsoft graph core that set the default hosts
  • update the documentation

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.