Microsoft 365 & Microsoft Graph Library for Python
MIT License
Bot releases are hidden (Show)
Published by vgrem over 2 years ago
SharePoint API:
ListItem.validate_update_list_item
method: setting dates_in_utc
as an optional parameter (#509)Search
namespace enhancements #496SearchService.query
methodctx = ClientContext(site_url).with_credentials(credentials)
search = SearchService(ctx)
result = search.query("IsDocument:1").execute_query()
SearchService.post_query
methodctx = ClientContext(site_url).with_credentials(credentials)
search = SearchService(ctx)
request = SearchRequest(query_text="IsDocument:1",
sort_list=[Sort("LastModifiedTime", 1)],
select_properties=["Path", "LastModifiedTime"],
row_limit=20)
result = search.post_query(request).execute_query()
Published by vgrem over 2 years ago
SharePoint API:
ListItem
introduced support for system metadata update (#330)SiteProperies.update
method bug fix #480Web.ensure_folder_path
method bug fix #452ListItem
system updatePrefer ListItem.validate_update_list_item
method which supports overriding system metadata,
Here is an example which demonstrates how to update list item system metadata (namely Author
and Modified
field values):
ctx = ClientContext(site_url).with_credentials(credentials)
list_tasks = ctx.web.lists.get_by_title("Tasks")
items = list_tasks.items.get().top(1).execute_query()
if len(items) == 0:
sys.exit("No items for update found")
item_to_update = items[0] # type: ListItem
author = ctx.web.site_users.get_by_email(user_principal_name)
modified_date = datetime.utcnow() - timedelta(days=3)
result = item_to_update.validate_update_list_item({
"Author": FieldUserValue.from_user(author),
"Modified": modified_date
}).execute_query()
has_any_error = any([item.HasException for item in result.value])
if has_any_error:
print("Item update completed with errors, for details refer 'ErrorMessage' property")
else:
print("Item has been updated successfully")
Published by vgrem over 2 years ago
Example:
from office365.graph_client import GraphClient
from office365.onedrive.driveitems.driveItem import DriveItem
def print_download_progress(offset):
print("Downloaded '{0}' bytes...".format(offset))
client = GraphClient(acquire_token_by_username_password)
# # 1. address file by path and get file metadata
file_item = client.me.drive.root.get_by_path("archive/big_buck_bunny.mp4").get().execute_query() # type: DriveItem
# 2 download a large file (chunked file download)
with tempfile.TemporaryDirectory() as local_path:
with open(os.path.join(local_path, file_item.name), 'wb') as local_file:
file_item.download_session(local_file, print_download_progress).execute_query()
print("File '{0}' has been downloaded into {1}".format(file_item.name, local_file.name))
#430: improved support for overriding underlying HTTP request settings(such as proxy and SSL) by @juguerre
#465: SharePoint API: allow passing scopes via certificate authentication method by @theodoriss
Example
from office365.sharepoint.client_context import ClientContext
cert_settings = {
'client_id': '-- app id--',
'thumbprint': "-- cert thumbprint--",
'cert_path': 'mycert.pem'),
'scopes': ['https://contoso.onmicrosoft.com/.default']
}
ctx = ClientContext(test_site_url).with_client_certificate(test_tenant, **cert_settings)
current_web = ctx.web.get().execute_query()
print("{0}".format(current_web.url))
#461: include pytz
to install dependency by @Zahlii
Microsoft Graph API: Improved support for delta queries (official docs)
Example: get incremental changes for users
client = GraphClient(acquire_token_func)
changed_users = self.client.users.delta.get().execute_query()
Published by vgrem almost 3 years ago
publishing
& webhooks
namespacesThe example demonstrates how to create a Site Page
ctx = ClientContext(team_site_url).with_credentials(client_credentials)
new_page = ctx.site_pages.pages.add()
new_page.save_draft(title="My news page")
new_page.publish().execute_query()
The example demonstrates how to create a webhook to SharePoint list:
ctx = ClientContext(site_url).with_credentials(client_credentials)
push_service_url = "https://westeurope0.pushnp.svc.ms/notifications?token=526a9d28-d4ec-45b7-81b9-4e1599524784"
target_list = client.web.lists.get_by_title("Documents")
subscription = target_list.subscriptions.add(push_service_url).execute_query()
where
push_service_url - your service endpoint URL. SharePoint sends an HTTP POST to this endpoint when events occur in the specified resource
Refer Overview of SharePoint webhooks for a details.
Create plannerTask
endpoint)from office365.graph_client import GraphClient
client = GraphClient(acquire_token_func)
plan = ensure_plan(client.me.planner, "My plan")
task = client.planner.tasks.add(title="New task", planId=plan.id).execute_query()
Get MIME content of a message
endpoint)The example demonstrates how to download an Outlook message body in MIME format and save into a file:
client = GraphClient(acquire_token_func)
# requires Mail.ReadWrite permission
user = client.users[test_user_principal_name]
messages = user.messages.select(["id"]).top(10).get().execute_query()
with tempfile.TemporaryDirectory() as local_path:
for message in messages: # type: Message
with open(os.path.join(local_path, message.id + ".eml"), 'wb') as local_file:
message.download(local_file).execute_query() # download MIME representation of a message
Published by vgrem about 3 years ago
SecurableObject.get_user_effective_permissions
de-serializing response bug fixedctx = ClientContext(team_site_url).with_credentials(client_credentials)
version = ctx.web.get_file_by_server_relative_path(file_url).versions.get_by_id(512)
with open(download_path, "wb") as local_file:
file = version.download(local_file).execute_query()
Documentation:
Documentation: ListItem.GetUserEffectivePermissions
method
from pprint import pprint
from office365.sharepoint.client_context import ClientContext
from office365.sharepoint.permissions.permission_kind import PermissionKind
client = ClientContext(team_site_url).with_credentials(user_credentials)
file_url = "/sites/team/Shared Documents/Guide.docx"
target_user = client.web.site_users.get_by_email(test_user_principal_name_alt)
target_file = client.web.get_file_by_server_relative_path(file_url)
result = target_file.listItemAllFields.get_user_effective_permissions(target_user).execute_query()
pprint(result.value.permission_levels) # print all permission levels
# verify whether user has Reader role to a file
if result.value.has(PermissionKind.OpenItems):
print("User has access to read a file")
Documentation: reportRoot: getOffice365ActivationsUserCounts
import msal
from office365.graph_client import GraphClient
def acquire_token_by_client_credentials():
settings = load_settings()
authority_url = 'https://login.microsoftonline.com/{0}'.format(tenant)
app = msal.ConfidentialClientApplication(
authority=authority_url,
client_id=client_id,
client_credential=client_secret
)
return app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])
client = GraphClient(acquire_token_by_client_credentials)
result = client.reports.get_office365_activations_user_counts().execute_query()
Documentation: use the Microsoft Search API to search content in OneDrive and SharePoint
import msal
from office365.graph_client import GraphClient
def acquire_token_by_client_credentials():
settings = load_settings()
authority_url = 'https://login.microsoftonline.com/{0}'.format(tenant)
app = msal.ConfidentialClientApplication(
authority=authority_url,
client_id=client_id,
client_credential=client_secret
)
return app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])
client = GraphClient(acquire_token_by_client_credentials)
result = client.search.query("Guide.docx", entity_types=["driveItem"]).execute_query()
Published by vgrem about 3 years ago
generator
module @rikeshtailorWeb.get_folder_by_server_relative_path
return type fix @sharifhsnPublished by vgrem about 3 years ago
communications
API has been introducedtests
)Example 1: address folder by path, where archive/2018
is a folder path:
folder_item = client.me.drive.root.get_by_path("archive/2018").get().execute_query() # type: DriveItem
Examples: list all teams
client = GraphClient(acquire_token_by_client_credentials)
teams = client.teams.get_all(["displayName"]).execute_query()
for team in teams: # type: Team
print(team.display_name)
Published by vgrem over 3 years ago
msal
1.12.0ListItem.update
method (related #365)Published by vgrem over 3 years ago
SharePoint API: improved support for a file and folders addressing details
SharePoint API: support for saving taxonomy columns #353
Example: save a single-valued taxonomy field value
ctx = ClientContext(site_url).with_credentials(credentials)
tasks_list = ctx.web.lists.get_by_title("Tasks")
tax_field_value = TaxonomyFieldValue("{term-label}", "{term-guid}")
item_to_create = tasks_list.add_item({
"Title": "New task",
"{tex-column-name}": tax_field_value,
}).execute_query()
Example: save a multi-valued taxonomy field value
ctx = ClientContext(site_url).with_credentials(credentials)
tasks_list = ctx.web.lists.get_by_title("Tasks")
tax_field_value = TaxonomyFieldValue("{term-label}", "{term-guid}")
tax_field_values = TaxonomyFieldValueCollection([tax_field_value])
item_to_create = tasks_list.add_item({
"Title": "New task",
"{tex-column-name}": tax_field_values,
}).execute_query()
Published by vgrem over 3 years ago
Published by vgrem over 3 years ago
ClientObject.get_property()
semantics by @kraptorhubsite
namespace, File/Folder copy/move operations
def acquire_token_client_credentials():
authority_url = 'https://login.microsoftonline.com/{tenant}'
app = msal.ConfidentialClientApplication(
authority=authority_url,
client_id='{client-id}',
client_credential='{client-secret}'
)
result = app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])
return result
client = GraphClient(acquire_token_client_credentials)
current_user = self.client.users['{user-principal-name}'].get() # 1.1: construct query to retrieve user details
my_drive = self.client.users['{user-principal-name}'].drive.get() # 1.2: construct query to retrieve user's drive
client.execute_batch() # 2: submit a query to the server
Published by vgrem almost 4 years ago
Summary:
fields
, tenants
namespaces)Here are a few examples which demonstrate how to create field and set values for a different field types:
Create a multi lookup field:
lookup_field = list.fields.add_lookup_field(title=lookup_field_name,
lookup_list_id=lookup_list.properties['Id'],
lookup_field_name='Title',
allow_multiple_values=True).execute_query()
Set a multi lookup field value
field_value = FieldMultiLookupValue()
field_value.add(FieldLookupValue(lookup_id))
updated = item_to_update.set_property(lookup_field_name, field_value).update().execute_query()
The list of methods (fields
namespace):
FieldCollection.add_url_field(title)
FieldCollection.add_lookup_field(title, lookup_list_id, lookup_field_name, allow_multiple_values)
FieldCollection.add_choice_field(title, values, multiple_values)
FieldCollection.create_taxonomy_field(name, ssp_id, term_set_id, anchor_id,field_id, text_field_id, web_id, list_id)
The list of methods (tenant
namespace):
Tenant.get_site_health_status(site_url)
Published by vgrem almost 4 years ago
requests_ntlm
is included as an optional dependencyREADME.md
broken links resolvedPublished by vgrem almost 4 years ago
FileCollection.create_upload_session
method by @beliaev-maksim #289adal
library to msal
as a mandatory dependency #296sharepoint
namespace, new types and methods (Tenant
, ViewField
, ContentType
classes)OutlookClient
is decommissioned and no longer availablePublished by vgrem almost 4 years ago
FieldCollection.create_field_as_xml
, FieldCollection.create_taxonomy_field
Published by vgrem about 4 years ago
Here is the comparison of two approaches, in the first example update operation is submitted to server per every list item, while in the second one multiple list item update operations are submitted via a since (batch) request:
list_tasks = ctx.web.lists.get_by_title("Tasks")
items = list_tasks.items.get().execute_query() #
for task_id, item in enumerate(items):
task_prefix = str(randint(0, 10000))
item.set_property("Title", f"Task {task_prefix}")
item.update()
ctx.execute_query() # <- update operation is submitted to server per every list item
list_tasks = ctx.web.lists.get_by_title("Tasks")
items = list_tasks.items.get().execute_query()
for task_id, item in enumerate(items):
task_prefix = str(randint(0, 10000))
item.set_property("Title", f"Task {task_prefix}")
item.update()
ctx.execute_batch() # <- construct a single (batch) for all list items and submit to server
list = client.web.lists.get_by_title(list_title)
list.delete_object()
client.execute_query()
list delete operation could be constructed and submitted to a server in a more compact manner:
client.web.lists.get_by_title(list_title).delete_object().execute_query()
SharePoint API Changes
namespace improvements (#259), here is the list of operations:
Site.get_changes
Web.get_changes
List.get_changes
ListItem.get_changes
SharePoint API RecycleBin
entity class and operations
Published by vgrem about 4 years ago
Finally the initial support for SharePoint API Batch requests has been introduced. All insert/update/delete operations are supported.
The following example how current user and web objects could be retrieved by grouping two operations and submitting it as a single request to the server:
client = ClientContext(site_url).with_credentials(user_credentials)
current_user = client.web.currentUser
client.load(current_user)
current_web = client.web
client.load(current_web)
client.execute_batch()
which offers a new way of improving the performance.
Among another improvements and changes:
improved support for Office365 auth with ADFS by @liuliqiu
style enforcement (flake8
), code formatting (isort
) configuration by @domdinicola
ClientRuntimeContext.execute_query_retry
method which implements Retry pattern
Published by vgrem over 4 years ago
The list of changes:
Published by vgrem over 4 years ago
ctx = ClientContext(settings['url']).with_credentials(credentials)
target_web = ctx.web.load().execute_query() #method chaining
print(target_web.url)
Web
and File
resources by absolute Urlabs_file_url = "https://{tenant}.sharepoint.com/sites/team/Shared Documents/sample.docx".format(tenant=tenant)
user_credentials = UserCredential(username, password)
with open(local_path, 'wb') as local_file:
file = File.from_url(abs_file_url).with_credentials(user_credentials).download(local_file).execute_query()
print("'{0}' file has been downloaded".format(file.serverRelativeUrl))
According to Documentation
Search in SharePoint includes a Search REST service you can use to add search functionality to your client and mobile applications by
using any technology that supports REST web requests.
Example
The following example demonstrates how to construct a search for a documents (via Keyword Query Language syntax) and print file url (Path
managed property)
from office365.runtime.auth.userCredential import UserCredential
from office365.sharepoint.client_context import ClientContext
from office365.sharepoint.search.searchRequest import SearchRequest
from office365.sharepoint.search.searchService import SearchService
from settings import settings
ctx = ClientContext.connect_with_credentials(site_url,
UserCredential(username, password))
search = SearchService(ctx)
request = SearchRequest("IsDocument:1")
result = search.post_query(request)
ctx.execute_query()
relevant_results = result.PrimaryQueryResult.RelevantResults
for i in relevant_results['Table']['Rows']:
cells = relevant_results['Table']['Rows'][i]['Cells']
print(cells[6]['Value'])
The following example demonstrates how to create a site collection via Tenant.CreateSite method
:
admin_site_url = "https://{0}-admin.sharepoint.com/".format(tenant)
credentials = UserCredential(username, password)
client = ClientContext(admin_site_url).with_credentials(credentials)
tenant = Tenant(client)
props = SiteCreationProperties(target_site_url, user_principal_name)
site_props = tenant.ensure_site(props)
client.execute_query()
Creating list item and setting multi lookup field value:
create_info = {
"Title": "New task"
}
multi_lookup_value = FieldMultiLookupValue()
multi_lookup_value.add(FieldLookupValue(lookup_id))
new_item = self.target_list.add_item(create_info)
new_item.set_property("Predecessors", multi_lookup_value)
client.load(items)
client.execute_query()
Updating list item with multi choice field value:
multi_choice_value = FieldMultiChoiceValue(["In Progress"])
item_to_update.set_property("TaskStatuses", multi_choice_value)
item_to_update.update()
client.execute_query()
#210: connect to Office 365 with federated accounts, credit goes to @liuliqiu
#206: SharePoint Session API upload
Published by vgrem over 4 years ago
and more
The support for Microsoft Teams API has been introduced, the following example demonstrates how how create a new team under a group which corresponds to Create team
endpoint
tenant_name = "contoso.onmicrosoft.com"
client = GraphClient(tenant_name, get_token)
new_team = client.groups[group_id].add_team()
client.execute_query()
where
def get_token(auth_ctx):
"""Acquire token via client credential flow (ADAL Python library is utilized)
:type auth_ctx: adal.AuthenticationContext
"""
token = auth_ctx.acquire_token_with_client_credentials(
"https://graph.microsoft.com",
client_id,
client_secret)
return token
Here is an example which demonstrates how to retrieve data from a SharePoint list which contains more then 5k items:
def print_progress(items_read):
print("Items read: {0}".format(items_read))
ctx = ClientContext.connect_with_credentials(site_url,
ClientCredential(client_id,client_secret))
list_source = ctx.web.lists.get_by_title("Contacts_Large")
items = list_source.items
items.page_loaded += print_progress # page load event
items.page_size = 400 # specify custom page size (default is 100)
ctx.load(items)
ctx.execute_query()
#print("Items count: {0}".format(len(items)))
for item in items:
print("{0}".format(item.properties['Title']))
The example demonstrates how to connect to SharePoint Online with certificate credentials:
ctx = ClientContext.connect_with_certificate(site_url,
client_id,
thumbprint,
certificate_path)
current_web = ctx.web
ctx.load(current_web)
ctx.execute_query()
print("{0}".format(current_web.url))
Refer how-to page for a more details
In terms of file and folder operations the following methods have been introduced:
File.download(file_object)
- download a file content into a file object (SharePoint API)Folder.copyto(new_folder_url, overwrite)
- copy a folder (SharePoint API)Folder.moveto(new_folder_url, flags)
move a folder (SharePoint API)DriveItem.download
(file_object) - downloads a file content into a file object (OneDrive API)DriveItem.get_content()
- downloads a file content (OneDrive API)