Skip to content

Commit e2b089e

Browse files
Restore suppprt for 2.7 and resolve compatibility errors
1 parent 43db12a commit e2b089e

File tree

125 files changed

+252
-199
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

125 files changed

+252
-199
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
language: python
22
os: linux
33
python:
4+
- '2.7'
45
- '3.6'
5-
- '3.8'
66
- '3.9'
77
install:
88
- pip install -r requirements.txt

examples/directory/delete_groups.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
client = GraphClient(acquire_token_by_username_password)
55

6-
groups = client.groups.get().top(50).execute_query()
6+
groups = client.groups.get().top(10).execute_query()
77
deletedCount = 0
88
groups_count = len(groups)
99
while len(groups) > 0:

examples/sharepoint/files/upload_large_file.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import os
22

33
from office365.sharepoint.client_context import ClientContext
4-
from tests import test_site_url, test_user_credentials, test_team_site_url
4+
from tests import test_user_credentials, test_team_site_url
55

66
ctx = ClientContext(test_team_site_url).with_credentials(test_user_credentials)
77

@@ -15,7 +15,7 @@
1515

1616

1717
def print_upload_progress(offset):
18-
print("Uploaded '{}' bytes from '{}'...[{}%]".format(offset, file_size, round(offset / file_size * 100, 2)))
18+
print("Uploaded '{0}' bytes from '{1}'...[{2}%]".format(offset, file_size, round(offset / file_size * 100, 2)))
1919

2020

2121
uploaded_file = target_folder.files.create_upload_session(local_path, size_chunk, print_upload_progress).execute_query()

generator/templates/complex_type.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,4 @@
22

33

44
class ComplexType(ClientValue):
5-
6-
def __init__(self):
7-
super().__init__()
5+
pass

