Giter Club home page Giter Club logo

msgraph-sdk-python-core's Introduction

PyPI version CI Actions Status Downloads

Microsoft Graph Core Python Client Library.

The Microsoft Graph Core Python Client Library contains core classes used by Microsoft Graph Python Client Library to send native HTTP requests to Microsoft Graph API.

NOTE: This is a new major version of the Python Core library for Microsoft Graph based on the Kiota project. We recommend to use this library with the full Python SDK. Upgrading to this version from the previous version of the Python Core library will introduce breaking changes into your application.

Prerequisites

Python 3.8+

This library doesn't support older versions of Python.

Getting started

1. Register your application

To call Microsoft Graph, your app must acquire an access token from the Microsoft identity platform. Learn more about this -

2. Install the required packages

msgraph-core is available on PyPI.

pip3 install msgraph-core
pip3 install azure-identity

3. Configure an Authentication Provider Object

An instance of the BaseGraphRequestAdapter class handles building client. To create a new instance of this class, you need to provide an instance of AuthenticationProvider, which can authenticate requests to Microsoft Graph.

Note: This client library offers an asynchronous API by default. Async is a concurrency model that is far more efficient than multi-threading, and can provide significant performance benefits and enable the use of long-lived network connections such as WebSockets. We support popular python async environments such as asyncio, anyio or trio. For authentication you need to use one of the async credential classes from azure.identity.

# Using EnvironmentCredential for demonstration purposes.
# There are many other options for getting an access token. See the following for more information.
# https://pypi.org/project/azure-identity/#async-credentials
from azure.identity.aio import EnvironmentCredential
from msgraph_core.authentication import AzureIdentityAuthenticationProvider

credential=EnvironmentCredential()
auth_provider = AzureIdentityAuthenticationProvider(credential)

Note: AzureIdentityAuthenticationProvider sets the default scopes and allowed hosts.

5. Pass the authentication provider object to the BaseGraphRequestAdapter constructor.

from msgraph_core import BaseGraphRequestAdapter
adapter = BaseGraphRequestAdapter(auth_provider)

6. Make a requests to the graph.

After you have a BaseGraphRequestAdapter that is authenticated, you can begin making calls against the service.

import asyncio
from kiota_abstractions.request_information import RequestInformation

request_info = RequestInformation()
request_info.url = 'https://graph.microsoft.com/v1.0/me'

# User is your own type that implements Parsable or comes from the service library
user = asyncio.run(adapter.send_async(request_info, User, {}))
print(user.display_name)

Telemetry Metadata

This library captures metadata by default that provides insights into its usage and helps to improve the developer experience. This metadata includes the SdkVersion, RuntimeEnvironment and HostOs on which the client is running.

Issues

View or log issues on the Issues tab in the repo.

Contributing

Please see the contributing guidelines.

Copyright and license

Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT license.

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.

msgraph-sdk-python-core's People

Contributors

andrueastman avatar baywet avatar dependabot[bot] avatar fey101 avatar github-actions[bot] avatar isvargasmsft avatar jmichael7 avatar jobala avatar kenchrcum avatar levensailor avatar michaelmainer avatar microsoft-github-policy-service[bot] avatar musale avatar ndagistanley avatar omonimus1 avatar rajatdiptabiswas avatar samwelkanda avatar shemogumbe avatar william-lp avatar

Stargazers

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

Watchers

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

msgraph-sdk-python-core's Issues

Is a HTTPClient appropriate?

Having had some time to review this code and also the Python requests library I am wondering if it is wise to create our own _HTTPClient class. The Python requests library exposes a module, not a class, so the behavior we are creating is potentially not consistent with how users expect requests to work.

One of primary goals is to simplify retrofitting existing applications that are calling the Graph using requests with our library.

Looking at the example code from PR #1 our calling pattern looks like:

    from msgraph_sdk_python import HTTPClientFactory
    requests = HTTPClientFactory.with_graph_middlewares(middlewares)
    response = requests.get('/me')

If an existing application already has import requests, what happens when we call requests.get ?

From what I can tell the requests object now derives from Session, but has some of the requests api added. If we keep this approach we would need to implement them all to not break existing calls to requests.

Is there an advantage to sub-classing Session? Could the "with_graph_middlewares" not just mount the custom HttpAdapter? Perhaps it could return the session if the consumer decides they want further configure it? Perhaps it should accept an existing session if other configuration has already been done to it?

While our goal is to have similar architectural concepts across languages, the role of HttpClientFactory is to configure the native library to make HTTP requests in a way that is most suited for calling Microsoft Graph. It may not actually need to construct an instance of a HttpClient. That would be an example of us taking our foreign C# pattern and applying it to a different platform.

There is something not quite right about using a variable name to pretend that our class instance is the requests module, but then it actually be a Session and therefore you need to know to close requests, which is something a Python dev has never had to do before. There is something "uncanny valley" about this.

Thoughts? /cc @jobala @ddyett @MIchaelMainer

Documentation

  • Document how to build the library
  • Add module level docstrings
  • Add class level docstrings
  • Add function/method docstrings

Delete or update deprecated test.pypi and pypi projects

