Skip to content

Commit eed54b8

Browse files
committed
typings enhancements, perf and test rate limit examples
1 parent 9666ffa commit eed54b8

File tree

18 files changed

+328
-42
lines changed

18 files changed

+328
-42
lines changed

examples/sharepoint/connect.ipynb

+9-17
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,16 @@
1111
"start_time": "2024-02-11T10:23:26.197964378Z"
1212
}
1313
},
14-
"outputs": [],
1514
"source": [
1615
"from office365.sharepoint.client_context import ClientContext\n",
1716
"client_id = \"4b7eb3df-afc3-4b7d-ae1d-629f22a3fe42\" \n",
1817
"site_url = \"https://mediadev8.sharepoint.com\"\n",
1918
"tenant_name = \"mediadev8.onmicrosoft.com\""
20-
]
19+
],
20+
"outputs": []
2121
},
2222
{
2323
"cell_type": "code",
24-
"outputs": [],
2524
"source": [
2625
"ctx = ClientContext(site_url).with_interactive(tenant_name, client_id)"
2726
],
@@ -33,20 +32,11 @@
3332
}
3433
},
3534
"id": "b5504d6537baaebd",
36-
"execution_count": 32
35+
"execution_count": 32,
36+
"outputs": []
3737
},
3838
{
3939
"cell_type": "code",
40-
"outputs": [
41-
{
42-
"data": {
43-
"text/plain": "[email protected]"
44-
},
45-
"execution_count": 34,
46-
"metadata": {},
47-
"output_type": "execute_result"
48-
}
49-
],
5040
"source": [
5141
"me = ctx.web.current_user.get().execute_query()\n",
5242
"me"
@@ -59,16 +49,18 @@
5949
}
6050
},
6151
"id": "e61a0947e8ef00d5",
62-
"execution_count": 34
52+
"execution_count": 34,
53+
"outputs": []
6354
},
6455
{
6556
"cell_type": "code",
66-
"outputs": [],
6757
"source": [],
6858
"metadata": {
6959
"collapsed": false
7060
},
71-
"id": "403e49d95b83b674"
61+
"id": "403e49d95b83b674",
62+
"execution_count": null,
63+
"outputs": []
7264
}
7365
],
7466
"metadata": {

examples/sharepoint/run_test_perf.py

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
Diagnosing performance issues
3+
4+
In SharePoint, you can access the information that is sent back to the client in the response header for each file.
5+
The most useful value for diagnosing performance issues is SPRequestDuration, which displays the amount of time
6+
that the request took on the server to be processed. This can help determine if the request is heavy and resource
7+
intensive.
8+
9+
https://learn.microsoft.com/en-us/microsoft-365/enterprise/diagnosing-performance-issues-with-sharepoint-online?view=o365-worldwide
10+
"""
11+
from requests import Response
12+
13+
from office365.sharepoint.client_context import ClientContext
14+
from tests import test_client_credentials, test_site_url
15+
16+
17+
def do_work(client: ClientContext):
18+
def _after_execute(resp: Response):
19+
header_name = "SPRequestDuration"
20+
duration = resp.headers.get(header_name, None)
21+
if duration:
22+
print("SPRequestDuration: {0}".format(duration))
23+
24+
def _execute(iteration: int):
25+
web = (
26+
client.web.get()
27+
.after_execute(_after_execute, include_response=True)
28+
.execute_query()
29+
)
30+
print("Iteration: {0}, result: {1}".format(iteration, web.title))
31+
32+
for i in range(10):
33+
_execute(i)
34+
35+
36+
if __name__ == "__main__":
37+
ctx = ClientContext(test_site_url).with_credentials(test_client_credentials)
38+
do_work(ctx)
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""
2+
"""
3+
import asyncio
4+
5+
from requests import Response
6+
7+
from office365.sharepoint.client_context import ClientContext
8+
from tests import test_client_credentials, test_site_url
9+
10+
11+
async def do_work(client: ClientContext, instance: int):
12+
def _inspect_response(resp: Response):
13+
header_names = ["RateLimit-Limit", "RateLimit-Remaining", "RateLimit-Reset"]
14+
rate_limit = {}
15+
for header_name in header_names:
16+
header_value = resp.headers.get(header_name, None)
17+
if header_value is not None:
18+
rate_limit[header_name] = header_value
19+
20+
if rate_limit:
21+
print(rate_limit)
22+
23+
def _execute(iteration: int):
24+
web = client.web.get().execute_query_with_incremental_retry()
25+
if iteration % 25 == 0:
26+
print(
27+
"Instance #{0}, iteration: {1}, result: {2}".format(
28+
instance, iteration, web.title
29+
)
30+
)
31+
32+
for i in range(1000):
33+
await loop.run_in_executor(None, _execute, i)
34+
35+
36+
async def main():
37+
ctx = ClientContext(test_site_url).with_credentials(test_client_credentials)
38+
tasks = []
39+
for i in range(20):
40+
tasks.append(do_work(ctx, i))
41+
await asyncio.gather(*tasks)
42+
43+
44+
if __name__ == "__main__":
45+
loop = asyncio.get_event_loop()
46+
loop.run_until_complete(main())
47+
loop.close()

examples/sharepoint/search/search_documents.py

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""
2+
Search for document files
23
34
"""
45
from office365.sharepoint.client_context import ClientContext

examples/sharepoint/search/search_site_only.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
ctx = ClientContext(test_site_url).with_credentials(test_user_credentials)
1212

1313
result = ctx.search.post_query(
14-
"Path={0}/*".format(test_team_site_url), row_limit=10
14+
"Path:{0}".format(test_team_site_url), row_limit=10
1515
).execute_query()
1616
for row in result.value.PrimaryQueryResult.RelevantResults.Table.Rows:
1717
print("{0}".format(row.Cells["Path"]))

examples/sharepoint/sitescripts/__init__.py

Whitespace-only changes.

generator/import_metadata.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ def export_to_file(path, content):
2626
"--endpoint",
2727
dest="endpoint",
2828
help="Import metadata endpoint",
29-
default="microsoftgraph",
29+
default="sharepoint",
3030
)
3131
parser.add_argument(
3232
"-p",
3333
"--path",
3434
dest="path",
35-
default="./metadata/MicrosoftGraph.xml",
35+
default="./metadata/SharePoint.xml",
3636
help="Import metadata endpoint",
3737
)
3838

generator/metadata/MicrosoftGraph.xml

+83-1
Original file line numberDiff line numberDiff line change
@@ -20709,6 +20709,52 @@
2070920709
<Member Name="stapleDualRight" Value="30"/>
2071020710
<Member Name="stapleDualBottom" Value="31"/>
2071120711
<Member Name="unknownFutureValue" Value="32"/>
20712+
<Member Name="stapleTripleLeft" Value="33"/>
20713+
<Member Name="stapleTripleTop" Value="34"/>
20714+
<Member Name="stapleTripleRight" Value="35"/>
20715+
<Member Name="stapleTripleBottom" Value="36"/>
20716+
<Member Name="bindLeft" Value="37"/>
20717+
<Member Name="bindTop" Value="38"/>
20718+
<Member Name="bindRight" Value="39"/>
20719+
<Member Name="bindBottom" Value="40"/>
20720+
<Member Name="foldAccordion" Value="41"/>
20721+
<Member Name="foldDoubleGate" Value="42"/>
20722+
<Member Name="foldGate" Value="43"/>
20723+
<Member Name="foldHalf" Value="44"/>
20724+
<Member Name="foldHalfZ" Value="45"/>
20725+
<Member Name="foldLeftGate" Value="46"/>
20726+
<Member Name="foldLetter" Value="47"/>
20727+
<Member Name="foldParallel" Value="48"/>
20728+
<Member Name="foldPoster" Value="49"/>
20729+
<Member Name="foldRightGate" Value="50"/>
20730+
<Member Name="foldZ" Value="51"/>
20731+
<Member Name="foldEngineeringZ" Value="52"/>
20732+
<Member Name="punchTopLeft" Value="53"/>
20733+
<Member Name="punchBottomLeft" Value="54"/>
20734+
<Member Name="punchTopRight" Value="55"/>
20735+
<Member Name="punchBottomRight" Value="56"/>
20736+
<Member Name="punchDualLeft" Value="57"/>
20737+
<Member Name="punchDualTop" Value="58"/>
20738+
<Member Name="punchDualRight" Value="59"/>
20739+
<Member Name="punchDualBottom" Value="60"/>
20740+
<Member Name="punchTripleLeft" Value="61"/>
20741+
<Member Name="punchTripleTop" Value="62"/>
20742+
<Member Name="punchTripleRight" Value="63"/>
20743+
<Member Name="punchTripleBottom" Value="64"/>
20744+
<Member Name="punchQuadLeft" Value="65"/>
20745+
<Member Name="punchQuadTop" Value="66"/>
20746+
<Member Name="punchQuadRight" Value="67"/>
20747+
<Member Name="punchQuadBottom" Value="68"/>
20748+
<Member Name="fold" Value="69"/>
20749+
<Member Name="trim" Value="70"/>
20750+
<Member Name="bale" Value="71"/>
20751+
<Member Name="bookletMaker" Value="72"/>
20752+
<Member Name="coat" Value="73"/>
20753+
<Member Name="laminate" Value="74"/>
20754+
<Member Name="trimAfterPages" Value="75"/>
20755+
<Member Name="trimAfterDocuments" Value="76"/>
20756+
<Member Name="trimAfterCopies" Value="77"/>
20757+
<Member Name="trimAfterJob" Value="78"/>
2071220758
</EnumType>
2071320759
<EnumType Name="printJobProcessingState">
2071420760
<Member Name="unknown" Value="0"/>
@@ -24573,9 +24619,10 @@
2457324619
<NavigationProperty Name="notes" Type="Collection(graph.authoredNote)" ContainsTarget="true"/>
2457424620
<NavigationProperty Name="team" Type="graph.team"/>
2457524621
</EntityType>
24576-
<EntityType Name="security" BaseType="graph.entity">
24622+
<EntityType Name="security">
2457724623
<NavigationProperty Name="subjectRightsRequests" Type="Collection(graph.subjectRightsRequest)" ContainsTarget="true"/>
2457824624
<NavigationProperty Name="cases" Type="microsoft.graph.security.casesRoot" ContainsTarget="true"/>
24625+
<NavigationProperty Name="identities" Type="microsoft.graph.security.identityContainer" ContainsTarget="true"/>
2457924626
<NavigationProperty Name="alerts_v2" Type="Collection(microsoft.graph.security.alert)" ContainsTarget="true"/>
2458024627
<NavigationProperty Name="incidents" Type="Collection(microsoft.graph.security.incident)" ContainsTarget="true"/>
2458124628
<NavigationProperty Name="attackSimulation" Type="graph.attackSimulationRoot" ContainsTarget="true"/>
@@ -39410,6 +39457,23 @@
3941039457
<Member Name="site" Value="2"/>
3941139458
<Member Name="unknownFutureValue" Value="4"/>
3941239459
</EnumType>
39460+
<EnumType Name="healthIssueSeverity">
39461+
<Member Name="low" Value="1"/>
39462+
<Member Name="medium" Value="2"/>
39463+
<Member Name="high" Value="3"/>
39464+
<Member Name="unknownFutureValue" Value="4"/>
39465+
</EnumType>
39466+
<EnumType Name="healthIssueStatus">
39467+
<Member Name="open" Value="1"/>
39468+
<Member Name="closed" Value="2"/>
39469+
<Member Name="suppressed" Value="3"/>
39470+
<Member Name="unknownFutureValue" Value="4"/>
39471+
</EnumType>
39472+
<EnumType Name="healthIssueType">
39473+
<Member Name="sensor" Value="1"/>
39474+
<Member Name="global" Value="2"/>
39475+
<Member Name="unknownFutureValue" Value="3"/>
39476+
</EnumType>
3941339477
<EnumType Name="behaviorDuringRetentionPeriod">
3941439478
<Member Name="doNotRetain" Value="0"/>
3941539479
<Member Name="retain" Value="1"/>
@@ -39758,6 +39822,9 @@
3975839822
<EntityType Name="casesRoot" BaseType="graph.entity">
3975939823
<NavigationProperty Name="ediscoveryCases" Type="Collection(microsoft.graph.security.ediscoveryCase)" ContainsTarget="true"/>
3976039824
</EntityType>
39825+
<EntityType Name="identityContainer" BaseType="graph.entity">
39826+
<NavigationProperty Name="healthIssues" Type="Collection(microsoft.graph.security.healthIssue)" ContainsTarget="true"/>
39827+
</EntityType>
3976139828
<EntityType Name="alert" BaseType="graph.entity">
3976239829
<Property Name="actorDisplayName" Type="Edm.String"/>
3976339830
<Property Name="additionalData" Type="microsoft.graph.security.dictionary"/>
@@ -40003,6 +40070,21 @@
4000340070
<EntityType Name="ediscoveryHoldOperation" BaseType="microsoft.graph.security.caseOperation"/>
4000440071
<EntityType Name="ediscoveryPurgeDataOperation" BaseType="microsoft.graph.security.caseOperation"/>
4000540072
<EntityType Name="ediscoveryTagOperation" BaseType="microsoft.graph.security.caseOperation"/>
40073+
<EntityType Name="healthIssue" BaseType="graph.entity">
40074+
<Property Name="additionalInformation" Type="Collection(Edm.String)" Nullable="false"/>
40075+
<Property Name="createdDateTime" Type="Edm.DateTimeOffset" Nullable="false"/>
40076+
<Property Name="description" Type="Edm.String" Nullable="false"/>
40077+
<Property Name="displayName" Type="Edm.String"/>
40078+
<Property Name="domainNames" Type="Collection(Edm.String)"/>
40079+
<Property Name="healthIssueType" Type="microsoft.graph.security.healthIssueType"/>
40080+
<Property Name="issueTypeId" Type="Edm.String"/>
40081+
<Property Name="lastModifiedDateTime" Type="Edm.DateTimeOffset" Nullable="false"/>
40082+
<Property Name="recommendations" Type="Collection(Edm.String)" Nullable="false"/>
40083+
<Property Name="recommendedActionCommands" Type="Collection(Edm.String)" Nullable="false"/>
40084+
<Property Name="sensorDNSNames" Type="Collection(Edm.String)"/>
40085+
<Property Name="severity" Type="microsoft.graph.security.healthIssueSeverity"/>
40086+
<Property Name="status" Type="microsoft.graph.security.healthIssueStatus"/>
40087+
</EntityType>
4000640088
<ComplexType Name="alertComment">
4000740089
<Property Name="comment" Type="Edm.String"/>
4000840090
<Property Name="createdByDisplayName" Type="Edm.String"/>

office365/runtime/client_object.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import datetime
44
from typing import TYPE_CHECKING, Any, Callable, Generic, List, Optional, TypeVar
55

6+
from requests import Response
67
from typing_extensions import Self
78

89
from office365.runtime.client_runtime_context import ClientRuntimeContext
@@ -80,10 +81,10 @@ def before_execute(self, action):
8081
self.context.before_execute(action)
8182
return self
8283

83-
def after_execute(self, action, execute_first=False):
84-
# type: (Callable[[Self], None], bool) -> Self
84+
def after_execute(self, action, execute_first=False, include_response=False):
85+
# type: (Callable[[Self|Response], None], bool, bool) -> Self
8586
"""Attach an event handler to client object which gets triggered after query is submitted to server"""
86-
self.context.after_query_execute(action, execute_first)
87+
self.context.after_query_execute(action, execute_first, include_response)
8788
return self
8889

8990
def get(self):

office365/runtime/client_runtime_context.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ def _process_request(request):
126126
self.pending_request().beforeExecute += _process_request
127127
return self
128128

129-
def after_query_execute(self, action, execute_first=False):
130-
# type: (Callable[[T], None], bool) -> Self
129+
def after_query_execute(self, action, execute_first=False, include_response=False):
130+
# type: (Callable[[T|Response], None], bool, bool) -> Self
131131
"""Attach an event handler which is triggered after query is submitted to server"""
132132
if len(self._queries) == 0:
133133
return
@@ -138,7 +138,7 @@ def _process_response(resp):
138138
resp.raise_for_status()
139139
if self.current_query.id == query.id:
140140
self.pending_request().afterExecute -= _process_response
141-
action(query.return_type)
141+
action(resp if include_response else query.return_type)
142142

143143
self.pending_request().afterExecute += _process_response
144144

office365/sharepoint/businessdata/infrastructure/securestore/connection_settings.py

+23-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,30 @@
1+
from typing import Optional
2+
3+
from office365.runtime.paths.resource_path import ResourcePath
14
from office365.sharepoint.entity import Entity
25

36

47
class ConnectionSettings(Entity):
5-
""""""
8+
"""The ConnectionSettings contains information about an endpoint (4) that can be used to connect to it."""
9+
10+
def __init__(self, context, resource_path=None):
11+
if resource_path is None:
12+
resource_path = ResourcePath(
13+
"Microsoft.BusinessData.Infrastructure.SecureStore.ConnectionSettings"
14+
)
15+
super(ConnectionSettings, self).__init__(context, resource_path)
16+
17+
@property
18+
def authentication_mode(self):
19+
# type: () -> Optional[str]
20+
"""The authentication mode used by the endpoint"""
21+
return self.properties.get("AuthenticationMode", None)
22+
23+
@property
24+
def parent_name(self):
25+
# type: () -> Optional[str]
26+
"""The unique name used to identify the parent of the endpoint"""
27+
return self.properties.get("parentName", None)
628

729
@property
830
def entity_type_name(self):
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1+
from office365.runtime.types.collections import StringCollection
12
from office365.sharepoint.entity import Entity
23

34

45
class MembershipResult(Entity):
6+
@property
7+
def groups_list(self):
8+
return self.properties.get("GroupsList", StringCollection())
9+
510
@property
611
def entity_type_name(self):
712
return "SP.Directory.MembershipResult"

0 commit comments

Comments
 (0)