diff --git a/README.md b/README.md index 5c83e4c5a..f8e8a7afc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # About -Office 365 & Microsoft Graph library for Python +Microsoft 365 & Microsoft Graph library for Python # Usage @@ -356,11 +356,11 @@ def download_files(remote_folder, local_path): Additional examples: - [create list column](examples/onedrive/columns/create_text.py) -- [download file](examples/onedrive/files/download_default.py) +- [download file](examples/onedrive/files/download.py) - [export files](examples/onedrive/files/export.py) - [upload folder](examples/onedrive/folders/upload.py) - [list drives](examples/onedrive/drives/list.py) -- [list files](examples/onedrive/folders/list_with_files.py) +- [list files](examples/onedrive/folders/list_files.py) Refer to [OneDrive examples section](examples/onedrive) for more examples. diff --git a/examples/onedrive/columns/list_site.py b/examples/onedrive/columns/list_site.py index 1322aa68e..521c62a4b 100644 --- a/examples/onedrive/columns/list_site.py +++ b/examples/onedrive/columns/list_site.py @@ -1,12 +1,12 @@ """ Retrieves site columns +https://learn.microsoft.com/en-us/graph/api/site-list-columns?view=graph-rest-1.0 """ from office365.graph_client import GraphClient -from office365.onedrive.columns.definition import ColumnDefinition from tests.graph_case import acquire_token_by_username_password client = GraphClient(acquire_token_by_username_password) columns = client.sites.root.columns.get().execute_query() for column in columns: - print(column.name) + print(column) diff --git a/examples/onedrive/drives/list.py b/examples/onedrive/drives/list.py index 0248750a8..5b29d3752 100644 --- a/examples/onedrive/drives/list.py +++ b/examples/onedrive/drives/list.py @@ -1,7 +1,7 @@ """ List available drives -https://learn.microsoft.com/en-us/graph/api/drive-list?view=graph-rest-1.0&tabs=http +https://learn.microsoft.com/en-us/graph/api/drive-list?view=graph-rest-1.0 """ from office365.graph_client import GraphClient from tests.graph_case import acquire_token_by_client_credentials diff --git a/examples/onedrive/drives/list_recent_files.py b/examples/onedrive/drives/list_recent_files.py new file mode 100644 index 000000000..37f4054e2 --- /dev/null +++ b/examples/onedrive/drives/list_recent_files.py @@ -0,0 +1,14 @@ +""" +List recent files + +https://learn.microsoft.com/en-us/graph/api/drive-recent?view=graph-rest-1.0 +""" +from office365.graph_client import GraphClient +from tests import test_client_id, test_password, test_tenant, test_username + +client = GraphClient.with_username_and_password( + test_tenant, test_client_id, test_username, test_password +) +items = client.me.drive.recent().execute_query() +for item in items: + print(item.web_url) diff --git a/examples/onedrive/files/list_shared_with_me.py b/examples/onedrive/drives/list_shared_with_me.py similarity index 100% rename from examples/onedrive/files/list_shared_with_me.py rename to examples/onedrive/drives/list_shared_with_me.py diff --git a/examples/onedrive/excel/__init__.py b/examples/onedrive/excel/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/onedrive/excel/read_worksheet.py b/examples/onedrive/excel/read_worksheet.py index ecfaff9b8..d08f2b275 100644 --- a/examples/onedrive/excel/read_worksheet.py +++ b/examples/onedrive/excel/read_worksheet.py @@ -1,13 +1,19 @@ +""" +Retrieve a list of worksheet objects. + +https://learn.microsoft.com/en-us/graph/api/workbook-list-worksheets?view=graph-rest-1.0 +""" + import sys -from examples.onedrive import upload_excel_sample from office365.graph_client import GraphClient from tests.graph_case import acquire_token_by_username_password client = GraphClient(acquire_token_by_username_password) -drive_item = upload_excel_sample(client) -# Load worksheets +drive_item = client.me.drive.root.get_by_path("Financial Sample.xlsx") worksheets = drive_item.workbook.worksheets.get().execute_query() if len(worksheets) == 0: sys.exit("No worksheets found") -print("Worksheet name: {0}".format(worksheets[0].name)) + +for worksheet in worksheets: + print("Worksheet name: {0}".format(worksheet)) diff --git a/examples/onedrive/files/__init__.py b/examples/onedrive/files/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/onedrive/files/download_default.py b/examples/onedrive/files/download.py similarity index 100% rename from examples/onedrive/files/download_default.py rename to examples/onedrive/files/download.py diff --git a/examples/onedrive/files/download_large.py b/examples/onedrive/files/download_large.py index 23fe9ee38..34daad210 100644 --- a/examples/onedrive/files/download_large.py +++ b/examples/onedrive/files/download_large.py @@ -14,6 +14,7 @@ def print_progress(offset): + # type: (int) -> None print("Downloaded '{0}' bytes...".format(offset)) diff --git a/examples/onedrive/files/export.py b/examples/onedrive/files/export.py index 1dcffb189..c4abdf10f 100644 --- a/examples/onedrive/files/export.py +++ b/examples/onedrive/files/export.py @@ -8,16 +8,18 @@ import tempfile from office365.graph_client import GraphClient -from office365.onedrive.drives.drive import Drive +from office365.onedrive.driveitems.driveItem import DriveItem from tests import test_user_principal_name from tests.graph_case import acquire_token_by_client_credentials client = GraphClient(acquire_token_by_client_credentials) -drive = client.users[test_user_principal_name].drive # type: Drive +drive = client.users[test_user_principal_name].drive with tempfile.TemporaryDirectory() as local_path: drive_items = drive.root.children.get().execute_query() - file_items = [item for item in drive_items if item.file is not None] # files only + file_items = [ + item for item in drive_items if item.file is not None + ] # type: list[DriveItem] for drive_item in file_items: with open(os.path.join(local_path, drive_item.name), "wb") as local_file: - drive_item.download(local_file).execute_query() # download file content + drive_item.download(local_file).execute_query() print("File '{0}' has been downloaded".format(local_file.name)) diff --git a/examples/onedrive/files/get_by_abs_url.py b/examples/onedrive/files/get_by_abs_url.py index b53ab37eb..7d8fa9d28 100644 --- a/examples/onedrive/files/get_by_abs_url.py +++ b/examples/onedrive/files/get_by_abs_url.py @@ -1,5 +1,5 @@ """ - +Retrieves file by absolute url """ from office365.graph_client import GraphClient from tests import test_team_site_url @@ -9,4 +9,4 @@ client = GraphClient(acquire_token_by_username_password) file_item = client.shares.by_url(file_abs_url).drive_item.get().execute_query() -print(f"Drive item Id: {file_item.web_url}") +print(file_item.web_url) diff --git a/examples/onedrive/files/upload.py b/examples/onedrive/files/upload.py index 42c786145..e4221a99f 100644 --- a/examples/onedrive/files/upload.py +++ b/examples/onedrive/files/upload.py @@ -9,9 +9,7 @@ from tests.graph_case import acquire_token_by_client_credentials client = GraphClient(acquire_token_by_client_credentials) -folder = client.users.get_by_principal_name( - test_user_principal_name_alt -).drive.root.get_by_path("archive") +folder = client.users.get_by_principal_name(test_user_principal_name_alt).drive.root local_path = "../../data/Financial Sample.xlsx" file = folder.upload_file(local_path).execute_query() diff --git a/examples/onedrive/folders/__init__.py b/examples/onedrive/folders/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/onedrive/lists/create_list.py b/examples/onedrive/lists/create_list.py index 3854f200f..f3dae2c1c 100644 --- a/examples/onedrive/lists/create_list.py +++ b/examples/onedrive/lists/create_list.py @@ -10,10 +10,12 @@ from tests.graph_case import acquire_token_by_client_credentials client = GraphClient(acquire_token_by_client_credentials) + print("Creating a custom list...") custom_list = client.sites.root.lists.add( create_unique_name("Books"), "genericList" ).execute_query() print("List has been created at {0}".format(custom_list.web_url)) + print("Cleaning up resources...") custom_list.delete_object().execute_query() diff --git a/examples/onedrive/lists/get_metadata.py b/examples/onedrive/lists/get_metadata.py index 0953e180c..e86d353de 100644 --- a/examples/onedrive/lists/get_metadata.py +++ b/examples/onedrive/lists/get_metadata.py @@ -1,7 +1,7 @@ """ Get metadata for a list -https://learn.microsoft.com/en-us/graph/api/list-get?view=graph-rest-1.0&tabs=http +https://learn.microsoft.com/en-us/graph/api/list-get?view=graph-rest-1.0 """ from office365.graph_client import GraphClient diff --git a/examples/onedrive/sites/grant_permission.py b/examples/onedrive/sites/grant_permission.py index b547b55ec..26d45bbe0 100644 --- a/examples/onedrive/sites/grant_permission.py +++ b/examples/onedrive/sites/grant_permission.py @@ -1,9 +1,8 @@ """ -Grant permissions on a site. +Grants permissions on a site. https://learn.microsoft.com/en-us/graph/api/site-post-permissions?view=graph-rest-1.0 """ -import json from office365.graph_client import GraphClient from tests import test_client_credentials, test_team_site_url @@ -16,5 +15,5 @@ print("Granting an Application a permissions on Site...") site = client.sites.get_by_url(test_team_site_url) -permission = site.permissions.add(["read", "write"], app).execute_query() -print(json.dumps(permission.granted_to.to_json(), indent=4)) +permission = site.permissions.add(["write"], app).execute_query() +print(permission.granted_to) diff --git a/examples/onedrive/sites/list_permission.py b/examples/onedrive/sites/list_permission.py new file mode 100644 index 000000000..8b1871fca --- /dev/null +++ b/examples/onedrive/sites/list_permission.py @@ -0,0 +1,15 @@ +""" +Lists site permissions. + +""" + +from office365.graph_client import GraphClient +from tests import test_team_site_url +from tests.graph_case import acquire_token_by_client_credentials + +client = GraphClient(acquire_token_by_client_credentials) + +site = client.sites.get_by_url(test_team_site_url) +permissions = site.permissions.get().execute_query() +for perm in permissions: + print(perm.granted_to) diff --git a/examples/onedrive/sites/revoke_permission.py b/examples/onedrive/sites/revoke_permission.py new file mode 100644 index 000000000..c4b3b324c --- /dev/null +++ b/examples/onedrive/sites/revoke_permission.py @@ -0,0 +1,16 @@ +""" +Revokes permissions from a site. + +https://learn.microsoft.com/en-us/graph/api/site-delete-permission?view=graph-rest-1.0 +""" + +from office365.graph_client import GraphClient +from tests import test_client_credentials, test_team_site_url +from tests.graph_case import acquire_token_by_client_credentials + +client = GraphClient(acquire_token_by_client_credentials) + +app = client.applications.get_by_app_id(test_client_credentials.clientId) +site = client.sites.get_by_url(test_team_site_url) +site.permissions.delete(["write"], app).execute_query() +# site.permissions.delete_all().execute_query() diff --git a/examples/onedrive/sites/search.py b/examples/onedrive/sites/search.py index 0f575083b..9ce040884 100644 --- a/examples/onedrive/sites/search.py +++ b/examples/onedrive/sites/search.py @@ -1,8 +1,6 @@ """ Search across a SharePoint tenant for sites that match keywords provided. - - https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/site_search?view=odsp-graph-online """ diff --git a/examples/sharepoint/folders/get_by_shared_link.py b/examples/sharepoint/folders/get_by_shared_link.py new file mode 100644 index 000000000..e72a7a2eb --- /dev/null +++ b/examples/sharepoint/folders/get_by_shared_link.py @@ -0,0 +1,16 @@ +""" +Returns the folder object from the tokenized sharing link URL. +""" +from office365.sharepoint.client_context import ClientContext +from office365.sharepoint.sharing.links.kind import SharingLinkKind +from tests import test_team_site_url, test_user_credentials + +ctx = ClientContext(test_team_site_url).with_credentials(test_user_credentials) + +folder = ctx.web.get_folder_by_server_relative_url("Shared Documents/Archive") +# Share a folder +result = folder.share_link(SharingLinkKind.OrganizationView).execute_query() + + +shared_folder = ctx.web.get_folder_by_guest_url(str(result.value)).execute_query() +print(shared_folder) diff --git a/examples/sharepoint/folders/list_folders.py b/examples/sharepoint/folders/list_folders.py index 5c34dc79d..c84d32602 100644 --- a/examples/sharepoint/folders/list_folders.py +++ b/examples/sharepoint/folders/list_folders.py @@ -8,7 +8,7 @@ ctx = ClientContext(test_team_site_url).with_credentials(test_client_credentials) folders = ( - ctx.web.default_document_library().root_folder.get_folders(False).execute_query() + ctx.web.default_document_library().root_folder.get_files(False).execute_query() ) for folder in folders: print( diff --git a/examples/sharepoint/folders/rename.py b/examples/sharepoint/folders/rename.py new file mode 100644 index 000000000..0ca8af765 --- /dev/null +++ b/examples/sharepoint/folders/rename.py @@ -0,0 +1,15 @@ +""" +Demonstrates how to rename a folder +""" +from office365.sharepoint.client_context import ClientContext +from tests import create_unique_name, test_client_credentials, test_team_site_url + +ctx = ClientContext(test_team_site_url).with_credentials(test_client_credentials) + +folder = ctx.web.default_document_library().root_folder.add( + create_unique_name("Orders - (2007)") +) # create temp folder + +folder.rename("OUT - (Drafts 123)").execute_query() + +folder.delete_object().execute_query() diff --git a/examples/sharepoint/sites/get_admins.py b/examples/sharepoint/sites/get_admins.py index a2e82217d..addd3ef1c 100644 --- a/examples/sharepoint/sites/get_admins.py +++ b/examples/sharepoint/sites/get_admins.py @@ -3,9 +3,9 @@ """ from office365.sharepoint.client_context import ClientContext -from tests import test_admin_credentials, test_site_url +from tests import test_admin_credentials, test_team_site_url -client = ClientContext(test_site_url).with_credentials(test_admin_credentials) +client = ClientContext(test_team_site_url).with_credentials(test_admin_credentials) result = client.site.get_site_administrators().execute_query() for info in result.value: print(info) diff --git a/examples/sharepoint/sites/get_basic_props.py b/examples/sharepoint/sites/get_basic_props.py index 91471f6b2..f95ed51a6 100644 --- a/examples/sharepoint/sites/get_basic_props.py +++ b/examples/sharepoint/sites/get_basic_props.py @@ -2,9 +2,9 @@ Gets site basic properties """ from office365.sharepoint.client_context import ClientContext -from tests import test_client_credentials, test_site_url +from tests import test_client_credentials, test_site_url, test_team_site_url -client = ClientContext(test_site_url).with_credentials(test_client_credentials) +client = ClientContext(test_team_site_url).with_credentials(test_client_credentials) site = client.site.get().execute_query() print("Site url: {}".format(site.url)) diff --git a/examples/sharepoint/sites/grant_app_access.py b/examples/sharepoint/sites/grant_app_access.py index 15d2afa62..7fa5e5694 100644 --- a/examples/sharepoint/sites/grant_app_access.py +++ b/examples/sharepoint/sites/grant_app_access.py @@ -3,40 +3,19 @@ Refer: https://developer.microsoft.com/en-us/office/blogs/controlling-app-access-on-specific-sharepoint-site-collections/ - """ -import json from office365.graph_client import GraphClient from tests import test_client_credentials, test_team_site_url from tests.graph_case import acquire_token_by_client_credentials - -def assign_site_access(site, application, roles=None, clear_existing=False): - """ - :param office365.onedrive.sites.site.Site site: Site the permissions to grant - :param office365.onedrive.directory.applications.Application application: Application - :param list[str] roles: The list of roles to add - :param bool clear_existing: Clear existing permissions first - """ - if clear_existing: - print("Clearing existing permissions...") - target_site.permissions.delete_all().execute_query() - - if roles: - print( - "Granting {0} permissions for application {1}".format( - roles, application.app_id - ) - ) - site.permissions.add(roles, application).execute_query() - - result = site.permissions.get().execute_query() - print("Current permissions: {0}".format(json.dumps(result.to_json(), indent=4))) - - client = GraphClient(acquire_token_by_client_credentials) -target_site = client.sites.get_by_url(test_team_site_url) +site = client.sites.get_by_url(test_team_site_url) app = client.applications.get_by_app_id(test_client_credentials.clientId) -# assign_site_access(user_site_url, [], True) -assign_site_access(target_site, app, ["read", "write"], True) +roles = ["read", "write"] + +print("Granting {0} permissions for application {1}".format(roles, app)) +site.permissions.add(roles, app).execute_query() +result = site.permissions.get().execute_query() +for perm in result: + print("Current permissions: {0}".format(perm.granted_to_identities)) diff --git a/examples/teams/create_team.py b/examples/teams/create_team.py index ef232e126..10679d41c 100644 --- a/examples/teams/create_team.py +++ b/examples/teams/create_team.py @@ -14,8 +14,8 @@ client = GraphClient(acquire_token_by_username_password) team_name = create_unique_name("Team") print("Creating a team '{0}' ...".format(team_name)) -new_team = client.teams.create(team_name).execute_query_and_wait() +team = client.teams.create(team_name).execute_query_and_wait() print("Team has been created") print("Cleaning up temporary resources... ") -new_team.delete_object().execute_query() +team.delete_object().execute_query() diff --git a/generator/import_metadata.py b/generator/import_metadata.py index 16166b566..cddc3963e 100644 --- a/generator/import_metadata.py +++ b/generator/import_metadata.py @@ -21,13 +21,13 @@ def export_to_file(path, content): "--endpoint", dest="endpoint", help="Import metadata endpoint", - default="sharepoint", + default="microsoftgraph", ) parser.add_argument( "-p", "--path", dest="path", - default="./metadata/SharePoint.xml", + default="./metadata/MicrosoftGraph.xml", help="Import metadata endpoint", ) diff --git a/generator/metadata/MicrosoftGraph.xml b/generator/metadata/MicrosoftGraph.xml index 4fc9a8cf2..4d48e12b6 100644 --- a/generator/metadata/MicrosoftGraph.xml +++ b/generator/metadata/MicrosoftGraph.xml @@ -21358,6 +21358,7 @@ + @@ -25293,6 +25294,13 @@ + + + + + + + diff --git a/office365/directory/applications/application.py b/office365/directory/applications/application.py index a53c2bbd9..ab406585b 100644 --- a/office365/directory/applications/application.py +++ b/office365/directory/applications/application.py @@ -30,6 +30,17 @@ class Application(DirectoryObject): an Application in Azure AD """ + def __repr__(self): + return self.id or self.app_id or self.entity_type_name + + def __str__(self): + if self.display_name: + return "Name: {0}".format(self.display_name) + elif self.app_id: + return "App Id: {0}".format(self.app_id) + else: + return self.entity_type_name + def add_certificate( self, cert_data, display_name, start_datetime=None, end_datetime=None ): @@ -62,7 +73,7 @@ def remove_certificate(self, thumbprint): Remove a certificate from an application. :param str thumbprint: The unique identifier for the password. """ - raise NotImplementedError("") + raise NotImplementedError("remove_certificate") def add_password(self, display_name): """Adds a strong password to an application. @@ -178,6 +189,7 @@ def application_template_id(self): @property def app_roles(self): + # type: () -> ClientValueCollection[AppRole] """ The collection of roles defined for the application. With app role assignments, these roles can be assigned to users, groups, or service principals associated with other applications @@ -191,16 +203,12 @@ def api(self): @property def certification(self): - """ - Specifies the certification status of the application. - """ + """Specifies the certification status of the application.""" return self.properties.get("certification", Certification()) @property def created_datetime(self): - """ - The date and time the application was registered. - """ + """The date and time the application was registered.""" return self.properties.get("createdDateTime", datetime.datetime.min) @property @@ -318,9 +326,3 @@ def get_property(self, name, default_value=None): } default_value = property_mapping.get(name, None) return super(Application, self).get_property(name, default_value) - - def __repr__(self): - return self.id - - def __str__(self): - return self.display_name diff --git a/office365/directory/rolemanagement/role.py b/office365/directory/rolemanagement/role.py index 495c28fc6..09f904d3f 100644 --- a/office365/directory/rolemanagement/role.py +++ b/office365/directory/rolemanagement/role.py @@ -8,7 +8,10 @@ class DirectoryRole(DirectoryObject): """Represents an Azure AD directory role. Azure AD directory roles are also known as administrator roles""" def __repr__(self): - return self.display_name + return self.id or self.entity_type_name + + def __str__(self): + return "Name: {0}".format(self.display_name) @property def description(self): diff --git a/office365/onedrive/columns/definition.py b/office365/onedrive/columns/definition.py index 4c54f9f77..06e4ba928 100644 --- a/office365/onedrive/columns/definition.py +++ b/office365/onedrive/columns/definition.py @@ -32,6 +32,12 @@ class ColumnDefinition(BaseItem): To list hidden field values on listItems, include the desired columns by name in your $select statement. """ + def __str__(self): + return self.name + + def __repr__(self): + return self.name or self.id or self.entity_type_name + @property def display_name(self): # type: () -> Optional[str] @@ -41,9 +47,7 @@ def display_name(self): @property def enforce_unique_values(self): # type: () -> Optional[bool] - """ - If true, no two list items may have the same value for this column. - """ + """If true, no two list items may have the same value for this column.""" return self.properties.get("enforceUniqueValues", None) @property @@ -195,9 +199,7 @@ def term(self): @property def type(self): # type: () -> Optional[str] - """ - For site columns, the type of column. - """ + """For site columns, the type of column.""" return self.properties.get("type", None) def get_property(self, name, default_value=None): diff --git a/office365/onedrive/driveitems/driveItem.py b/office365/onedrive/driveitems/driveItem.py index bcf568aa7..4f0944344 100644 --- a/office365/onedrive/driveitems/driveItem.py +++ b/office365/onedrive/driveitems/driveItem.py @@ -62,13 +62,30 @@ class DriveItem(BaseItem): """The driveItem resource represents a file, folder, or other item stored in a drive. All file system objects in OneDrive and SharePoint are returned as driveItem resources""" - def get_by_path(self, url_path): - # type: (str) -> "DriveItem" + def get_files(self, recursive=False): + """Retrieves files + :param bool recursive: Determines whether to enumerate folders recursively """ - Retrieve DriveItem by server relative path + return_type = EntityCollection(self.context, DriveItem) - :type url_path: str - """ + def _get_files(parent_drive_item): + # type: (DriveItem) -> None + def _after_loaded(): + for drive_item in parent_drive_item.children: + if drive_item.is_folder: + if recursive: + _get_files(drive_item) + else: + return_type.add_child(drive_item) + + parent_drive_item.ensure_properties(["children"], _after_loaded) + + _get_files(self) + return return_type + + def get_by_path(self, url_path): + # type: (str) -> "DriveItem" + """Retrieve DriveItem by server relative path""" return DriveItem( self.context, UrlPath(url_path, self.resource_path), self.children ) @@ -77,7 +94,6 @@ def create_powerpoint(self, name): # type: (str) -> "DriveItem" """ Creates a PowerPoint file - :param str name: File name """ return self.upload(name, None) @@ -140,18 +156,14 @@ def extract_sensitivity_labels(self): def follow(self): # type: () -> Self - """ - Follow a driveItem. - """ + """Follow a driveItem.""" qry = ServiceOperationQuery(self, "follow") self.context.add_query(qry) return self def unfollow(self): # type: () -> Self - """ - Unfollow a driveItem. - """ + """Unfollow a driveItem.""" qry = ServiceOperationQuery(self, "unfollow") self.context.add_query(qry) return self @@ -363,9 +375,7 @@ def copy(self, name=None, parent=None, conflict_behavior=ConflictBehavior.Fail): return_type = ClientResult(self.context) # type: ClientResult[str] def _create_request(request): - """ - :type request: office365.runtime.http.request_options.RequestOptions - """ + # type: (RequestOptions) -> None request.url += "?@microsoft.graph.conflictBehavior={0}".format( conflict_behavior ) @@ -533,7 +543,6 @@ def _create_query(): qry = _create_query() self.context.add_query(qry) - return return_type def permanent_delete(self): @@ -583,10 +592,7 @@ def preview(self, page, zoom=None): def validate_permission(self, challenge_token=None, password=None): # type: (Optional[str], Optional[str]) -> Self - """ - :type challenge_token: str - :type password: str - """ + """ """ payload = {"challengeToken": challenge_token, "password": password} qry = ServiceOperationQuery(self, "validatePermission", None, payload) self.context.add_query(qry) @@ -619,9 +625,7 @@ def photo(self): @property def location(self): # type: () -> GeoCoordinates - """ - Location metadata, if the item has location data. Read-only. - """ + """Location metadata, if the item has location data""" return self.properties.get("location", GeoCoordinates()) @property @@ -664,15 +668,12 @@ def shared(self): @property def web_dav_url(self): # type: () -> str or None - """ - WebDAV compatible URL for the item. - :rtype: str or None - """ + """WebDAV compatible URL for the item.""" return self.properties.get("webDavUrl", None) @property def children(self): - # type: () -> EntityCollection[DriveItem] + # type: () -> EntityCollection["DriveItem"] """Collection containing Item objects for the immediate children of Item. Only items representing folders have children. """ diff --git a/office365/onedrive/lists/list.py b/office365/onedrive/lists/list.py index 3d4ef9eef..b61ae66ee 100644 --- a/office365/onedrive/lists/list.py +++ b/office365/onedrive/lists/list.py @@ -1,3 +1,5 @@ +from typing import Optional + from office365.base_item import BaseItem from office365.entity_collection import EntityCollection from office365.onedrive.columns.definition_collection import ColumnDefinitionCollection @@ -16,10 +18,8 @@ class List(BaseItem): @property def display_name(self): - """ - The displayable title of the list - :rtype: str or None - """ + # type: () -> Optional[str] + """The displayable title of the list""" return self.properties.get("displayName", None) @property diff --git a/office365/onedrive/permissions/collection.py b/office365/onedrive/permissions/collection.py index d7e156424..ec4ea5aea 100644 --- a/office365/onedrive/permissions/collection.py +++ b/office365/onedrive/permissions/collection.py @@ -1,9 +1,17 @@ +from typing import TYPE_CHECKING + from office365.directory.permissions.identity import Identity from office365.entity import Entity from office365.entity_collection import EntityCollection from office365.onedrive.permissions.permission import Permission from office365.runtime.queries.create_entity import CreateEntityQuery +if TYPE_CHECKING: + from office365.directory.applications.application import Application + from office365.directory.groups.group import Group + from office365.directory.users.user import User + from office365.intune.devices.device import Device + class PermissionCollection(EntityCollection[Permission]): """Permission's collection""" @@ -12,6 +20,7 @@ def __init__(self, context, resource_path=None): super(PermissionCollection, self).__init__(context, Permission, resource_path) def add(self, roles, identity=None, identity_type=None): + # type: (list[str], Application|User|Group|Device|str, str) -> Permission """ Create a new permission object. @@ -21,6 +30,7 @@ def add(self, roles, identity=None, identity_type=None): """ return_type = Permission(self.context) + self.add_child(return_type) known_identities = { "application": self.context.applications, @@ -41,7 +51,7 @@ def add(self, roles, identity=None, identity_type=None): raise ValueError("Unknown identity type") identity = known_identity[identity] - def _create(): + def _add(): payload = { "roles": roles, "grantedToIdentities": [ @@ -53,13 +63,27 @@ def _create(): ], } - self.add_child(return_type) qry = CreateEntityQuery(self, payload, return_type) self.context.add_query(qry) - identity.ensure_properties(["displayName"], _create) + identity.ensure_properties(["displayName"], _add) return return_type + def delete(self, roles, identity): + # type: (list[str], Application|User|Group|Device) -> Permission + """ + Deletes the permission. + """ + + def _delete(col): + pass + + def _identity_loaded(): + self.get_all(page_loaded=_delete) + + identity.ensure_property("id", _identity_loaded) + return self + def delete_all(self): """ Remove all access to resource diff --git a/office365/onedrive/shares/collection.py b/office365/onedrive/shares/collection.py index 405cdf32e..355a4c843 100644 --- a/office365/onedrive/shares/collection.py +++ b/office365/onedrive/shares/collection.py @@ -10,7 +10,6 @@ def __init__(self, context, resource_path=None): def by_url(self, url): """ Address shared item by absolute url - :type url: str """ return SharedDriveItem(self.context, SharedPath(url, self.resource_path)) diff --git a/office365/onedrive/shares/drive_item.py b/office365/onedrive/shares/drive_item.py index 8ce46a6ce..2c321bd69 100644 --- a/office365/onedrive/shares/drive_item.py +++ b/office365/onedrive/shares/drive_item.py @@ -26,6 +26,7 @@ def items(self): @property def list_item(self): + # type: () -> ListItem """Used to access the underlying listItem""" return self.properties.get( "listItem", @@ -34,6 +35,7 @@ def list_item(self): @property def list(self): + # type: () -> List """Used to access the underlying list""" return self.properties.get( "list", List(self.context, ResourcePath("list", self.resource_path)) @@ -41,6 +43,7 @@ def list(self): @property def drive_item(self): + # type: () -> DriveItem """Used to access the underlying driveItem""" return self.properties.get( "driveItem", diff --git a/office365/onedrive/workbooks/worksheets/worksheet.py b/office365/onedrive/workbooks/worksheets/worksheet.py index db45f6237..4bac61b2d 100644 --- a/office365/onedrive/workbooks/worksheets/worksheet.py +++ b/office365/onedrive/workbooks/worksheets/worksheet.py @@ -20,8 +20,12 @@ class WorkbookWorksheet(Entity): def __repr__(self): return self.name + def __str__(self): + return self.name + @property def charts(self): + # type: () -> EntityCollection[WorkbookChart] """Returns collection of charts that are part of the worksheet""" return self.properties.get( "charts", @@ -33,9 +37,7 @@ def charts(self): @property def name(self): # type: () -> Optional[str] - """ - The display name of the worksheet. - """ + """The display name of the worksheet.""" return self.properties.get("name", None) @property diff --git a/office365/onenote/pages/collection.py b/office365/onenote/pages/collection.py index d31c10911..b52ef956f 100644 --- a/office365/onenote/pages/collection.py +++ b/office365/onenote/pages/collection.py @@ -1,3 +1,5 @@ +from typing import IO + from office365.entity_collection import EntityCollection from office365.onenote.internal.multipart_page_query import OneNotePageCreateQuery from office365.onenote.pages.page import OnenotePage @@ -10,12 +12,11 @@ def __init__(self, context, resource_path=None): super(OnenotePageCollection, self).__init__(context, OnenotePage, resource_path) def add(self, presentation_file, attachment_files=None): + # type: (IO, dict) -> OnenotePage """ Create a new OneNote page. - :param typing.IO presentation_file: Presentation file :param dict or None attachment_files: Attachment files - :rtype: OnenotePage """ qry = OneNotePageCreateQuery(self, presentation_file, attachment_files) self.context.add_query(qry) diff --git a/office365/onenote/sectiongroups/section_group.py b/office365/onenote/sectiongroups/section_group.py index 8433bed6f..1faf58a84 100644 --- a/office365/onenote/sectiongroups/section_group.py +++ b/office365/onenote/sectiongroups/section_group.py @@ -1,3 +1,5 @@ +from typing import Optional + from office365.entity_collection import EntityCollection from office365.onenote.entity_hierarchy_model import OnenoteEntityHierarchyModel from office365.onenote.notebooks.notebook import Notebook @@ -10,22 +12,21 @@ class SectionGroup(OnenoteEntityHierarchyModel): @property def section_groups_url(self): - """The URL for the sectionGroups navigation property, which returns all the section groups in the section group. - - :rtype: str or None + # type: () -> Optional[str] + """ + The URL for the sectionGroups navigation property, which returns all the section groups in the section group. """ return self.properties.get("sectionGroupsUrl", None) @property def sections_url(self): - """The URL for the sections navigation property, which returns all the sections in the section group. - - :rtype: str or None - """ + # type: () -> Optional[str] + """The URL for the sections navigation property, which returns all the sections in the section group.""" return self.properties.get("sectionsUrl", None) @property def parent_notebook(self): + # type: () -> Notebook """The notebook that contains the section group. Read-only.""" return self.properties.get( "parentNotebook", @@ -34,6 +35,7 @@ def parent_notebook(self): @property def sections(self): + # type: () -> EntityCollection[OnenoteSection] """The sections in the section group. Read-only. Nullable.""" return self.properties.get( "sections", @@ -46,6 +48,7 @@ def sections(self): @property def section_groups(self): + # type: () -> EntityCollection[SectionGroup] """Retrieve a list of onenoteSection objects from the specified notebook.""" return self.properties.get( "sectionGroups", diff --git a/office365/teams/collection.py b/office365/teams/collection.py index 1f6419ab1..0d70cc07f 100644 --- a/office365/teams/collection.py +++ b/office365/teams/collection.py @@ -1,8 +1,8 @@ from typing import Callable +import requests from typing_extensions import Self -from office365.directory.groups.group import Group from office365.entity_collection import EntityCollection from office365.runtime.odata.path_builder import ODataPathBuilder from office365.runtime.paths.resource_path import ResourcePath @@ -44,18 +44,8 @@ def create(self, display_name, description=None): return_type = Team(self.context) self.add_child(return_type) - payload = { - "displayName": display_name, - "description": description, - "template@odata.bind": "https://graph.microsoft.com/v1.0/teamsTemplates('standard')", - } - qry = CreateEntityQuery(self, payload, return_type) - self.context.add_query(qry) - def _process_response(resp): - """ - :type resp: requests.Response - """ + # type: (requests.Response) -> None content_loc = resp.headers.get("Content-Location", None) team_path = ODataPathBuilder.parse(content_loc) return_type.set_property("id", team_path.segment, False) @@ -65,5 +55,11 @@ def _process_response(resp): operation = TeamsAsyncOperation(self.context, operation_path) return_type.operations.add_child(operation) - self.context.after_execute(_process_response) + payload = { + "displayName": display_name, + "description": description, + "template@odata.bind": "https://graph.microsoft.com/v1.0/teamsTemplates('standard')", + } + qry = CreateEntityQuery(self, payload, return_type) + self.context.add_query(qry).after_execute(_process_response) return return_type diff --git a/office365/teams/members/conversation_collection.py b/office365/teams/members/conversation_collection.py index db3d0fd7a..858206369 100644 --- a/office365/teams/members/conversation_collection.py +++ b/office365/teams/members/conversation_collection.py @@ -2,7 +2,7 @@ from office365.teams.members.conversation import ConversationMember -class ConversationMemberCollection(EntityCollection): +class ConversationMemberCollection(EntityCollection[ConversationMember]): def __init__(self, context, resource_path=None): super(ConversationMemberCollection, self).__init__( context, ConversationMember, resource_path @@ -18,8 +18,6 @@ def add(self, user, roles, visible_history_start_datetime=None): Each member must be assigned a role of owner or guest. Guest tenant members must be assigned the guest role :param list[str] roles: The roles for that user. :param datetime.datetime visible_history_start_datetime: - - :rtype: ConversationMember """ return_type = super(ConversationMemberCollection, self).add(roles=roles) from office365.directory.users.user import User diff --git a/office365/teams/operations/async_operation.py b/office365/teams/operations/async_operation.py index 385863902..11f7fd382 100644 --- a/office365/teams/operations/async_operation.py +++ b/office365/teams/operations/async_operation.py @@ -68,16 +68,14 @@ def target_resource_id(self): @property def target_resource_location(self): + # type: () -> Optional[str] """The location of the object that's created or modified as result of this async operation. This URL should be treated as an opaque value and not parsed into its component paths. - :rtype: str or None """ return self.properties.get("targetResourceLocation", None) @property def status(self): - """ - Operation status. - :rtype: str - """ + # type: () -> Optional[str] + """Operation status.""" return self.properties.get("status", None) diff --git a/office365/teams/schedule/groups/group.py b/office365/teams/schedule/groups/group.py index 7775c407e..d6bb75c13 100644 --- a/office365/teams/schedule/groups/group.py +++ b/office365/teams/schedule/groups/group.py @@ -1,3 +1,5 @@ +from typing import Optional + from office365.runtime.types.collections import StringCollection from office365.teams.schedule.change_tracked_entity import ChangeTrackedEntity @@ -7,6 +9,7 @@ class SchedulingGroup(ChangeTrackedEntity): @property def is_active(self): + # type: () -> Optional[bool] """Indicates whether the schedulingGroup can be used when creating new entities or updating existing ones""" return self.properties.get("isActive", None)