Wisely update the package availability and statements to make it clear which Python packages are intended to be used and that are on our support path. Yank releases where it is expected that a customer could have taken a dependency - make sure you add a reason so that pip will display a message about the status of the package. Delete packages that no one could've taken a dependency on. Another avenue to communicate is to update _init.py which provides the summary for the package, as well as update readme files so that we clearly communicate the quality stage for a package.

"This package has been deprecated. Please switch to the msgraph-core package in main PyPI."
AB#9824

RequestContext Object/Alternative

The design doc specifies a RequestContext object to be passed along with the request object to customize middleware behavior. As it stands, the behavior of middleware is adjusted by passing configuration as a dictionary of keyword arguments when initializing the graph session or per request.
AB#8654

401 Handling

Trap 401 responses and pass information in the www-authenticate header to help generate a valid authorization token and re-issue the request.

Passing stream=True to get fails

I was using stream in the GraphSession version, but got this error, migrating to GraphClient (0.1.2):

    result = graph_get(nextLink, stream=True)
  File "/home/allan/projects/sixtus/graphpoc/./getusers.py", line 71, in graph_get
    result = graph_client.get(url, scopes=scopes, **kwargs)
  File "/home/allan/.pyenv/versions/graphpoc/lib/python3.9/site-packages/msgraph/core/_graph_client.py", line 74, in get
    prepared_request = self.prepare_request('GET', self._graph_url(url), **kwargs)
  File "/home/allan/.pyenv/versions/graphpoc/lib/python3.9/site-packages/msgraph/core/_graph_client.py", line 25, in wrapper
    request = func(*args, **kwargs)
  File "/home/allan/.pyenv/versions/graphpoc/lib/python3.9/site-packages/msgraph/core/_graph_client.py", line 129, in prepare_request
    req = Request(method, url, **kwargs)
TypeError: __init__() got an unexpected keyword argument 'stream'

I did a quick fix for me, which you are welcome to implement generically:

def get(self, url: str, **kwargs):
    r"""Sends a GET request. Returns :class:`Response` object.
    :param url: URL for the new :class:`Request` object.
    :param \*\*kwargs: Optional arguments that ``request`` takes.
    :rtype: requests.Response
    """
    stream = kwargs.pop('stream', None)
    prepared_request = self.prepare_request('GET', self._graph_url(url), **kwargs)
    return self.graph_session.send(prepared_request, stream=stream)

Is support for stream planned?
AB#10115

No reply address configured

I get an error right when I give consent to the application.

Message: AADSTS500113: No reply address is registered for the application.

I enabled the default URL in authentication section of application. Any suggestion what's wrong here.

Current URL where i get error is

https://login.microsoftonline.com/common/Consent/Set

What shouls be the expected reply url in Azure app registration as per this app ?

Sample

A simple sample that uses the client library and demonstrates the developer experience

Issue with scopes

I'm trying to run this super basic query with a slight deviation from the one in the readme and I'm already failing...
What am I doing wrong?

from azure.identity import ClientSecretCredential
from msgraphcore import GraphSession
import os, json

scopes = ['mail.send', 'user.read']

# Use device code flow as we're a console app
graph_credentials = ClientSecretCredential(
    client_id=os.environ["AZURE_CLIENT_ID"],
    client_secret=os.environ["AZURE_CLIENT_SECRET"],
    tenant_id=os.environ["AZURE_TENANT_ID"]
)
graph_session = GraphSession(graph_credentials, scopes)

result = graph_session.get('/me')
print(result.json())

Error message is:

azure.core.exceptions.ClientAuthenticationError: Unexpected response '{'error': 'invalid_scope', 'error_description': "AADSTS70011: The provided request must include a 'scope' input parameter. The provided value for the input parameter 'scope' is not valid. The scope mail.send user.read is not valid.\r\nTrace ID: b0c68aec-4c59-4596-84cb-6b8c7959c100\r\nCorrelation ID: c56e3743-7939-4d8b-8823-9e58a247e800\r\nTimestamp: 2020-06-26 02:25:06Z", 'error_codes': [70011], 'timestamp': '2020-06-26 02:25:06Z', 'trace_id': 'b0c68aec-4c59-4596-84cb-6b8c7959c100', 'correlation_id': 'c56e3743-7939-4d8b-8823-9e58a247e800'}'

Use TLS 1.2

Overview

Enforce Requests to use an arbitrary TLS version -- TLS 1.2

Notes

We can enforce Requests to use an arbitrary TLS version through a HTTPAdapter. However, we can only mount one HTTPAdapter at any time. We are already using a HTTPAdapter to implement the middleware pipeline. To support TLS 1.2 and middlewares at the same time, we need to write a HTTPAdapter that enforces use of TLS 1.2 and supports a middleware pipeline.

Multiple Graph Session objects

Describe the bug
Graph Sessions objects do not seems to be independant.

To Reproduce
Steps to reproduce the behavior:

Get users tenant A

client_secret_credentials = ClientSecretCredential(tenant_id='tenant_a',
client_id='xxxx-xxxx-xxxx',
client_secret=client_secret)

