Office365-REST-Python-Client 2.5.2__py3-none-any.whl → 2.5.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. {Office365_REST_Python_Client-2.5.2.dist-info → Office365_REST_Python_Client-2.5.3.dist-info}/METADATA +4 -4
  2. {Office365_REST_Python_Client-2.5.2.dist-info → Office365_REST_Python_Client-2.5.3.dist-info}/RECORD +122 -119
  3. office365/base_item.py +12 -20
  4. office365/communications/presences/presence.py +18 -7
  5. office365/delta_path.py +1 -1
  6. office365/directory/administrative_unit.py +6 -7
  7. office365/directory/applications/application.py +15 -13
  8. office365/directory/audit/signins/signin.py +8 -12
  9. office365/directory/authentication/methods/details.py +8 -6
  10. office365/directory/groups/lifecycle_policy.py +8 -7
  11. office365/directory/identities/provider.py +5 -6
  12. office365/directory/internal/paths/me.py +1 -1
  13. office365/directory/permissions/email_identity.py +7 -0
  14. office365/directory/rolemanagement/role.py +5 -4
  15. office365/directory/rolemanagement/template.py +2 -6
  16. office365/directory/rolemanagement/unified_role_assignment.py +5 -4
  17. office365/directory/rolemanagement/unified_role_definition.py +6 -4
  18. office365/directory/serviceprincipals/service_principal.py +11 -6
  19. office365/directory/users/user.py +8 -11
  20. office365/entity.py +2 -2
  21. office365/entity_collection.py +11 -4
  22. office365/intune/devices/enrollment/configuration.py +6 -4
  23. office365/intune/devices/managed.py +9 -12
  24. office365/onedrive/analytics/item_activity_stat.py +4 -3
  25. office365/onedrive/columns/definition.py +9 -9
  26. office365/onedrive/documentsets/version.py +1 -3
  27. office365/onedrive/driveitems/driveItem.py +30 -29
  28. office365/onedrive/internal/paths/children.py +2 -2
  29. office365/onedrive/internal/paths/root.py +1 -1
  30. office365/onedrive/internal/paths/shared.py +1 -1
  31. office365/onedrive/internal/paths/site.py +3 -3
  32. office365/onedrive/internal/paths/url.py +2 -2
  33. office365/onedrive/listitems/list_item.py +2 -0
  34. office365/onedrive/lists/list.py +7 -4
  35. office365/onedrive/permissions/collection.py +26 -6
  36. office365/onedrive/sharepoint.py +1 -0
  37. office365/onedrive/shares/collection.py +2 -5
  38. office365/onedrive/shares/drive_item.py +3 -0
  39. office365/onedrive/termstore/groups/collection.py +3 -8
  40. office365/onedrive/termstore/groups/group.py +8 -0
  41. office365/onedrive/termstore/sets/collection.py +2 -6
  42. office365/onedrive/termstore/sets/name.py +5 -0
  43. office365/onedrive/termstore/sets/set.py +7 -0
  44. office365/onedrive/termstore/store.py +10 -13
  45. office365/onedrive/versions/drive_item.py +3 -1
  46. office365/onedrive/workbooks/ranges/range.py +9 -13
  47. office365/onedrive/workbooks/ranges/view.py +1 -0
  48. office365/onedrive/workbooks/tables/table.py +1 -3
  49. office365/onedrive/workbooks/worksheets/worksheet.py +5 -3
  50. office365/onenote/pages/collection.py +3 -2
  51. office365/onenote/resources/resource.py +5 -4
  52. office365/onenote/sectiongroups/section_group.py +10 -7
  53. office365/outlook/calendar/calendar.py +1 -1
  54. office365/outlook/calendar/schedule/information.py +0 -1
  55. office365/outlook/contacts/contact.py +3 -9
  56. office365/outlook/contacts/folder.py +3 -0
  57. office365/outlook/mail/messages/message.py +25 -18
  58. office365/outlook/mail/recipient.py +3 -1
  59. office365/runtime/auth/authentication_context.py +2 -2
  60. office365/runtime/auth/providers/acs_token_provider.py +7 -9
  61. office365/runtime/client_object.py +3 -11
  62. office365/runtime/client_object_collection.py +22 -20
  63. office365/runtime/client_result.py +1 -3
  64. office365/runtime/client_value_collection.py +2 -6
  65. office365/runtime/odata/query_options.py +1 -3
  66. office365/runtime/odata/type.py +2 -0
  67. office365/runtime/paths/appid.py +1 -1
  68. office365/runtime/{odata/url_builder.py → paths/builder.py} +24 -9
  69. office365/runtime/paths/item.py +1 -1
  70. office365/runtime/paths/resource_path.py +12 -16
  71. office365/runtime/paths/service_operation.py +8 -7
  72. office365/runtime/paths/v3/__init__.py +0 -0
  73. office365/runtime/paths/{key.py → v3/entity.py} +5 -5
  74. office365/runtime/paths/v4/__init__.py +0 -0
  75. office365/runtime/paths/{entity.py → v4/entity.py} +13 -11
  76. office365/sharepoint/contenttypes/content_type.py +6 -0
  77. office365/sharepoint/documentmanagement/document_set.py +4 -6
  78. office365/sharepoint/entity_collection.py +9 -0
  79. office365/sharepoint/features/feature.py +6 -8
  80. office365/sharepoint/files/checked_out_file.py +4 -2
  81. office365/sharepoint/files/checked_out_file_collection.py +1 -1
  82. office365/sharepoint/files/collection.py +35 -3
  83. office365/sharepoint/files/file.py +35 -11
  84. office365/sharepoint/files/versions/collection.py +4 -0
  85. office365/sharepoint/files/versions/event.py +6 -3
  86. office365/sharepoint/files/versions/version.py +6 -4
  87. office365/sharepoint/folders/collection.py +2 -2
  88. office365/sharepoint/folders/folder.py +5 -11
  89. office365/sharepoint/internal/paths/static_operation.py +9 -0
  90. office365/sharepoint/internal/paths/web.py +20 -0
  91. office365/sharepoint/listitems/collection.py +4 -0
  92. office365/sharepoint/listitems/listitem.py +19 -30
  93. office365/sharepoint/lists/list.py +44 -60
  94. office365/sharepoint/portal/groups/service.py +12 -16
  95. office365/sharepoint/portal/groups/site_manager.py +0 -1
  96. office365/sharepoint/publishing/pages/metadata.py +7 -2
  97. office365/sharepoint/publishing/pages/metadata_collection.py +0 -1
  98. office365/sharepoint/publishing/pages/page.py +3 -6
  99. office365/sharepoint/publishing/pages/reposts/repost.py +5 -9
  100. office365/sharepoint/recyclebin/item.py +11 -9
  101. office365/sharepoint/sharing/links/share_response.py +3 -0
  102. office365/sharepoint/sharing/result.py +18 -41
  103. office365/sharepoint/sites/site.py +46 -68
  104. office365/sharepoint/taxonomy/item.py +4 -2
  105. office365/sharepoint/taxonomy/stores/store.py +2 -6
  106. office365/sharepoint/tenant/administration/internal/permission_grant.py +7 -0
  107. office365/sharepoint/tenant/administration/sites/properties.py +55 -44
  108. office365/sharepoint/tenant/administration/tenant.py +25 -40
  109. office365/sharepoint/usercustomactions/collection.py +0 -1
  110. office365/sharepoint/webs/collection.py +8 -0
  111. office365/sharepoint/webs/template_collection.py +2 -4
  112. office365/sharepoint/webs/web.py +27 -24
  113. office365/teams/apps/app.py +1 -0
  114. office365/teams/collection.py +12 -16
  115. office365/teams/members/conversation_collection.py +1 -3
  116. office365/teams/operations/async_operation.py +3 -5
  117. office365/teams/schedule/groups/group.py +3 -0
  118. office365/teams/team.py +1 -1
  119. office365/todo/attachments/base.py +7 -9
  120. office365/runtime/odata/path_builder.py +0 -23
  121. office365/sharepoint/internal/key_value.py +0 -28
  122. {Office365_REST_Python_Client-2.5.2.dist-info → Office365_REST_Python_Client-2.5.3.dist-info}/LICENSE +0 -0
  123. {Office365_REST_Python_Client-2.5.2.dist-info → Office365_REST_Python_Client-2.5.3.dist-info}/WHEEL +0 -0
  124. {Office365_REST_Python_Client-2.5.2.dist-info → Office365_REST_Python_Client-2.5.3.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
- from typing import Callable, Generic, Iterator, List, Optional, Type, TypeVar
1
+ from typing import Any, Callable, Generic, Iterator, List, Optional, Type, TypeVar
2
2
 
3
3
  from typing_extensions import Self
4
4
 
@@ -40,6 +40,8 @@ class ClientObjectCollection(ClientObject, Generic[T]):
40
40
  raise AttributeError(
41
41
  "No class model for entity type '{0}' was found".format(self._item_type)
42
42
  )
43
+ if resource_path is None:
44
+ resource_path = ResourcePath(None, self.resource_path)
43
45
  client_object = self._item_type(
44
46
  context=self.context, resource_path=resource_path
45
47
  ) # type: T
@@ -66,9 +68,7 @@ class ClientObjectCollection(ClientObject, Generic[T]):
66
68
 
67
69
  def add_child(self, client_object):
68
70
  # type: (T) -> Self
69
- """
70
- Adds client object into collection
71
- """
71
+ """Adds client object into collection"""
72
72
  client_object._parent_collection = self
73
73
  self._data.append(client_object)
74
74
  return self
@@ -110,7 +110,6 @@ class ClientObjectCollection(ClientObject, Generic[T]):
110
110
  # type: (str) -> Self
111
111
  """
112
112
  Allows clients to filter a collection of resources that are addressed by a request URL
113
-
114
113
  :param str expression: Filter expression, for example: 'Id eq 123'
115
114
  """
116
115
  self.query_options.filter = expression
@@ -134,17 +133,13 @@ class ClientObjectCollection(ClientObject, Generic[T]):
134
133
 
135
134
  def top(self, value):
136
135
  # type: (int) -> Self
137
- """
138
- Specifies the number of items in the queried collection to be included in the result
139
- """
136
+ """Specifies the number of items in the queried collection to be included in the result"""
140
137
  self.query_options.top = value
141
138
  return self
142
139
 
143
140
  def paged(self, page_size=None, page_loaded=None):
144
141
  # type: (int, Callable[[Self], None]) -> Self
145
- """
146
- Retrieves via server-driven paging mode
147
- """
142
+ """Retrieves via server-driven paging mode"""
148
143
  self._paged_mode = True
149
144
  if callable(page_loaded):
150
145
  self._page_loaded += page_loaded
@@ -152,6 +147,12 @@ class ClientObjectCollection(ClientObject, Generic[T]):
152
147
  self.top(page_size)
153
148
  return self
154
149
 
150
+ def after_execute(self, action, *args, **kwargs):
151
+ # type: (Callable[[Self, Any, Any], None], Any, Any) -> Self
152
+ super(ClientObjectCollection, self).after_execute(action, *args, **kwargs)
153
+ self._page_loaded += action
154
+ return self
155
+
155
156
  def get(self):
156
157
  # type: () -> Self
157
158
 
@@ -196,22 +197,22 @@ class ClientObjectCollection(ClientObject, Generic[T]):
196
197
  def first(self, expression):
197
198
  # type: (str) -> T
198
199
  """Return the first Entity instance that matches current query
199
-
200
200
  :param str expression: Filter expression
201
201
  """
202
202
  return_type = self.create_typed_object()
203
203
  self.add_child(return_type)
204
- key = return_type.property_ref_name
205
204
 
206
205
  def _after_loaded(col):
207
206
  # type: (ClientObjectCollection) -> None
208
207
  if len(col) < 1:
209
208
  message = "Not found for filter: {0}".format(self.query_options.filter)
210
209
  raise ValueError(message)
211
- return_type.set_property(key, col[0].get_property(key))
210
+ [
211
+ return_type.set_property(k, v, False)
212
+ for k, v in col[0].properties.items()
213
+ ]
212
214
 
213
- self.filter(expression).top(1)
214
- self.context.load(self, [key], after_loaded=_after_loaded)
215
+ self.get().filter(expression).top(1).after_execute(_after_loaded)
215
216
  return return_type
216
217
 
217
218
  def single(self, expression):
@@ -223,7 +224,6 @@ class ClientObjectCollection(ClientObject, Generic[T]):
223
224
  """
224
225
  return_type = self.create_typed_object()
225
226
  self.add_child(return_type)
226
- key = return_type.property_ref_name
227
227
 
228
228
  def _after_loaded(col):
229
229
  # type: (ClientObjectCollection) -> None
@@ -233,10 +233,12 @@ class ClientObjectCollection(ClientObject, Generic[T]):
233
233
  elif len(col) > 1:
234
234
  message = "Ambiguous match found for filter: {0}".format(expression)
235
235
  raise ValueError(message)
236
- return_type.set_property(key, col[0].get_property(key), False)
236
+ [
237
+ return_type.set_property(k, v, False)
238
+ for k, v in col[0].properties.items()
239
+ ]
237
240
 
238
- self.filter(expression).top(2)
239
- self.context.load(self, after_loaded=_after_loaded)
241
+ self.get().filter(expression).top(2).after_execute(_after_loaded)
240
242
  return return_type
241
243
 
242
244
  @property
@@ -59,9 +59,7 @@ class ClientResult(Generic[T]):
59
59
  def execute_query_retry(
60
60
  self, max_retry=5, timeout_secs=5, success_callback=None, failure_callback=None
61
61
  ):
62
- """
63
- Executes the current set of data retrieval queries and method invocations and retries it if needed.
64
- """
62
+ """Executes the current set of data retrieval queries and method invocations and retries it if needed."""
65
63
  self._context.execute_query_retry(
66
64
  max_retry=max_retry,
67
65
  timeout_secs=timeout_secs,
@@ -41,9 +41,7 @@ class ClientValueCollection(ClientValue, Generic[T]):
41
41
 
42
42
  def to_json(self, json_format=None):
43
43
  # type: (ODataJsonFormat) -> list
44
- """
45
- Serializes a client value's collection
46
- """
44
+ """Serializes a client value's collection"""
47
45
  json = [v for v in self]
48
46
  for i, v in enumerate(json):
49
47
  if isinstance(v, ClientValue):
@@ -81,7 +79,5 @@ class ClientValueCollection(ClientValue, Generic[T]):
81
79
 
82
80
  @property
83
81
  def entity_type_name(self):
84
- """
85
- Returns server type name of value's collection
86
- """
82
+ """Returns server type name of value's collection"""
87
83
  return "Collection({0})".format(ODataType.resolve_type(self._item_type))
@@ -90,9 +90,7 @@ class QueryOptions(object):
90
90
  self.custom = {}
91
91
 
92
92
  def to_url(self):
93
- """Convert query options to url
94
- :return: str
95
- """
93
+ """Convert query options to url"""
96
94
  return "&".join(["$%s=%s" % (key, value) for (key, value) in self])
97
95
 
98
96
  def __iter__(self):
@@ -64,6 +64,8 @@ class ODataType(object):
64
64
  """
65
65
  if value is None:
66
66
  return None
67
+ elif isinstance(value, datetime.datetime):
68
+ return value
67
69
 
68
70
  known_formats = [
69
71
  "%Y-%m-%dT%H:%M:%SZ",
@@ -7,7 +7,7 @@ class AppIdPath(ResourcePath):
7
7
 
8
8
  @property
9
9
  def segment(self):
10
- return "(appId='{0}')".format(self.key)
10
+ return "(appId='{0}')".format(self._key)
11
11
 
12
12
  @property
13
13
  def delimiter(self):
@@ -1,18 +1,33 @@
1
1
  import json
2
+ import re
3
+ from typing import TYPE_CHECKING
2
4
 
3
5
  from office365.runtime.client_value import ClientValue
4
6
  from office365.runtime.compat import is_string_type
7
+ from office365.runtime.paths.resource_path import ResourcePath
5
8
 
9
+ if TYPE_CHECKING:
10
+ from office365.runtime.paths.service_operation import ServiceOperationPath
6
11
 
7
- class ODataUrlBuilder(object):
12
+
13
+ class ODataPathBuilder(object):
8
14
  @staticmethod
9
- def build_segment(path):
10
- """
11
- Constructs url for path segment
15
+ def parse_url(path_str):
16
+ # type: (str) -> ResourcePath
17
+ """Parses path from a string"""
18
+ segments = [n for n in re.split(r"[('')]|/", path_str) if n]
19
+ if not segments:
20
+ raise TypeError("Invalid path")
21
+ path = None
22
+ for segment in segments:
23
+ path = ResourcePath(segment, path)
24
+ return path
12
25
 
13
- :type path: office365.runtime.paths.service_operation.ServiceOperationPath
14
- """
15
- url = path.key or ""
26
+ @staticmethod
27
+ def build_segment(path):
28
+ # type: (ServiceOperationPath) -> str
29
+ """Constructs url for path segment"""
30
+ url = path.name or ""
16
31
  if isinstance(path.parameters, ClientValue):
17
32
  url += "(@v)?@v={0}".format(json.dumps(path.parameters.to_json()))
18
33
  elif path.parameters is not None:
@@ -20,7 +35,7 @@ class ODataUrlBuilder(object):
20
35
  if isinstance(path.parameters, dict):
21
36
  url += ",".join(
22
37
  [
23
- "%s=%s" % (key, ODataUrlBuilder._encode_method_value(value))
38
+ "%s=%s" % (key, ODataPathBuilder._encode_method_value(value))
24
39
  for (key, value) in path.parameters.items()
25
40
  if value is not None
26
41
  ]
@@ -28,7 +43,7 @@ class ODataUrlBuilder(object):
28
43
  else:
29
44
  url += ",".join(
30
45
  [
31
- "%s" % (ODataUrlBuilder._encode_method_value(value))
46
+ "%s" % (ODataPathBuilder._encode_method_value(value))
32
47
  for (i, value) in enumerate(path.parameters)
33
48
  if value is not None
34
49
  ]
@@ -1,4 +1,4 @@
1
- from office365.runtime.paths.entity import EntityPath
1
+ from office365.runtime.paths.v4.entity import EntityPath
2
2
 
3
3
 
4
4
  class ItemPath(EntityPath):
@@ -1,18 +1,21 @@
1
+ from typing import Iterator
2
+
3
+
1
4
  class ResourcePath(object):
2
5
  """OData resource path"""
3
6
 
4
- def __init__(self, key, parent=None):
5
- """
6
- :type key: int or str
7
- :type parent: ResourcePath or None
8
- """
7
+ def __init__(self, key=None, parent=None):
8
+ # type: (int|str, "ResourcePath") -> None
9
9
  self._key = key
10
10
  self._parent = parent
11
11
 
12
- def patch(self, key, inplace=False):
12
+ def patch(self, key):
13
+ if self._key is None:
14
+ self._key = key
13
15
  return self
14
16
 
15
17
  def __iter__(self):
18
+ # type: () -> Iterator["ResourcePath"]
16
19
  current = self
17
20
  while current:
18
21
  yield current
@@ -25,11 +28,8 @@ class ResourcePath(object):
25
28
  return self.to_url()
26
29
 
27
30
  def to_url(self):
28
- """
29
- Builds url
30
-
31
- :rtype: str
32
- """
31
+ # type: () -> str
32
+ """Builds url"""
33
33
  segments = []
34
34
  for path in self:
35
35
  segments.insert(0, path.segment)
@@ -43,11 +43,7 @@ class ResourcePath(object):
43
43
 
44
44
  @property
45
45
  def segment(self):
46
- return str(self.key)
47
-
48
- @property
49
- def key(self):
50
- return self._key
46
+ return str(self._key)
51
47
 
52
48
  @property
53
49
  def delimiter(self):
@@ -1,4 +1,5 @@
1
- from office365.runtime.odata.url_builder import ODataUrlBuilder
1
+ from office365.runtime.client_value import ClientValue
2
+ from office365.runtime.paths.builder import ODataPathBuilder
2
3
  from office365.runtime.paths.resource_path import ResourcePath
3
4
 
4
5
 
@@ -6,17 +7,17 @@ class ServiceOperationPath(ResourcePath):
6
7
  """Path to address Service Operations which represents simple functions exposed by an OData service"""
7
8
 
8
9
  def __init__(self, name, parameters=None, parent=None):
9
- """
10
- :type parameters: list or dict or office365.runtime.client_value.ClientValue or None
11
- :type name: str
12
- :type parent: office365.runtime.paths.resource_path.ResourcePath
13
- """
10
+ # type: (str, list|dict|ClientValue, ResourcePath) -> None
14
11
  super(ServiceOperationPath, self).__init__(name, parent)
15
12
  self._parameters = parameters
16
13
 
17
14
  @property
18
15
  def segment(self):
19
- return ODataUrlBuilder.build_segment(self)
16
+ return ODataPathBuilder.build_segment(self)
17
+
18
+ @property
19
+ def name(self):
20
+ return self._key
20
21
 
21
22
  @property
22
23
  def parameters(self):
File without changes
@@ -1,16 +1,16 @@
1
1
  from office365.runtime.paths.resource_path import ResourcePath
2
2
 
3
3
 
4
- class KeyPath(ResourcePath):
4
+ class EntityPath(ResourcePath):
5
5
  """Path for addressing a single entity by key"""
6
6
 
7
7
  @property
8
8
  def segment(self):
9
- if self.key is None:
9
+ if self._key is None:
10
10
  return "(<key>)"
11
- elif isinstance(self.key, int):
12
- return "({0})".format(self.key)
13
- return "('{0}')".format(self.key)
11
+ elif isinstance(self._key, int):
12
+ return "({0})".format(self._key)
13
+ return "('{0}')".format(self._key)
14
14
 
15
15
  @property
16
16
  def delimiter(self):
File without changes
@@ -12,23 +12,25 @@ class EntityPath(ResourcePath):
12
12
 
13
13
  @property
14
14
  def collection(self):
15
+ from office365.onedrive.internal.paths.children import ChildrenPath
16
+
17
+ if self._collection is None:
18
+ if isinstance(self.parent, ChildrenPath):
19
+ self._collection = self.parent.collection
20
+ else:
21
+ self._collection = self.parent
15
22
  return self._collection
16
23
 
17
24
  @property
18
25
  def segment(self):
19
- return str(self.key or "<key>")
26
+ return str(self._key or "<key>")
20
27
 
21
- def patch(self, key, inplace=False):
28
+ def patch(self, key):
22
29
  """
23
30
  Patches path
24
-
25
31
  :type key: str or None
26
- :type inplace: bool
27
32
  """
28
- if inplace:
29
- self._key = key
30
- self._parent = self.collection
31
- self.__class__ = ResourcePath
32
- return self
33
- else:
34
- return ResourcePath(key, self.collection)
33
+ self._key = key
34
+ self._parent = self.collection
35
+ self.__class__ = EntityPath
36
+ return self
@@ -19,6 +19,12 @@ class ContentType(Entity):
19
19
  to items of those types
20
20
  """
21
21
 
22
+ def __str__(self):
23
+ return self.name
24
+
25
+ def __repr__(self):
26
+ return self.string_id or str(self.id) or self.entity_type_name
27
+
22
28
  def reorder_fields(self, field_names):
23
29
  """
24
30
  The ReorderFields method is called to change the order in which fields appear in a content type.
@@ -1,6 +1,8 @@
1
1
  from office365.runtime.http.http_method import HttpMethod
2
+ from office365.runtime.http.request_options import RequestOptions
2
3
  from office365.runtime.queries.client_query import ClientQuery
3
4
  from office365.sharepoint.folders.folder import Folder
5
+ from office365.sharepoint.lists.list import List
4
6
 
5
7
 
6
8
  class DocumentSet(Folder):
@@ -26,18 +28,14 @@ class DocumentSet(Folder):
26
28
  target_list.ensure_property("Title", _create, target_list=target_list)
27
29
 
28
30
  def _create(target_list):
29
- """
30
- :type target_list: office365.sharepoint.lists.list.List
31
- """
31
+ # type: (List) -> None
32
32
  qry = ClientQuery(context, return_type=return_type)
33
33
  context.add_query(qry)
34
34
  folder_url = parent_folder.serverRelativeUrl + "/" + name
35
35
  return_type.set_property("ServerRelativeUrl", folder_url)
36
36
 
37
37
  def _construct_request(request):
38
- """
39
- :type request: office365.runtime.http.request_options.RequestOptions
40
- """
38
+ # type: (RequestOptions) -> None
41
39
  list_name = target_list.title.replace(" ", "")
42
40
  request.url = r"{0}/_vti_bin/listdata.svc/{1}".format(
43
41
  context.base_url, list_name
@@ -2,6 +2,7 @@ from typing import TYPE_CHECKING, Optional, Type, TypeVar
2
2
 
3
3
  from office365.runtime.client_object_collection import ClientObjectCollection
4
4
  from office365.runtime.paths.resource_path import ResourcePath
5
+ from office365.runtime.paths.v3.entity import EntityPath
5
6
  from office365.sharepoint.entity import Entity
6
7
 
7
8
  if TYPE_CHECKING:
@@ -21,6 +22,14 @@ class EntityCollection(ClientObjectCollection[T]):
21
22
  context, item_type, resource_path, parent
22
23
  )
23
24
 
25
+ def create_typed_object(self, initial_properties=None, resource_path=None):
26
+ # type: (Optional[dict], Optional[ResourcePath]) -> T
27
+ if resource_path is None:
28
+ resource_path = EntityPath(None, self.resource_path)
29
+ return super(EntityCollection, self).create_typed_object(
30
+ initial_properties, resource_path
31
+ )
32
+
24
33
  @property
25
34
  def context(self):
26
35
  # type: () -> ClientContext
@@ -1,3 +1,5 @@
1
+ from typing import Optional
2
+
1
3
  from office365.sharepoint.entity import Entity
2
4
 
3
5
 
@@ -6,16 +8,12 @@ class Feature(Entity):
6
8
 
7
9
  @property
8
10
  def definition_id(self):
9
- """
10
- Gets the GUID that identifies this feature.
11
- :rtype: str or None
12
- """
11
+ # type: () -> Optional[str]
12
+ """Gets the GUID that identifies this feature."""
13
13
  return self.properties.get("DefinitionId", None)
14
14
 
15
15
  @property
16
16
  def display_name(self):
17
- """
18
- Gets the GUID that identifies this feature.
19
- :rtype: str or None
20
- """
17
+ # type: () -> Optional[str]
18
+ """Gets the GUID that identifies this feature."""
21
19
  return self.properties.get("DisplayName", None)
@@ -1,5 +1,5 @@
1
- from office365.runtime.paths.key import KeyPath
2
1
  from office365.runtime.paths.resource_path import ResourcePath
2
+ from office365.runtime.paths.v3.entity import EntityPath
3
3
  from office365.runtime.queries.service_operation import ServiceOperationQuery
4
4
  from office365.sharepoint.entity import Entity
5
5
  from office365.sharepoint.principal.users.user import User
@@ -43,5 +43,7 @@ class CheckedOutFile(Entity):
43
43
  super(CheckedOutFile, self).set_property(name, value, persist_changes)
44
44
  # fallback: create a new resource path
45
45
  if name == "CheckedOutById":
46
- self._resource_path = KeyPath(value, self.parent_collection.resource_path)
46
+ self._resource_path = EntityPath(
47
+ value, self.parent_collection.resource_path
48
+ )
47
49
  return self
@@ -3,7 +3,7 @@ from office365.sharepoint.entity_collection import EntityCollection
3
3
  from office365.sharepoint.files.checked_out_file import CheckedOutFile
4
4
 
5
5
 
6
- class CheckedOutFileCollection(EntityCollection):
6
+ class CheckedOutFileCollection(EntityCollection[CheckedOutFile]):
7
7
  def __init__(self, context, resource_path=None):
8
8
  super(CheckedOutFileCollection, self).__init__(
9
9
  context, CheckedOutFile, resource_path
@@ -1,23 +1,31 @@
1
+ import hashlib
1
2
  import os
2
3
  import uuid
3
- from typing import IO, Callable
4
+ from typing import IO, TYPE_CHECKING, Callable
4
5
 
5
6
  from office365.runtime.client_result import ClientResult
7
+ from office365.runtime.paths.resource_path import ResourcePath
6
8
  from office365.runtime.paths.service_operation import ServiceOperationPath
7
9
  from office365.runtime.queries.service_operation import ServiceOperationQuery
10
+ from office365.sharepoint.client_context import ClientContext
8
11
  from office365.sharepoint.entity_collection import EntityCollection
9
12
  from office365.sharepoint.files.creation_information import FileCreationInformation
10
13
  from office365.sharepoint.files.file import File
11
14
  from office365.sharepoint.types.resource_path import ResourcePath as SPResPath
12
15
 
16
+ if TYPE_CHECKING:
17
+ from office365.sharepoint.folders.folder import Folder
18
+
13
19
 
14
20
  class FileCollection(EntityCollection[File]):
15
21
  """Represents a collection of File resources."""
16
22
 
17
23
  def __init__(self, context, resource_path=None, parent=None):
24
+ # type: (ClientContext, ResourcePath, Folder) -> None
18
25
  super(FileCollection, self).__init__(context, File, resource_path, parent)
19
26
 
20
27
  def upload(self, path_or_file):
28
+ # type: (str|IO) -> File
21
29
  """Uploads a file into folder.
22
30
 
23
31
  Note: This method only supports files up to 4MB in size!
@@ -34,6 +42,23 @@ class FileCollection(EntityCollection[File]):
34
42
  name = os.path.basename(path_or_file)
35
43
  return self.add(name, content, True)
36
44
 
45
+ def upload_with_checksum(self, file_object, chunk_size=1024):
46
+ # type: (IO, int) -> File
47
+ """ """
48
+ h = hashlib.sha1() # hashlib.md5()
49
+ file_name = os.path.basename(file_object.name)
50
+ upload_id = str(uuid.uuid4())
51
+
52
+ def _upload_session(return_type):
53
+ # type: (File) -> None
54
+ content = file_object.read(chunk_size)
55
+ h.update(content)
56
+ return_type.upload_with_checksum(
57
+ upload_id, h.hexdigest(), content
58
+ ).after_execute(_upload_session)
59
+
60
+ return self.add(file_name, None, True).after_execute(_upload_session)
61
+
37
62
  def create_upload_session(
38
63
  self, file, chunk_size, chunk_uploaded=None, file_name=None, **kwargs
39
64
  ):
@@ -118,7 +143,7 @@ class FileCollection(EntityCollection[File]):
118
143
  return_type = File(self.context)
119
144
  self.add_child(return_type)
120
145
 
121
- def _parent_folder_loaded():
146
+ def _add_template_file():
122
147
  params = {
123
148
  "urlOfFile": str(
124
149
  SPResPath.create_relative(
@@ -132,17 +157,24 @@ class FileCollection(EntityCollection[File]):
132
157
  )
133
158
  self.context.add_query(qry)
134
159
 
135
- self.parent.ensure_property("ServerRelativeUrl", _parent_folder_loaded)
160
+ self.parent.ensure_property("ServerRelativeUrl", _add_template_file)
136
161
  return return_type
137
162
 
138
163
  def get_by_url(self, url):
164
+ # type: (str) -> File
139
165
  """Retrieve File object by url"""
140
166
  return File(
141
167
  self.context, ServiceOperationPath("GetByUrl", [url], self.resource_path)
142
168
  )
143
169
 
144
170
  def get_by_id(self, _id):
171
+ # type: (int) -> File
145
172
  """Gets the File with the specified ID."""
146
173
  return File(
147
174
  self.context, ServiceOperationPath("getById", [_id], self.resource_path)
148
175
  )
176
+
177
+ @property
178
+ def parent(self):
179
+ # type: () -> Folder
180
+ return self._parent