Skip to content

Commit 0774043

Browse files
committed
additional type hints enhancements (folder namespace), #740: fix for copy_to_using_path method
1 parent 41432e0 commit 0774043

File tree

8 files changed

+98
-67
lines changed

8 files changed

+98
-67
lines changed
+5-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Demonstrates how to copy a folder within a site
33
"""
4+
45
from office365.sharepoint.client_context import ClientContext
56
from tests import create_unique_name, test_team_site_url, test_user_credentials
67

@@ -10,10 +11,11 @@
1011
folder_from = ctx.web.default_document_library().root_folder.add(
1112
create_unique_name("from")
1213
)
13-
folder_to = ctx.web.default_document_library().root_folder.add(create_unique_name("to"))
14+
# folder_to = ctx.web.default_document_library().root_folder.add(create_unique_name("to"))
15+
folder_to_url = "/sites/team/Shared Documents/Archive/2001/01"
1416

1517
# copies the folder with a new name
16-
folder = folder_from.copy_to_using_path(folder_to).execute_query()
18+
folder = folder_from.copy_to(folder_to_url).execute_query()
1719
print(
1820
"Folder has been copied from '{0}' into '{1}'".format(
1921
folder_from.serverRelativeUrl, folder.serverRelativeUrl
@@ -22,4 +24,4 @@
2224

2325
# clean up
2426
folder_from.delete_object().execute_query()
25-
folder_to.delete_object().execute_query()
27+
folder.delete_object().execute_query()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""
2+
Demonstrates how to copy a folder using path
3+
"""
4+
5+
from office365.sharepoint.client_context import ClientContext
6+
from tests import create_unique_name, test_team_site_url, test_user_credentials
7+
8+
ctx = ClientContext(test_team_site_url).with_credentials(test_user_credentials)
9+
10+
# creates a temporary folder first in a Documents library
11+
folder_from = ctx.web.default_document_library().root_folder.add(
12+
create_unique_name("from")
13+
)
14+
# folder_to = ctx.web.default_document_library().root_folder.add(create_unique_name("to"))
15+
folder_to_url = "Shared Documents/Archive/2001/01"
16+
17+
# copies the folder with a new name
18+
folder = folder_from.copy_to_using_path(folder_to_url).execute_query()
19+
print(
20+
"Folder has been copied from '{0}' into '{1}'".format(
21+
folder_from.server_relative_path, folder.server_relative_path
22+
)
23+
)
24+
25+
# clean up
26+
folder_from.delete_object().execute_query()
27+
folder.delete_object().execute_query()
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
"""
2+
Get Folder properties
3+
"""
4+
from office365.sharepoint.client_context import ClientContext
5+
from tests import test_client_credentials, test_team_site_url
6+
7+
ctx = ClientContext(test_team_site_url).with_credentials(test_client_credentials)
8+
folder = (
9+
ctx.web.get_folder_by_server_relative_url("Shared Documents").get().execute_query()
10+
)
11+
print(folder.name)

examples/sharepoint/folders/list_folders.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import Callable
2+
13
from office365.sharepoint.client_context import ClientContext
24
from office365.sharepoint.folders.folder import Folder
35
from tests import test_client_credentials, test_team_site_url
@@ -6,10 +8,7 @@
68

79

810
def enum_folder(parent_folder, action):
9-
"""
10-
:type parent_folder: Folder
11-
:type action: (Folder)-> None
12-
"""
11+
# type: (Folder, Callable[[Folder], None]) -> None
1312
parent_folder.expand(["Folders"]).get().execute_query()
1413
action(parent_folder)
1514
for folder in parent_folder.folders:

office365/sharepoint/client_context.py

+5
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,11 @@ def tenant_url(self):
689689
names[0] = names[0] + "-admin"
690690
return result.scheme + "://" + ".".join(names)
691691

692+
@property
693+
def site_path(self):
694+
root_url = get_absolute_url(self.base_url)
695+
return self.base_url.replace(root_url, "")
696+
692697
@property
693698
def is_tenant(self):
694699
"""

office365/sharepoint/folders/collection.py

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def ensure_path(self, path):
3333
3434
:param str path: server or site relative url to a folder
3535
"""
36+
path = path.replace(self.context.site_path, "")
3637
names = [name for name in path.split("/") if name]
3738
if not names:
3839
raise ValueError("Invalid server or site relative url")

office365/sharepoint/folders/folder.py

+40-60
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from datetime import datetime
2-
from typing import TYPE_CHECKING
2+
from typing import TYPE_CHECKING, Optional
3+
4+
from typing_extensions import Self
35

46
from office365.runtime.client_result import ClientResult
57
from office365.runtime.client_value_collection import ClientValueCollection
@@ -20,6 +22,7 @@
2022

2123
if TYPE_CHECKING:
2224
from office365.sharepoint.files.collection import FileCollection
25+
from office365.sharepoint.folders.collection import FolderCollection
2326

2427