graph_session = GraphSession(client_secret_credentials, scopes)
result_a = graph_session.get('/users')

client_secret_credentials = ClientSecretCredential(tenant_id='tenant_b',
client_id='xxxx-xxxx-xxxx',
client_secret=client_secret)

Get users tenant B

graph_session = GraphSession(client_secret_credentials, scopes)
result_b = graph_session.get('/users')

print(result_a.content) # users tenant A
print(result_b.content) # users tenant A!

Expected behavior
print(result_b.content) # users tenant B
AB#9198

Issue with sending emails

Hello, I'm trying to send an email from Python app using Microsoft Graph SDK. The code that I show below runs well and does not throw any error. However I do not receive any email to the email address indicated in toRecipients.
What is missing?

import os
from msgraphcore import GraphSession
from azure.identity import ClientSecretCredential

scopes = ['user.read']
    graph_credentials = ClientSecretCredential(
      client_id=os.environ["AZURE_CLIENT_ID"],
      client_secret=os.environ[AZURE_CLIENT_SECRET"],
      tenant_id=os.environ[AZURE_TENANT_ID"]
)
graph_session = GraphSession(graph_credentials, scopes)
post_sample(graph_session)


def post_sample(graph_session):
    body = {
        'message': {
            'subject': 'Python SDK test',
            'body': {
                'contentType': 'Text',
                'content': 'Bla-bla-bla.'
            },
            'toRecipients': [{
                'emailAddress': {
                    'address': '[email protected]'
                }
            }]
        }
    }

    # ['mail.send']
    result = graph_session \
        .post('/me/microsoft.graph.sendMail',
              data=json.dumps(body),
              scopes=['.default'],
              headers={'Content-Type': 'application/json'}
              )
    print(result.status_code)

AB#8590

Add Github labels

Add the same Github labels as other msgraph-sdks for consistency across repos.

HTTP Proxy

Do we need a custom adapter to enable a developer to configure a HTTP proxy that will be used for outgoing requests or can we reuse the default python requests library proxy mechanism.

A sample implementation based on the requests library would look follows:

from msgraphcore import GraphSession

device_credentials = DefaultAzureCredential()
scopes = ['.default']

graph_session = GraphSession(device_credentials, scopes)

# If you need to use a proxy, you can configure it once for the entire `Session`

proxies = {
  'http': 'http://10.10.1.10:3128',
  'https': 'http://10.10.1.10:1080',
}
graph_session.proxies.update(proxies)

# Or you can also configure individual requests with the `proxies` argument to any request method:

proxies = {
  'http': 'http://10.10.1.10:3128',
  'https': 'http://10.10.1.10:1080',
}

graph_session.get("https://graph.microsoft.com/v1.0/me", proxies=proxies)

AB#9806

Issue with dependency list in msgraphcore pip package

The package published to pypi is missing requests==2.23.0, when installing via pip, the said package is missing the dependency in the setup.py

Python Version: python3.8
Pip Version: 20.1.1

The following error gets thrown when attempting to install:

Collecting https://test-files.pythonhosted.org/packages/48/d3/693a1555d7f715ddf7f29ae9f1487579882203596199a8003c16154ae27e/msgraphcore-0.0.1.tar.gz
  Downloading https://test-files.pythonhosted.org/packages/48/d3/693a1555d7f715ddf7f29ae9f1487579882203596199a8003c16154ae27e/msgraphcore-0.0.1.tar.gz (19 kB)
ERROR: https://test-files.pythonhosted.org/packages/48/d3/693a1555d7f715ddf7f29ae9f1487579882203596199a8003c16154ae27e/msgraphcore-0.0.1.tar.gz has a pyproject.toml file that does not comply with PEP 518: 'build-system.requires' contains an invalid requirement: 'requests = 2.23.0'

The current setup.py contains this:

#!/usr/bin/env python


from distutils.core import setup

packages = \
['msgraphcore']

package_data = \
{'': ['*'], 'msgraphcore': ['middleware/*', 'middleware\\options/*']}

setup(name='msgraphcore',
      version='0.0.2',
      description='msgraph-core',
      author='Microsoft',
      author_email='[email protected]',
      url=None,
      packages=packages,
      package_data=package_data,
     )

The proposed setup.py should contain the additional dependency when published:

#!/usr/bin/env python


from distutils.core import setup

packages = \
['msgraphcore']

package_data = \
{'': ['*'], 'msgraphcore': ['middleware/*', 'middleware\\options/*']}

setup(name='msgraphcore',
      version='0.0.2',
      install_requires=[
      	'requests==2.23.0'
      ],
      description='msgraph-core',
      author='Microsoft',
      author_email='[email protected]',
      url=None,
      packages=packages,
      package_data=package_data,
     )

AB#7078

Add a GraphClientFactory

Provides end users with the functionality to disable/rearrange the default middleware, and configure their own custom middleware pipeline.

AB#8653

API version in during request

Would be nice to have only one session and be able to make requests to all endpoints (v1.0, beta).
Currently api_version is a parameter in GraphSession.__init__.
I would suggest to put this parameter into all request-methods.
AB#7080

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.