Office365-REST-Python-Client 3.1.0__py3-none-any.whl → 3.2.0__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 (245) hide show
  1. office365/communications/callrecords/call_record.py +18 -0
  2. office365/communications/calls/call.py +3 -0
  3. office365/communications/presences/presence.py +3 -0
  4. office365/communications/quotas.py +66 -0
  5. office365/communications/virtualevents/virtual_event.py +3 -0
  6. office365/directory/domains/domain.py +3 -0
  7. office365/directory/licenses/subscribed_sku.py +3 -0
  8. office365/directory/objects/object.py +3 -0
  9. office365/directory/quotas.py +34 -0
  10. office365/entity_collection.py +2 -2
  11. office365/graph_client.py +46 -2
  12. office365/limits.py +66 -0
  13. office365/migration/__init__.py +6 -1
  14. office365/migration/adapters/__init__.py +14 -4
  15. office365/migration/adapters/filesystem.py +4 -1
  16. office365/migration/assessment/export.py +5 -5
  17. office365/migration/assessment/issue.py +19 -0
  18. office365/migration/assessment/report.py +11 -0
  19. office365/migration/assessment/scanners/base.py +37 -49
  20. office365/migration/base.py +33 -8
  21. office365/migration/checkpoint.py +1 -1
  22. office365/migration/outlook/assessor.py +4 -4
  23. office365/migration/package/__init__.py +82 -0
  24. office365/migration/package/builder.py +603 -0
  25. office365/migration/package/crypto.py +54 -0
  26. office365/migration/package/manifest_xml.py +495 -0
  27. office365/migration/package/staging.py +180 -0
  28. office365/migration/report.py +7 -2
  29. office365/migration/report_io.py +79 -0
  30. office365/migration/runner.py +117 -10
  31. office365/migration/server_job.py +126 -14
  32. office365/migration/session.py +132 -49
  33. office365/migration/settings.py +67 -0
  34. office365/migration/sharepoint/__init__.py +2 -0
  35. office365/migration/sharepoint/adapters.py +207 -41
  36. office365/migration/sharepoint/assessor.py +45 -9
  37. office365/migration/sharepoint/options.py +57 -0
  38. office365/migration/sharepoint/package_target.py +209 -0
  39. office365/migration/sharepoint/registry.py +22 -0
  40. office365/migration/sharepoint/resolvers.py +96 -0
  41. office365/migration/sharepoint/scanners/__init__.py +29 -0
  42. office365/migration/sharepoint/scanners/browser_file_handling.py +55 -0
  43. office365/migration/sharepoint/scanners/checked_out_files.py +57 -0
  44. office365/migration/sharepoint/scanners/file_versions.py +56 -0
  45. office365/migration/sharepoint/scanners/files.py +5 -2
  46. office365/migration/sharepoint/scanners/large_excel_files.py +56 -0
  47. office365/migration/sharepoint/scanners/large_lists.py +58 -0
  48. office365/migration/sharepoint/scanners/large_sites.py +4 -3
  49. office365/migration/sharepoint/scanners/long_onedrive_urls.py +52 -0
  50. office365/migration/sharepoint/scanners/lookup.py +38 -0
  51. office365/migration/sharepoint/scanners/paths.py +9 -4
  52. office365/migration/sharepoint/scanners/permissions.py +20 -2
  53. office365/migration/sharepoint/scanners/smat.py +51 -0
  54. office365/migration/sharepoint/scanners/summary.py +1 -0
  55. office365/migration/sharepoint/scanners/thicket_folders.py +38 -0
  56. office365/migration/sharepoint/scanners/unsupported_site_templates.py +90 -0
  57. office365/migration/sharepoint/tenant_assessor.py +5 -3
  58. office365/migration/sharepoint/transfer.py +4 -2
  59. office365/migration/tasks.py +121 -0
  60. office365/migration/validators.py +2 -19
  61. office365/onedrive/driveitems/driveItem.py +116 -12
  62. office365/onedrive/termstore/groups/collection.py +2 -9
  63. office365/onedrive/termstore/sets/collection.py +2 -9
  64. office365/onedrive/termstore/terms/collection.py +3 -10
  65. office365/onedrive/workbooks/workbook.py +7 -0
  66. office365/outlook/contacts/folders/collection.py +4 -13
  67. office365/runtime/auth/authentication_context.py +5 -0
  68. office365/runtime/client_object.py +18 -0
  69. office365/runtime/client_object_collection.py +75 -245
  70. office365/runtime/client_request.py +77 -1
  71. office365/runtime/client_request_exception.py +127 -39
  72. office365/runtime/client_runtime_context.py +79 -8
  73. office365/runtime/converters/csv_writer.py +10 -4
  74. office365/runtime/converters/dataframe.py +84 -4
  75. office365/runtime/converters/json_file.py +12 -3
  76. office365/runtime/converters/parquet.py +67 -0
  77. office365/runtime/converters/records.py +31 -12
  78. office365/runtime/converters/registry.py +185 -0
  79. office365/runtime/converters/scalars.py +31 -0
  80. office365/runtime/converters/sql.py +69 -0
  81. office365/runtime/converters/streamers.py +105 -0
  82. office365/runtime/converters/streams.py +42 -0
  83. office365/runtime/converters/upsert.py +101 -0
  84. office365/runtime/exceptions.py +105 -0
  85. office365/runtime/http/prefer.py +26 -0
  86. office365/runtime/http/throttling.py +258 -56
  87. office365/runtime/imports.py +571 -0
  88. office365/runtime/limits.py +455 -0
  89. office365/runtime/odata/request.py +11 -2
  90. office365/runtime/odata/type.py +1 -0
  91. office365/runtime/odata/v3/batch_request.py +4 -2
  92. office365/runtime/odata/v4/batch_request.py +22 -7
  93. office365/runtime/operations.py +29 -0
  94. office365/runtime/parallel.py +12 -14
  95. office365/runtime/paths/v4/entity.py +2 -2
  96. office365/runtime/queries/batch.py +18 -1
  97. office365/runtime/queries/get_or_create.py +109 -0
  98. office365/runtime/record_collection.py +443 -0
  99. office365/runtime/retry.py +92 -26
  100. office365/runtime/transport/base.py +6 -1
  101. office365/runtime/transport/requests_transport.py +4 -0
  102. office365/runtime/transport/throttled_transport.py +67 -0
  103. office365/runtime/verification.py +40 -0
  104. office365/sharepoint/activities/logger.py +118 -8
  105. office365/sharepoint/administration/analytics/usage_service.py +15 -7
  106. office365/sharepoint/administration/sitemove/service.py +791 -8
  107. office365/sharepoint/alerts/alert.py +79 -0
  108. office365/sharepoint/apps/app_collection.py +25 -0
  109. office365/sharepoint/apps/launcher.py +16 -0
  110. office365/sharepoint/authpolicy/tenant/compliancereport.py +5 -0
  111. office365/sharepoint/businessdata/app_bdc_catalog.py +135 -0
  112. office365/sharepoint/businessdata/entityfieldvaluedictionary.py +65 -0
  113. office365/sharepoint/businessdata/entityidentifier.py +23 -0
  114. office365/sharepoint/businessdata/entityinstance.py +52 -0
  115. office365/sharepoint/businessdata/entityview.py +31 -0
  116. office365/sharepoint/businessdata/externalsubscriptionstore.py +9 -0
  117. office365/sharepoint/businessdata/typedescriptor.py +37 -0
  118. office365/sharepoint/client_context.py +40 -23
  119. office365/sharepoint/clientsidecomponent/hostedapps/app.py +21 -0
  120. office365/sharepoint/clientsidecomponent/hostedapps/manager.py +16 -0
  121. office365/sharepoint/comments/comment.py +84 -2
  122. office365/sharepoint/contentcenter/machinelearning/models/model.py +0 -23
  123. office365/sharepoint/contentcenter/machinelearning/publications/publication.py +0 -9
  124. office365/sharepoint/contentcenter/machinelearning/samples/sample.py +0 -14
  125. office365/sharepoint/contentcenter/machinelearning/workitems/item.py +0 -80
  126. office365/sharepoint/contentsolution/template_api.py +148 -0
  127. office365/sharepoint/contenttypes/collection.py +32 -10
  128. office365/sharepoint/convergence/addnoliveblobsinodcservicestateapi.py +9 -0
  129. office365/sharepoint/convergence/consumer_permissions.py +15 -0
  130. office365/sharepoint/convergence/migration_complete_state_api.py +25 -0
  131. office365/sharepoint/convergence/odcmetadatacleanedupapi.py +9 -0
  132. office365/sharepoint/documentmanagement/document_id.py +12 -0
  133. office365/sharepoint/entity.py +11 -2
  134. office365/sharepoint/entity_collection.py +2 -2
  135. office365/sharepoint/exceptions.py +194 -0
  136. office365/sharepoint/fields/builtin_field_id.py +45 -34
  137. office365/sharepoint/fields/builtin_field_name.py +123 -0
  138. office365/sharepoint/fields/coercion.py +131 -0
  139. office365/sharepoint/fields/collection.py +54 -37
  140. office365/sharepoint/fields/field.py +17 -0
  141. office365/sharepoint/fields/name.py +46 -2
  142. office365/sharepoint/files/collection.py +7 -1
  143. office365/sharepoint/files/file.py +54 -8
  144. office365/sharepoint/files/versions/version.py +38 -13
  145. office365/sharepoint/folders/collection.py +4 -0
  146. office365/sharepoint/folders/folder.py +91 -21
  147. office365/sharepoint/htmlpages/html_page.py +16 -0
  148. office365/sharepoint/htmlpages/html_page_service.py +19 -0
  149. office365/sharepoint/ir/migration.py +9 -0
  150. office365/sharepoint/listitems/caml/__init__.py +31 -0
  151. office365/sharepoint/listitems/caml/builder.py +129 -0
  152. office365/sharepoint/listitems/caml/expressions.py +424 -0
  153. office365/sharepoint/listitems/caml/fields.py +68 -0
  154. office365/sharepoint/listitems/caml/guard.py +63 -0
  155. office365/sharepoint/listitems/caml/query.py +71 -2
  156. office365/sharepoint/listitems/caml/values.py +113 -0
  157. office365/sharepoint/listitems/collection.py +21 -20
  158. office365/sharepoint/listitems/upsert.py +75 -0
  159. office365/sharepoint/lists/collection.py +29 -22
  160. office365/sharepoint/lists/exporter.py +4 -3
  161. office365/sharepoint/lists/list.py +397 -39
  162. office365/sharepoint/lists/smart_wiki_library_utility.py +58 -0
  163. office365/sharepoint/logger/export.py +12 -0
  164. office365/sharepoint/marketplace/app_metadata.py +97 -1
  165. office365/sharepoint/marketplace/appstatequeryjobdefinition.py +9 -0
  166. office365/sharepoint/marketplace/corporatecuratedgallery/carddesigns/card_designs.py +35 -0
  167. office365/sharepoint/marketplace/sitecollection/appcatalog/allowed_item.py +5 -0
  168. office365/sharepoint/marketplace/tenant/appcatalog/accessor.py +107 -30
  169. office365/sharepoint/microfeed/data.py +0 -6
  170. office365/sharepoint/microservice/manager.py +61 -0
  171. office365/sharepoint/migrationcenter/common/task.py +193 -4
  172. office365/sharepoint/migrationcenter/common/task_entity_data.py +1 -1
  173. office365/sharepoint/migrationcenter/deploy_status.py +13 -0
  174. office365/sharepoint/migrationcenter/service/properties.py +20 -0
  175. office365/sharepoint/migrationcenter/service/storage.py +34 -0
  176. office365/sharepoint/migrationcenter/spflight.py +13 -0
  177. office365/sharepoint/migrationcenter/urlparseresult.py +77 -0
  178. office365/sharepoint/multigeo/service/spmultigeoproxy.py +13 -0
  179. office365/sharepoint/navigation/servicerest.py +127 -0
  180. office365/sharepoint/oauth/authentication.py +13 -0
  181. office365/sharepoint/portal/theme_manager.py +120 -8
  182. office365/sharepoint/principal/users/user.py +10 -0
  183. office365/sharepoint/publishing/campaign/campaign.py +36 -1
  184. office365/sharepoint/publishing/feedvideopage.py +0 -7
  185. office365/sharepoint/publishing/pages/3d/page.py +0 -6
  186. office365/sharepoint/publishing/pages/page.py +0 -117
  187. office365/sharepoint/publishing/pages/reposts/repost.py +0 -7
  188. office365/sharepoint/publishing/pages/topics/topic.py +0 -7
  189. office365/sharepoint/publishing/subtitlefile.py +0 -40
  190. office365/sharepoint/quotamanagement/consumer/consumer_quota_info_api.py +14 -0
  191. office365/sharepoint/quotamanagement/consumer/non_quota_backfill_api.py +23 -0
  192. office365/sharepoint/quotamanagement/consumer/nonquotamigrationapi.py +9 -0
  193. office365/sharepoint/quotamanagement/consumer/quotamigrationapi.py +13 -0
  194. office365/sharepoint/request.py +57 -16
  195. office365/sharepoint/search/administration/document_crawl_log.py +24 -7
  196. office365/sharepoint/search/administration/providers/crawl_versions_info.py +29 -0
  197. office365/sharepoint/search/administration/providers/recycle_bin_info.py +23 -0
  198. office365/sharepoint/search/administration/providers/site_content_processing_info.py +67 -0
  199. office365/sharepoint/sites/site.py +976 -65
  200. office365/sharepoint/sites/siteprovisioninginfoprovider.py +13 -0
  201. office365/sharepoint/tenant/administration/datagovernance/insight_client.py +292 -23
  202. office365/sharepoint/tenant/administration/ddiadapter.py +97 -0
  203. office365/sharepoint/tenant/administration/internal/aad/collection.py +20 -0
  204. office365/sharepoint/tenant/administration/internal/aad/permission_grant.py +0 -19
  205. office365/sharepoint/tenant/administration/internal/appservice/permission_request.py +72 -1
  206. office365/sharepoint/tenant/administration/internal/appservice/principal.py +1 -3
  207. office365/sharepoint/tenant/administration/odb_license_enforcement_service.py +26 -0
  208. office365/sharepoint/tenant/administration/sites/properties.py +564 -6
  209. office365/sharepoint/tenant/administration/spdatagovernancesarrestapiclient.py +60 -1
  210. office365/sharepoint/tenant/insights/reports/manager.py +24 -12
  211. office365/sharepoint/tenant/management/office365_tenant.py +451 -2
  212. office365/sharepoint/tenantadministration/catalog_management_collection.py +69 -0
  213. office365/sharepoint/tenantadministration/catalog_management_custom_properties_collection.py +237 -0
  214. office365/sharepoint/tenantadministration/catalog_management_restricted_content_discovery_collection.py +56 -0
  215. office365/sharepoint/tenantadministration/sp_data_governance_client_exception.py +7 -0
  216. office365/sharepoint/thresholds.py +529 -0
  217. office365/sharepoint/translation/jobs/job.py +72 -2
  218. office365/sharepoint/translation/jobs/status.py +47 -9
  219. office365/sharepoint/translation/sync_translator.py +15 -2
  220. office365/sharepoint/utilities/move_copy_util.py +2 -1
  221. office365/sharepoint/viva/connections/page.py +27 -0
  222. office365/sharepoint/viva/home.py +38 -0
  223. office365/sharepoint/viva/learningmanager.py +9 -0
  224. office365/sharepoint/viva/vivaresources.py +60 -0
  225. office365/sharepoint/webhooks/subscription.py +0 -11
  226. office365/sharepoint/webparts/definitions/definition.py +13 -0
  227. office365/sharepoint/webparts/limited_manager.py +29 -7
  228. office365/sharepoint/webs/context_web_information.py +14 -9
  229. office365/sharepoint/webs/templates/__init__.py +11 -0
  230. office365/sharepoint/webs/templates/type.py +74 -15
  231. office365/sharepoint/workflow/definition.py +6 -0
  232. office365/sharepoint/workflow/deployment_service.py +155 -0
  233. office365/sharepoint/workflow/instances/service.py +33 -0
  234. office365/sharepoint/workflow/interopservice.py +68 -0
  235. office365/sharepoint/workflow/messagingservice.py +24 -0
  236. office365/sharepoint/workflow/servicesmanager.py +41 -2
  237. office365/sharepoint/workflow/subscriptions/service.py +67 -0
  238. office365/sharepoint/workflow/subscriptions/subscription.py +31 -0
  239. office365/sharepoint/workflow/task.py +425 -0
  240. office365_rest_python_client-3.2.0.dist-info/METADATA +605 -0
  241. {office365_rest_python_client-3.1.0.dist-info → office365_rest_python_client-3.2.0.dist-info}/RECORD +242 -185
  242. office365/migration/_util.py +0 -73
  243. office365/sharepoint/listitems/caml/types.py +0 -70
  244. office365_rest_python_client-3.1.0.dist-info/METADATA +0 -475
  245. {office365_rest_python_client-3.1.0.dist-info → office365_rest_python_client-3.2.0.dist-info}/WHEEL +0 -0