office365/calendar/attendee.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ def __init__(self, emailAddress=EmailAddress(), attendee_type=None, proposedNewT
1414
:param str status: The attendee's response (none, accepted, declined, etc.) for the event and date-time
1515
that the response was sent.
1616
"""
17-
super().__init__(emailAddress, attendee_type)
17+
super(Attendee, self).__init__(emailAddress, attendee_type)
1818
self.proposedNewTime = proposedNewTime
1919
self.status = status

office365/calendar/attendeeBase.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ def __init__(self, emailAddress, attendee_type=None):
1111
:param str attendee_type: The type of attendee. The possible values are: required, optional, resource.
1212
Currently if the attendee is a person, findMeetingTimes always considers the person is of the Required type.
1313
"""
14-
super().__init__(emailAddress)
14+
super(AttendeeBase, self).__init__(emailAddress)
1515
self.type = attendee_type

office365/calendar/dateTimeTimeZone.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def __init__(self, dateTime, timeZone=None):
1212
:param str dateTime: A single point of time in a combined date and time representation ({date}T{time};
1313
for example, 2017-08-29T04:00:00.0000000).
1414
"""
15-
super().__init__()
15+
super(DateTimeTimeZone, self).__init__()
1616
self.dateTime = dateTime
1717
self.timeZone = timeZone
1818

office365/calendar/emailAddress.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ class EmailAddress(ClientValue):
55
"""The name and email address of a contact or message recipient."""
66

77
def __init__(self, address=None, name=None):
8-
super().__init__()
8+
super(EmailAddress, self).__init__()
99
self.address = address
1010
self.name = name

office365/calendar/meeting_time_suggestions_result.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def __init__(self, meetingTimeSuggestions=None,
1717
organizerUnavailable, or unknown. This property is an empty string if the meetingTimeSuggestions property
1818
does include any meeting suggestions.
1919
"""
20-
super().__init__()
20+
super(MeetingTimeSuggestionsResult, self).__init__()
2121
self.meetingTimeSuggestions = ClientValueCollection(MeetingTimeSuggestion) if meetingTimeSuggestions is None \
2222
else meetingTimeSuggestions
2323
self.emptySuggestionsReason = emptySuggestionsReason

office365/calendar/reminder.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ def __init__(self, eventId=None):
99
1010
:param str eventId: The unique ID of the event. Read only.
1111
"""
12-
super().__init__()
12+
super(Reminder, self).__init__()
1313
self.eventId = eventId

office365/calendar/schedule_information.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def __init__(self, scheduleId=None, scheduleItems=None, availabilityView=None, e
2323
:param str scheduleId: An SMTP address of the user, distribution list, or resource, identifying an instance
2424
of scheduleInformation.
2525
"""
26-
super().__init__()
26+
super(ScheduleInformation, self).__init__()
2727
self.scheduleItems = ClientValueCollection(ScheduleItem) if scheduleItems is None else scheduleItems
2828
self.scheduleId = scheduleId
2929
self.availabilityView = availabilityView

office365/calendar/timeSlot.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ def __init__(self, start, end):
1010
:param datetime.datetime start: The date, time, and time zone that a period begins.
1111
:param datetime.datetime end: The date, time, and time zone that a period ends.
1212
"""
13-
super().__init__()
13+
super(TimeSlot, self).__init__()
1414
self.start = start
1515
self.end = end

office365/directory/assignedLicense.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
class AssignedLicense(ClientValue):
55

66
def __init__(self, skuId=None, disabledPlans=None):
7-
super().__init__()
7+
super(AssignedLicense, self).__init__()
88
self.skuId = skuId
99
self.disabledPlans = disabledPlans

office365/directory/passwordCredential.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class PasswordCredential(ClientValue):
66
The passwordCredentials property of the application entity is a collection of passwordCredential objects."""
77

88
def __init__(self, displayName=None, keyId=None):
9-
super().__init__()
9+
super(PasswordCredential, self).__init__()
1010
self.displayName = displayName
1111
self.secretText = None
1212
self.keyId = keyId

office365/directory/servicePlanInfo.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def __init__(self, servicePlanId=None, servicePlanName=None, provisioningStatus=
2222
:param str servicePlanName: The name of the service plan.
2323
:param str servicePlanId: The unique identifier of the service plan.
2424
"""
25-
super().__init__()
25+
super(ServicePlanInfo, self).__init__()
2626
self.servicePlanId = servicePlanId
2727
self.servicePlanName = servicePlanName
2828
self.provisioningStatus = provisioningStatus

office365/directory/userIdentity.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
class UserIdentity(ClientValue):
55

66
def __init__(self):
7-
super().__init__()
7+
super(UserIdentity, self).__init__()
88
self.displayName = None
99
self.ipAddress = None
1010
self.userPrincipalName = None

office365/mail/itemBody.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ def __init__(self, content, contentType="Text"):
1010
:type content: str
1111
:type contentType: str
1212
"""
13-
super().__init__()
13+
super(ItemBody, self).__init__()
1414
self.content = content
1515
self.contentType = contentType

office365/mail/location.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ def __init__(self, displayName=None):
99
1010
:param str displayName: The name associated with the location.
1111
"""
12-
super().__init__()
12+
super(Location, self).__init__()
1313
self.displayName = displayName

office365/mail/recipient.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ def __init__(self, emailAddress=EmailAddress()):
1111
1212
:param EmailAddress emailAddress: The recipient's email address.
1313
"""
14-
super().__init__()
14+
super(Recipient, self).__init__()
1515
self.emailAddress = emailAddress
1616

1717

1818
class RecipientCollection(ClientValueCollection):
1919

2020
def __init__(self, default_values=None):
21-
super().__init__(Recipient, default_values)
21+
super(RecipientCollection,self).__init__(Recipient, default_values)
2222

2323
@staticmethod
2424
def from_emails(values):

office365/onedrive/driveItemUploadableProperties.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ class DriveItemUploadableProperties(ClientValue):
55
"""The driveItemUploadableProperties resource represents an item being uploaded when creating an upload session."""
66

77
def __init__(self):
8-
super().__init__()
8+
super(DriveItemUploadableProperties, self).__init__()
99
self.fileSystemInfo = None
1010
self.name = None
1111
self.description = None

office365/onedrive/file_upload.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def __init__(self, target_folder, source_path, chunk_size=1024, chunk_uploaded=N
2828
:type source_path: str
2929
:type chunk_size: int
3030
"""
31-
super().__init__(target_folder, os.path.basename(source_path), "")
31+
super(ResumableFileUpload, self).__init__(target_folder, os.path.basename(source_path), "")
3232
self._chunk_size = chunk_size
3333
self._source_path = source_path
3434
self._file_name = os.path.basename(self._source_path)

office365/onedrive/uploadSession.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class UploadSession(ClientValue):
66
Business, or SharePoint document libraries. """
77

88
def __init__(self):
9-
super().__init__()
9+
super(UploadSession,self).__init__()
1010
self.expirationDateTime = None
1111
self.nextExpectedRanges = None
1212
self.uploadUrl = None

office365/runtime/auth/authentication_context.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import msal
2-
31
from office365.runtime.auth.client_credential import ClientCredential
42
from office365.runtime.auth.providers.acs_token_provider import ACSTokenProvider
53
from office365.runtime.auth.providers.oauth_token_provider import OAuthTokenProvider
@@ -30,8 +28,9 @@ def with_client_certificate(self, tenant, client_id, thumbprint, cert_path):
3028

3129
def _acquire_token_for_client_certificate():
3230
authority_url = 'https://login.microsoftonline.com/{0}'.format(tenant)
33-
scopes = [f"{self.url}/.default"]
31+
scopes = ["{url}/.default".format(url=self.url)]
3432
credentials = {"thumbprint": thumbprint, "private_key": open(cert_path).read()}
33+
import msal
3534
app = msal.ConfidentialClientApplication(
3635
client_id,
3736
authority=authority_url,

office365/runtime/auth/token_response.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ def is_valid(self):
1212

1313
@staticmethod
1414
def from_json(value):
15+
error = value.get('error', None)
16+
if error:
17+
raise ValueError(value)
1518

1619
def _normalize_key(name):
1720
key_parts = name.split("_")
1821
if len(key_parts) >= 2:
1922
names = [n.title() for n in key_parts[1:]]
2023
return key_parts[0] + "".join(names)
2124
return name
22-
2325
json = {_normalize_key(k): v for k, v in value.items()}
2426
return TokenResponse(**json)

office365/runtime/client_value_collection.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ def __init__(self, item_type, initial_values=None):
99
:type item_type: any
1010
:type initial_values: any
1111
"""
12-
super().__init__()
12+
super(ClientValueCollection, self).__init__()
1313
if initial_values is None:
1414
initial_values = []
1515
self._data = initial_values

office365/runtime/compat.py

+18
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,27 @@
1515

1616
if is_py2:
1717
from urlparse import urlparse
18+
from urllib import quote
19+
from urlparse import urljoin
1820
import pytz as timezone
21+
from email import message_from_string as message_from_bytes_or_string
1922
elif is_py3:
2023
from urllib.parse import urlparse
24+
from urllib.parse import quote
25+
from urllib.parse import urljoin
2126
from datetime import timezone
27+
from email import message_from_bytes as message_from_bytes_or_string
2228

2329

30+
def message_as_bytes_or_string(message):
31+
if is_py2:
32+
return message.as_string()
33+
else:
34+
return message.as_bytes()
35+
36+
37+
def is_string_type(value):
38+
if is_py2:
39+
return isinstance(value, basestring)
40+
else:
41+
return type(value) is str

office365/runtime/odata/odata_batch_request.py

+11-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json
22
import re
3-
from email import message_from_bytes
3+
from office365.runtime.compat import message_from_bytes_or_string, message_as_bytes_or_string
44
from email.message import Message
55

66
from office365.runtime.client_request import ClientRequest
@@ -25,7 +25,7 @@ def build_request(self, query):
2525
media_type = "multipart/mixed"
2626
content_type = "; ".join([media_type, "boundary={0}".format(query.current_boundary)])
2727
request.ensure_header('Content-Type', content_type)
28-
request.data = self._prepare_payload(query).as_bytes()
28+
request.data = self._prepare_payload(query)
2929
return request
3030

3131
def process_response(self, response, query):
@@ -54,7 +54,7 @@ def _read_response(self, response):
5454
+ response.content
5555
)
5656

57-
message = message_from_bytes(http_body) # type: Message
57+
message = message_from_bytes_or_string(http_body) # type: Message
5858
for raw_response in message.get_payload():
5959
if raw_response.get_content_type() == "application/http":
6060
yield self._deserialize_response(raw_response)
@@ -85,7 +85,7 @@ def _prepare_payload(self, query):
8585
message = self._serialize_request(request)
8686
main_message.attach(message)
8787

88-
return main_message
88+
return message_as_bytes_or_string(main_message)
8989

9090
@staticmethod
9191
def _normalize_headers(headers_raw):
@@ -114,7 +114,9 @@ def _deserialize_response(self, raw_response):
114114
"content": None
115115
}
116116
else:
117-
*headers_raw, content = lines[1:]
117+
#*headers_raw, content = lines[1:]
118+
headers_raw = lines[1:-1]
119+
content = lines[-1]
118120
content = json.loads(content)
119121
return {
120122
"status": status_info,
@@ -133,13 +135,13 @@ def _serialize_request(request):
133135
method = request.method
134136
if "X-HTTP-Method" in request.headers:
135137
method = request.headers["X-HTTP-Method"]
136-
lines = ["{method} {url} HTTP/1.1".format(method=method, url=request.url),
137-
*[':'.join(h) for h in request.headers.items()]]
138+
lines = ["{method} {url} HTTP/1.1".format(method=method, url=request.url)] + \
139+
[':'.join(h) for h in request.headers.items()]
138140
if request.data:
139141
lines.append(eol)
140142
lines.append(json.dumps(request.data))
141-
buffer = eol + eol.join(lines) + eol
142-
payload = buffer.encode('utf-8').lstrip()
143+
raw_content = eol + eol.join(lines) + eol
144+
payload = raw_content.encode('utf-8').lstrip()
143145

144146
message = Message()
145147
message.add_header("Content-Type", "application/http")

office365/runtime/odata/odata_path_parser.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
22

33
from office365.runtime.client_value import ClientValue
4+
from office365.runtime.compat import is_string_type
45

56

67
class ODataPathParser(object):
@@ -35,7 +36,7 @@ def from_method(method_name, method_parameters=None):
3536

3637
@staticmethod
3738
def encode_method_value(value):
38-
if type(value) is str:
39+
if is_string_type(value):
3940
value = value.replace("'", "''")
4041

4142
# Same replacements as SQL Server

office365/runtime/odata/odata_v3_reader.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ class ODataV3Reader(ODataBaseReader):
55
"""OData v3 reader"""
66

77
def __init__(self, options):
8-
super().__init__(options)
8+
super(ODataV3Reader,self).__init__(options)
99
self._options['namespaces'] = {
1010
'xmlns': 'http://schemas.microsoft.com/ado/2009/11/edm',
1111
'edmx': 'http://schemas.microsoft.com/ado/2007/06/edmx',

office365/runtime/odata/odata_v4_batch_request.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class ODataV4BatchRequest(ClientRequest):
88
""" JSON batch request """
99

1010
def __init__(self, context):
11-
super().__init__(context)
11+
super(ODataV4BatchRequest, self).__init__(context)
1212

1313
def build_request(self, query):
1414
"""

office365/runtime/odata/odata_v4_reader.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class ODataV4Reader(ODataBaseReader):
66
_options = None
77

88
def __init__(self, options):
9-
super().__init__(options)
9+
super(ODataV4Reader, self).__init__(options)
1010
self._options['namespaces'] = {
1111
'xmlns': 'http://docs.oasis-open.org/odata/ns/edm',
1212
'edmx': 'http://docs.oasis-open.org/odata/ns/edmx'

office365/runtime/queries/batch_query.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def __init__(self, context, queries=None):
2525
:type context: office365.runtime.client_runtime_context.ClientRuntimeContext
2626
:type queries: list[]
2727
"""
28-
super().__init__(context)
28+
super(BatchQuery, self).__init__(context)
2929
self._current_boundary = create_boundary("batch_")
3030
if queries is None:
3131
queries = []

0 commit comments

Comments
 (0)