2528
class Folder(Entity):
@@ -54,17 +57,14 @@ def download_folder(
5457
def get_files(self, recursive=False):
5558
"""
5659
Retrieves files
57-
5860
:param bool recursive: Determines whether to enumerate folders recursively
5961
"""
6062
from office365.sharepoint.files.collection import FileCollection
6163

6264
return_type = FileCollection(self.context, self.files.resource_path, self)
6365

6466
def _loaded(parent):
65-
"""
66-
:type parent: Folder
67-
"""
67+
# type: ("Folder") -> None
6868
[return_type.add_child(f) for f in parent.files]
6969
if recursive:
7070
for folder in parent.folders:
@@ -94,9 +94,7 @@ def _update_folder(url):
9494
self.set_property("ServerRelativeUrl", url)
9595

9696
def _move_to(destination_folder):
97-
"""
98-
:type destination_folder: Folder
99-
"""
97+
# type: ("Folder") -> None
10098
destination_url = "/".join(
10199
[destination_folder.serverRelativeUrl, self.name]
102100
)
@@ -261,10 +259,8 @@ def get_list_item_changes(self, query):
261259
return return_type
262260

263261
def add(self, name):
264-
"""Adds the folder that is located under a current folder
265-
266-
:type name: str
267-
"""
262+
# type: (str) -> Self
263+
"""Adds the folder that is located under a current folder"""
268264
return self.folders.add(name)
269265

270266
def rename(self, name):
@@ -352,6 +348,7 @@ def _loaded():
352348
return return_type
353349

354350
def copy_to(self, destination, keep_both=False, reset_author_and_created=False):
351+
# type: (str|"Folder", bool, bool) -> "Folder"
355352
"""Copies the folder with files to the destination URL.
356353
357354
:param str or Folder destination: Parent folder object or server relative folder url
@@ -362,9 +359,7 @@ def copy_to(self, destination, keep_both=False, reset_author_and_created=False):
362359
self.parent_collection.add_child(return_type)
363360

364361
def _copy_folder(destination_folder):
365-
"""
366-
:type destination_folder: Folder
367-
"""
362+
# type: ("Folder") -> None
368363
destination_url = "/".join(
369364
[destination_folder.serverRelativeUrl, self.name]
370365
)
@@ -393,6 +388,7 @@ def _source_folder_resolved():
393388
def copy_to_using_path(
394389
self, destination, keep_both=False, reset_author_and_created=False
395390
):
391+
# type: (str|"Folder", bool, bool) -> "Folder"
396392
"""Copies the folder with files to the destination Path.
397393
398394
:param str or Folder destination: Parent folder object or server relative folder url
@@ -404,9 +400,7 @@ def copy_to_using_path(
404400
self.parent_collection.add_child(return_type)
405401

406402
def _copy_folder_by_path(destination_folder):
407-
"""
408-
:type destination_folder: Folder
409-
"""
403+
# type: ("Folder") -> None
410404
destination_url = "/".join(
411405
[str(destination_folder.server_relative_path), self.name]
412406
)
@@ -425,9 +419,9 @@ def _source_folder_resolved():
425419
"ServerRelativePath", _copy_folder_by_path, destination
426420
)
427421
else:
428-
self.context.web.ensure_folder_path(destination).after_execute(
429-
_copy_folder_by_path
430-
)
422+
self.context.web.ensure_folder_path(destination).get().select(
423+
["ServerRelativePath"]
424+
).after_execute(_copy_folder_by_path)
431425

432426
self.ensure_properties(["ServerRelativePath", "Name"], _source_folder_resolved)
433427
return return_type
@@ -444,7 +438,8 @@ def storage_metrics(self):
444438

445439
@property
446440
def list_item_all_fields(self):
447-
"""Specifies the list item fields (2) values for the list item corresponding to the folder."""
441+
# type: () -> ListItem
442+
"""Specifies the list item fields values for the list item corresponding to the folder."""
448443
return self.properties.get(
449444
"ListItemAllFields",
450445
ListItem(
@@ -467,6 +462,7 @@ def files(self):
467462

468463
@property
469464
def folders(self):
465+
# type: () -> FolderCollection
470466
"""Specifies the collection of list folders contained within the list folder."""
471467
from office365.sharepoint.folders.collection import FolderCollection
472468

@@ -477,6 +473,7 @@ def folders(self):
477473

478474
@property
479475
def parent_folder(self):
476+
# type: () -> "Folder"
480477
"""Specifies the list folder."""
481478
return self.properties.get(
482479
"ParentFolder",
@@ -485,103 +482,85 @@ def parent_folder(self):
485482

486483
@property
487484
def name(self):
488-
"""Specifies the list folder name.
489-
490-
:rtype: str or None
491-
"""
485+
# type: () -> Optional[str]
486+
"""Specifies the list folder name."""
492487
return self.properties.get("Name", None)
493488

494489
@property
495490
def is_wopi_enabled(self):
491+
# type: () -> Optional[bool]
496492
"""
497493
Indicates whether the folder is enabled for WOPI default action.
498-
499-
:rtype: bool or None
500494
"""
501495
return self.properties.get("IsWOPIEnabled", None)
502496

503497
@property
504498
def prog_id(self):
505-
"""Gets the identifier (ID) of the application in which the folder was created.
506-
507-
:rtype: str or None
508-
"""
499+
# type: () -> Optional[str]
500+
"""Gets the identifier (ID) of the application in which the folder was created."""
509501
return self.properties.get("ProgID", None)
510502

511503
@property
512504
def unique_id(self):
513-
"""Gets the unique ID of the folder.
514-
515-
:rtype: str or None
516-
"""
505+
# type: () -> Optional[str]
506+
"""Gets the unique ID of the folder."""
517507
return self.properties.get("UniqueId", None)
518508

519509
@property
520510
def exists(self):
521-
"""Gets a Boolean value that indicates whether the folder exists.
522-
523-
:rtype: bool or None
524-
"""
511+
# type: () -> Optional[bool]
512+
"""Gets a Boolean value that indicates whether the folder exists."""
525513
return self.properties.get("Exists", None)
526514

527515
@property
528516
def welcome_page(self):
529-
"""Specifies the server-relative URL for the list folder Welcome page.
530-
531-
:rtype: str or None
532-
"""
517+
# type: () -> Optional[str]
518+
"""Specifies the server-relative URL for the list folder Welcome page."""
533519
return self.properties.get("WelcomePage", None)
534520

535521
@property
536522
def unique_content_type_order(self):
537-
"""Specifies the content type order for the list folder.
538-
539-
:rtype: office365.sharepoint.contenttypes.content_type_id.ContentTypeId or None
540-
"""
523+
"""Specifies the content type order for the list folder."""
541524
return self.properties.get("UniqueContentTypeOrder", ContentTypeId())
542525

543526
@property
544527
def content_type_order(self):
545-
"""Specifies the content type order for the list folder.
546-
547-
:rtype: office365.sharepoint.contenttypes.content_type_id.ContentTypeId or None
548-
"""
528+
"""Specifies the content type order for the list folder."""
549529
return self.properties.get("ContentTypeOrder", ContentTypeId())
550530

551531
@property
552532
def time_last_modified(self):
553-
"""Gets the last time this folder or a direct child was modified in UTC.
554-
555-
:rtype: str or None
556-
"""
557-
return self.properties.get("TimeLastModified", None)
533+
# type: () -> Optional[datetime]
534+
"""Gets the last time this folder or a direct child was modified in UTC."""
535+
return self.properties.get("TimeLastModified", datetime.min)
558536

559537
@property
560538
def time_created(self):
539+
# type: () -> Optional[datetime]
561540
"""
562541
Gets when the folder was created in UTC.
563-
:rtype: datetime or None
564542
"""
565543
return self.properties.get("TimeCreated", datetime.min)
566544

567545
@property
568546
def serverRelativeUrl(self):
547+
# type: () -> Optional[str]
569548
"""
570549
Gets the server-relative URL of the list folder.
571-
:rtype: str or None
572550
"""
573551
return self.properties.get("ServerRelativeUrl", None)
574552

575553
@property
576554
def server_relative_path(self):
555+
# type: () -> Optional[SPResPath]
577556
"""
578557
Gets the server-relative Path of the list folder.
579-
:rtype: SPResPath or None
580558
"""
581559
return self.properties.get("ServerRelativePath", SPResPath())
582560

583561
@property
584562
def property_ref_name(self):
563+
# type: () -> str
585564
return "ServerRelativeUrl"
586565

587566
def get_property(self, name, default_value=None):
@@ -594,6 +573,7 @@ def get_property(self, name, default_value=None):
594573
"ServerRelativePath": self.server_relative_path,
595574
"StorageMetrics": self.storage_metrics,
596575
"TimeCreated": self.time_created,
576+
"TimeLastModified": self.time_last_modified,
597577
}
598578
default_value = property_mapping.get(name, None)
599579
return super(Folder, self).get_property(name, default_value)

office365/sharepoint/utilities/move_copy_util.py

+6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import os
2+
from typing import IO, TYPE_CHECKING, Callable
23

34
from office365.runtime.client_result import ClientResult
45
from office365.runtime.queries.service_operation import ServiceOperationQuery
56
from office365.sharepoint.entity import Entity
67
from office365.sharepoint.types.resource_path import ResourcePath as SPResPath
78

9+
if TYPE_CHECKING:
10+
from office365.sharepoint.files.file import File
11+
from office365.sharepoint.folders.folder import Folder
12+
813

914
class MoveCopyUtil(Entity):
1015
"""A container class for static move/copy methods."""
@@ -141,6 +146,7 @@ def move_folder_by_path(context, src_path, dest_path, options):
141146
def download_folder(
142147
remove_folder, download_file, after_file_downloaded=None, recursive=True
143148
):
149+
# type: (Folder, IO, Callable[[File], None], bool) -> Folder
144150
"""
145151
Downloads a folder into a zip file
146152
:param office365.sharepoint.folders.folder.Folder remove_folder: Parent folder

0 commit comments

Comments
 (0)