@@ -8,11 +8,16 @@ jitter (so a fleet of clients doesn't retry in lock-step).
8
8
  from __future__ import annotations
9
9
 
10
10
  import random
11
+ from functools import wraps
11
12
  from time import sleep
12
13
  from typing import Any, Callable, Optional, Tuple, Type
13
14
 
15
+ from typing_extensions import ParamSpec
16
+
14
17
  from office365.runtime.client_request_exception import ClientRequestException
15
18
 
19
+ _P = ParamSpec("_P")
20
+
16
21
  TRANSIENT_STATUS_CODES = frozenset({408, 429, 500, 502, 503, 504})
17
22
 
18
23
 
@@ -85,8 +90,40 @@ def backoff_delay(attempt: int, base: int, max_delay: Optional[int] = None, jitt
85
90
  return delay
86
91
 
87
92
 
88
- def retry(
93
+ def _run_with_retry(
89
94
  func: Callable[[], Any],
95
+ *,
96
+ max_retry: int,
97
+ timeout_secs: int,
98
+ max_delay: Optional[int],
99
+ jitter: bool,
100
+ exceptions: Tuple[Type[Exception], ...],
101
+ is_retriable: Callable[[Exception], bool],
102
+ on_failure: Optional[Callable[[int, Exception], Optional[int]]],
103
+ on_success: Optional[Callable[[Any], None]],
104
+ ) -> Any:
105
+ last_ex: Exception | None = None
106
+ for attempt in range(1, max_retry + 1):
107
+ try:
108
+ result = func()
109
+ if callable(on_success):
110
+ on_success(result)
111
+ return result
112
+ except exceptions as e:
113
+ if not callable(is_retriable) or not is_retriable(e):
114
+ raise
115
+ last_ex = e
116
+ retry_after: Optional[int] = None
117
+ if callable(on_failure):
118
+ retry_after = on_failure(attempt, e)
119
+ delay = retry_after if retry_after is not None else backoff_delay(attempt, timeout_secs, max_delay, jitter)
120
+ sleep(delay)
121
+ assert last_ex is not None
122
+ raise last_ex
123
+
124
+
125
+ def retry(
126
+ func: Optional[Callable[[], Any]] = None,
90
127
  max_retry: int = 5,
91
128
  timeout_secs: int = 5,
92
129
  max_delay: Optional[int] = None,
@@ -96,20 +133,27 @@ def retry(
96
133
  on_failure: Optional[Callable[[int, Exception], Optional[int]]] = None,
97
134
  on_success: Optional[Callable[[Any], None]] = None,
98
135
  ) -> Any:
99
- """Run ``func``, retrying transient failures with exponential backoff.
136
+ """Run ``func`` with retries — or, called without ``func``, return a decorator.
100
137
 
101
138
  Permanent failures re-raise immediately; the last exception is re-raised
102
- once retries are exhausted.
139
+ once retries are exhausted. The delay between attempts is exponential with
140
+ jitter (:func:`backoff_delay`); when ``on_failure`` returns a delay (e.g.
141
+ the server's ``Retry-After`` via :func:`retry_after_delay`) that value
142
+ overrides the backoff.
143
+
144
+ Two forms::
103
145
 
104
- The delay between attempts is exponential with jitter (``backoff_delay``);
105
- when ``on_failure`` returns a delay (e.g. the server's ``Retry-After`` via
106
- :func:`retry_after_delay`) that value overrides the backoff.
146
+ retry(do_request, max_retry=3) # run now (existing behaviour)
147
+
148
+
149
+ @retry(max_retry=3) # decorate a callable
150
+ def do_request(): ...
107
151
 
108
152
  Args:
109
- func: Callable to execute
153
+ func: Callable to execute. Omit to get a decorator.
110
154
  max_retry: Maximum number of retry attempts
111
155
  timeout_secs: Base delay for exponential backoff (seconds)
112
- max_delay: Optional cap on the exponential delay (seconds)
156
+ max_delay: Optional cap for the exponential delay (seconds)
113
157
  jitter: Whether to randomize the delay (default True)
114
158
  exceptions: Exception types that are candidates for retry
115
159
  is_retriable: Classifier deciding whether a caught exception is retried
@@ -117,21 +161,43 @@ def retry(
117
161
  may return a retry delay (seconds) to override the backoff
118
162
  on_success: Called with ``func()`` result on success
119
163
  """
120
- last_ex: Exception | None = None
121
- for attempt in range(1, max_retry + 1):
122
- try:
123
- result = func()
124
- if callable(on_success):
125
- on_success(result)
126
- return result
127
- except exceptions as e:
128
- if not callable(is_retriable) or not is_retriable(e):
129
- raise
130
- last_ex = e
131
- retry_after: Optional[int] = None
132
- if callable(on_failure):
133
- retry_after = on_failure(attempt, e)
134
- delay = retry_after if retry_after is not None else backoff_delay(attempt, timeout_secs, max_delay, jitter)
135
- sleep(delay)
136
- assert last_ex is not None
137
- raise last_ex
164
+ options = {
165
+ "max_retry": max_retry,
166
+ "timeout_secs": timeout_secs,
167
+ "max_delay": max_delay,
168
+ "jitter": jitter,
169
+ "exceptions": exceptions,
170
+ "is_retriable": is_retriable,
171
+ "on_failure": on_failure,
172
+ "on_success": on_success,
173
+ }
174
+ if func is None:
175
+
176
+ def decorator(fn: Callable[_P, Any]) -> Callable[_P, Any]:
177
+ @wraps(fn)
178
+ def wrapper(*args: _P.args, **kwargs: _P.kwargs) -> Any:
179
+ return _run_with_retry(lambda: fn(*args, **kwargs), **options) # type: ignore[arg-type]
180
+
181
+ return wrapper
182
+
183
+ return decorator
184
+ return _run_with_retry(func, **options) # type: ignore[arg-type]
185
+
186
+
187
+ def retry_on(*exception_types: Type[Exception]) -> Callable[[Exception], bool]:
188
+ """Return a predicate that retries only the given exception types.
189
+
190
+ By default only transient failures are retried (HTTP 408/429/500/502/503/504
191
+ or non-HTTP errors). Use this as ``is_retriable`` to opt into retrying
192
+ failures the runtime does not consider transient - for example a file that
193
+ is locked while a user has it open (HTTP 423)::
194
+
195
+ from office365.runtime.exceptions import FileLockedException
196
+ from office365.runtime.retry import retry_on
197
+
198
+ folder.upload_file(name, content).execute_query_retry(is_retriable=retry_on(FileLockedException))
199
+
200
+ Args:
201
+ exception_types: Exception classes that should be retried.
202
+ """
203
+ return lambda ex: isinstance(ex, exception_types)
@@ -3,7 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from abc import ABC, abstractmethod
6
- from typing import Tuple
6
+ from typing import Any, Tuple
7
7
 
8
8
  from requests import Response
9
9
  from typing_extensions import Self
@@ -37,6 +37,11 @@ class BaseTransport(ABC):
37
37
  """Transport-level request timeout in seconds."""
38
38
  return None
39
39
 
40
+ @property
41
+ def auth(self) -> Any | None:
42
+ """Transport-level authentication handler, e.g. ``session.auth``."""
43
+ return None
44
+
40
45
  def close(self) -> None: # noqa: B027
41
46
  """Release transport resources (connections, etc.)."""
42
47
 
@@ -44,6 +44,10 @@ class RequestsTransport(BaseTransport):
44
44
  def timeout(self) -> int | Tuple[int, int] | None:
45
45
  return self._timeout
46
46
 
47
+ @property
48
+ def auth(self) -> Any | None:
49
+ return self._session.auth
50
+
47
51
  def execute(self, request: RequestOptions) -> Response:
48
52
  kwargs: dict[str, Any] = {"headers": request.headers}
49
53
  if request.verify is not None:
@@ -0,0 +1,67 @@
1
+ """Transport decorator that paces requests through a shared rate limiter.
2
+
3
+ Wraps any :class:`~office365.runtime.transport.base.BaseTransport` so every
4
+ request is gated by a shared :class:`~office365.runtime.http.throttling.RateLimiter`
5
+ before it is sent and every response (or error's response) is fed back into it.
6
+ The wrapper is transport-agnostic — it composes with ``requests`` today and with
7
+ an async transport later, and it keeps the pacing at the single I/O boundary so
8
+ call sites stay free of side effects.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from typing import TYPE_CHECKING, Any, Tuple
14
+
15
+ from office365.runtime.http.throttling import paced
16
+ from office365.runtime.transport.base import BaseTransport
17
+
18
+ if TYPE_CHECKING:
19
+ from requests import Response
20
+
21
+ from office365.runtime.http.request_options import RequestOptions
22
+ from office365.runtime.http.throttling import RateLimiter
23
+
24
+
25
+ class ThrottledTransport(BaseTransport):
26
+ """Decorates a transport with fleet-wide pacing from a shared limiter.
27
+
28
+ Args:
29
+ inner: The wrapped transport performing the actual I/O.
30
+ limiter: The shared :class:`RateLimiter` gating the fleet.
31
+ """
32
+
33
+ def __init__(self, inner: BaseTransport, limiter: "RateLimiter") -> None:
34
+ self._inner = inner
35
+ self._limiter = limiter
36
+
37
+ @property
38
+ def inner(self) -> BaseTransport:
39
+ """The wrapped transport."""
40
+ return self._inner
41
+
42
+ @property
43
+ def limiter(self) -> "RateLimiter":
44
+ """The shared rate limiter."""
45
+ return self._limiter
46
+
47
+ def execute(self, request: "RequestOptions") -> "Response":
48
+ return paced(lambda: self._inner.execute(request), self._limiter)
49
+
50
+ @property
51
+ def proxies(self) -> dict[str, str] | None:
52
+ return self._inner.proxies
53
+
54
+ @property
55
+ def verify(self) -> bool | str:
56
+ return self._inner.verify
57
+
58
+ @property
59
+ def timeout(self) -> int | Tuple[int, int] | None:
60
+ return self._inner.timeout
61
+
62
+ @property
63
+ def auth(self) -> Any | None:
64
+ return self._inner.auth
65
+
66
+ def close(self) -> None:
67
+ self._inner.close()
@@ -0,0 +1,40 @@
1
+ """Shared reconciliation report for the data pipeline and the migration toolkit.
2
+
3
+ One report type is returned by every ``verify*`` (``RecordCollection.verify``,
4
+ ``List.verify``, ``ImportResult.verify`` and ``migration.verify``), so callers
5
+ reason about reconciliation the same way regardless of the operation.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass, field
11
+
12
+
13
+ @dataclass
14
+ class VerificationReport:
15
+ """Outcome of a source-vs-target reconciliation.
16
+
17
+ ``source_count``/``target_count`` are the expected/found item counts,
18
+ ``checked`` the number of items checked, ``missing`` the expected keys absent
19
+ on the target, and ``mismatches`` human-readable issues (content mismatches,
20
+ unexpected items, ...). ``ok`` is True when the counts match and both lists
21
+ are empty.
22
+ """
23
+
24
+ source_count: int = 0
25
+ target_count: int = 0
26
+ checked: int = 0
27
+ missing: list[str] = field(default_factory=list)
28
+ mismatches: list[str] = field(default_factory=list)
29
+
30
+ @property
31
+ def ok(self) -> bool:
32
+ """Whether the source and target reconcile."""
33
+ return self.source_count == self.target_count and not self.missing and not self.mismatches
34
+
35
+ def summary(self) -> str:
36
+ status = "OK" if self.ok else "MISMATCH"
37
+ return (
38
+ f"{status} | source: {self.source_count}, target: {self.target_count}, "
39
+ f"checked: {self.checked}, missing: {len(self.missing)}, issues: {len(self.mismatches)}"
40
+ )
@@ -1,17 +1,16 @@
1
+ from uuid import UUID
2
+
3
+ from typing_extensions import Self
4
+
5
+ from office365.runtime.client_value_collection import ClientValueCollection
1
6
  from office365.runtime.queries.service_operation import ServiceOperationQuery
2
7
  from office365.sharepoint.entity import Entity
8
+ from office365.sharepoint.logger.activityrequest import LogActivityRequest
3
9
 
4
10
 
5
11
  class ActivityLogger(Entity):
6
12
  def log_activity(
7
- self,
8
- operation,
9
- list_id,
10
- list_item_unique_id,
11
- affected_resource_url,
12
- item_type,
13
- audit_creation_time,
14
- is_offline,
13
+ self, operation, list_id, list_item_unique_id, affected_resource_url, item_type, audit_creation_time, is_offline
15
14
  ):
16
15
  """Args:
17
16
  operation (str):
@@ -38,3 +37,114 @@ class ActivityLogger(Entity):
38
37
  @property
39
38
  def entity_type_name(self):
40
39
  return "Microsoft.SharePoint.Internal.ActivityLogger"
40
+
41
+ def feedback_direct(
42
+ self,
43
+ operation: str,
44
+ list_id: UUID,
45
+ list_item_unique_id: UUID,
46
+ affected_resource_url: str,
47
+ item_type: str,
48
+ json: str,
49
+ ) -> Self:
50
+ """FeedbackDirect operation.
51
+
52
+ Args:
53
+ operation (str): Operation parameter
54
+ list_id (UUID): ListId parameter
55
+ list_item_unique_id (UUID): ListItemUniqueId parameter
56
+ affected_resource_url (str): AffectedResourceUrl parameter
57
+ item_type (str): ItemType parameter
58
+ json (str): json parameter
59
+ """
60
+ qry = ServiceOperationQuery(
61
+ self,
62
+ "FeedbackDirect",
63
+ None,
64
+ {
65
+ "Operation": operation,
66
+ "ListId": list_id,
67
+ "ListItemUniqueId": list_item_unique_id,
68
+ "AffectedResourceUrl": affected_resource_url,
69
+ "ItemType": item_type,
70
+ "json": json,
71
+ },
72
+ None,
73
+ None,
74
+ )
75
+ self.context.add_query(qry)
76
+ return self
77
+
78
+ def feedback_indirect(
79
+ self,
80
+ operation: str,
81
+ list_id: UUID,
82
+ list_item_unique_id: UUID,
83
+ affected_resource_url: str,
84
+ item_type: str,
85
+ json: str,
86
+ ) -> Self:
87
+ """FeedbackIndirect operation.
88
+
89
+ Args:
90
+ operation (str): Operation parameter
91
+ list_id (UUID): ListId parameter
92
+ list_item_unique_id (UUID): ListItemUniqueId parameter
93
+ affected_resource_url (str): AffectedResourceUrl parameter
94
+ item_type (str): ItemType parameter
95
+ json (str): json parameter
96
+ """
97
+ qry = ServiceOperationQuery(
98
+ self,
99
+ "FeedbackIndirect",
100
+ None,
101
+ {
102
+ "Operation": operation,
103
+ "ListId": list_id,
104
+ "ListItemUniqueId": list_item_unique_id,
105
+ "AffectedResourceUrl": affected_resource_url,
106
+ "ItemType": item_type,
107
+ "json": json,
108
+ },
109
+ None,
110
+ None,
111
+ )
112
+ self.context.add_query(qry)
113
+ return self
114
+
115
+ def log_activity_bulk(
116
+ self,
117
+ operation: str,
118
+ site_id: UUID,
119
+ web_id: UUID,
120
+ list_id: UUID,
121
+ mailbox_type: str,
122
+ requests: ClientValueCollection[LogActivityRequest],
123
+ ) -> Self:
124
+ """LogActivityBulk operation.
125
+
126
+ Args:
127
+ operation (str): Operation parameter
128
+ site_id (UUID): SiteId parameter
129
+ web_id (UUID): WebId parameter
130
+ list_id (UUID): ListId parameter
131
+ mailbox_type (str): MailboxType parameter
132
+ requests (ClientValueCollection[LogActivityRequest]): Requests parameter
133
+ """
134
+ qry = ServiceOperationQuery(
135
+ self,
136
+ "LogActivityBulk",
137
+ None,
138
+ {
139
+ "Operation": operation,
140
+ "SiteId": site_id,
141
+ "WebId": web_id,
142
+ "ListId": list_id,
143
+ "MailboxType": mailbox_type,
144
+ "Requests": requests,
145
+ },
146
+ None,
147
+ None,
148
+ )
149
+ self.context.add_query(qry)
150
+ return self
@@ -1,5 +1,9 @@
1
+ from typing_extensions import Self
2
+
1
3
  from office365.runtime.paths.resource_path import ResourcePath
4
+ from office365.runtime.queries.function import FunctionQuery
2
5
  from office365.runtime.queries.service_operation import ServiceOperationQuery
6
+ from office365.sharepoint.administration.usageentry import UsageEntry
3
7
  from office365.sharepoint.entity import Entity
4
8
 
5
9
 
@@ -20,13 +24,7 @@ class SPAnalyticsUsageService(Entity):
20
24
  site (str):
21
25
  user (str):
22
26
  """
23
- payload = {
24
- "EventTypeId": event_type_id,
25
- "ItemId": item_id,
26
- "ScopeId": scope_id,
27
- "Site": site,
28
- "User": user,
29
- }
27
+ payload = {"EventTypeId": event_type_id, "ItemId": item_id, "ScopeId": scope_id, "Site": site, "User": user}
30
28
  qry = ServiceOperationQuery(self, "logevent", None, payload)
31
29
  self.context.add_query(qry)
32
30
  return self
@@ -34,3 +32,13 @@ class SPAnalyticsUsageService(Entity):
34
32
  @property
35
33
  def entity_type_name(self):
36
34
  return "Microsoft.SharePoint.Administration.SPAnalyticsUsageService"
35
+
36
+ def logevent(self, usage_entry: UsageEntry) -> Self:
37
+ """logevent operation.
38
+
39
+ Args:
40
+ usage_entry (UsageEntry): usageEntry parameter
41
+ """
42
+ qry = FunctionQuery(self, "logevent", [usage_entry], None)
43
+ self.context.add_query(qry)
44
+ return self