Skip to content

Commit 903f378

Browse files
authored
Merge pull request #1129 from RogerSelwyn/master
Update Docs with missing elements and update to latest Sphinx/Read The Docs
2 parents c2b128f + ff12461 commit 903f378

File tree

269 files changed

+37443
-22766
lines changed

Some content is hidden

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

269 files changed

+37443
-22766
lines changed

.github/workflows/build_pages.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: Pages Build
2+
3+
on:
4+
push:
5+
branches: [ "master" ]
6+
jobs:
7+
pages_build:
8+
name: Build Pages
9+
runs-on: "ubuntu-latest"
10+
steps:
11+
- name: "Checkout the repository"
12+
uses: actions/checkout@v4
13+
14+
- name: "Set up Python"
15+
uses: actions/setup-python@v5
16+
with:
17+
python-version: "3.12"
18+
cache: "pip"
19+
20+
- name: "Install requirements"
21+
run: python3 -m pip install -r requirements-pages.txt
22+
23+
- name: "Build pages"
24+
run: sphinx-build -b html -c ./docs/source/ ./docs/source/ ./docs/latest/
25+
26+
- name: "Pull any updates"
27+
shell: bash
28+
run: git pull
29+
30+
- name: "Check for changes"
31+
shell: bash
32+
run: git status
33+
34+
- name: "Stage changed files"
35+
shell: bash
36+
run: git add ./docs/latest
37+
38+
- name: "Commit changed files"
39+
shell: bash
40+
run: |
41+
git config --local user.email "[email protected]"
42+
git config --local user.name "GitHub Action"
43+
git commit -m "Update the docs" || true
44+
45+
- name: Push changes
46+
uses: ad-m/github-push-action@master
47+
with:
48+
github_token: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,7 @@ venv/
7878

7979
# O365 specific
8080
o365_token\.txt
81-
local_tests/
81+
local_tests/
82+
83+
# Mac Specifoc
84+
.DS_Store

O365/account.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
from typing import Type, Tuple, Optional, Callable, List
21
import warnings
2+
from typing import Callable, List, Optional, Tuple, Type
33

4-
from .connection import Connection, Protocol, MSGraphProtocol, MSOffice365Protocol
4+
from .connection import Connection, MSGraphProtocol, Protocol
55
from .utils import ME_RESOURCE, consent_input_token
66

77

88
class Account:
9-
connection_constructor: Type = Connection
9+
connection_constructor: Type = Connection #: :meta private:
1010

1111
def __init__(self, credentials: Tuple[str, str], *,
1212
username: Optional[str] = None,
@@ -25,6 +25,7 @@ def __init__(self, credentials: Tuple[str, str], *,
2525
protocol = protocol or MSGraphProtocol # Defaults to Graph protocol
2626
if isinstance(protocol, type):
2727
protocol = protocol(default_resource=main_resource, **kwargs)
28+
#: The protocol to use for the account. Defaults ot MSGraphProtocol. |br| **Type:** Protocol
2829
self.protocol: Protocol = protocol
2930

3031
if not isinstance(self.protocol, Protocol):
@@ -57,6 +58,7 @@ def __init__(self, credentials: Tuple[str, str], *,
5758
kwargs['username'] = username
5859

5960
self.con = self.connection_constructor(credentials, **kwargs)
61+
#: The resource in use for the account. |br| **Type:** str
6062
self.main_resource: str = main_resource or self.protocol.default_resource
6163

6264
def __repr__(self):
@@ -269,7 +271,7 @@ def address_book(self, *, resource: Optional[str] = None, address_book: str = 'p
269271

270272
def directory(self, resource: Optional[str] = None):
271273
""" Returns the active directory instance"""
272-
from .directory import Directory, USERS_RESOURCE
274+
from .directory import USERS_RESOURCE, Directory
273275

274276
return Directory(parent=self, main_resource=resource or USERS_RESOURCE)
275277

O365/address_book.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@
44
from dateutil.parser import parse
55
from requests.exceptions import HTTPError
66

7-
from .utils import Recipients
8-
from .utils import AttachableMixin, TrackerSet
9-
from .utils import Pagination, NEXT_LINK_KEYWORD, ApiComponent
10-
from .message import Message, RecipientType
117
from .category import Category
12-
8+
from .message import Message, RecipientType
9+
from .utils import (
10+
NEXT_LINK_KEYWORD,
11+
ApiComponent,
12+
AttachableMixin,
13+
Pagination,
14+
Recipients,
15+
TrackerSet,
16+
)
1317

1418
log = logging.getLogger(__name__)
1519

@@ -25,7 +29,7 @@ class Contact(ApiComponent, AttachableMixin):
2529
'photo_size': '/contacts/{id}/photos/{size}/$value',
2630
}
2731

28-
message_constructor = Message
32+
message_constructor = Message #: :meta private:
2933

3034
def __init__(self, *, parent=None, con=None, **kwargs):
3135
""" Create a contact API component
@@ -56,6 +60,7 @@ def __init__(self, *, parent=None, con=None, **kwargs):
5660
# internal to know which properties need to be updated on the server
5761
self._track_changes = TrackerSet(casing=cc)
5862

63+
#: The contact's unique identifier. |br| **Type:** str
5964
self.object_id = cloud_data.get(cc('id'), None)
6065
self.__created = cloud_data.get(cc('createdDateTime'), None)
6166
self.__modified = cloud_data.get(cc('lastModifiedDateTime'), None)
@@ -457,7 +462,7 @@ def personal_notes(self, value):
457462

458463
@property
459464
def folder_id(self):
460-
""" ID of the folder
465+
"""ID of the containing folder
461466
462467
:rtype: str
463468
"""
@@ -594,7 +599,8 @@ def new_message(self, recipient=None, *, recipient_type=RecipientType.TO):
594599
return new_message
595600

596601
def get_profile_photo(self, size=None):
597-
""" Returns this contact profile photo
602+
"""Returns this contact profile photo
603+
598604
:param str size: 48x48, 64x64, 96x96, 120x120, 240x240,
599605
360x360, 432x432, 504x504, and 648x648
600606
"""
@@ -636,8 +642,8 @@ class BaseContactFolder(ApiComponent):
636642
'child_folders': '/contactFolders/{id}/childFolders'
637643
}
638644

639-
contact_constructor = Contact
640-
message_constructor = Message
645+
contact_constructor = Contact #: :meta private:
646+
message_constructor = Message #: :meta private:
641647

642648
def __init__(self, *, parent=None, con=None, **kwargs):
643649
""" Create a contact folder component
@@ -663,17 +669,21 @@ def __init__(self, *, parent=None, con=None, **kwargs):
663669
main_resource=main_resource)
664670

665671
# This folder has no parents if root = True.
672+
#: Indicates if this is the root folder. |br| **Type:** bool
666673
self.root = kwargs.pop('root', False)
667674

668675
cloud_data = kwargs.get(self._cloud_data_key, {})
669676

670677
# Fallback to manual folder if nothing available on cloud data
678+
#: The folder's display name. |br| **Type:** str
671679
self.name = cloud_data.get(self._cc('displayName'),
672680
kwargs.get('name',
673681
''))
674682
# TODO: Most of above code is same as mailbox.Folder __init__
675683

684+
#: Unique identifier of the contact folder. |br| **Type:** str
676685
self.folder_id = cloud_data.get(self._cc('id'), None)
686+
#: The ID of the folder's parent folder. |br| **Type:** str
677687
self.parent_id = cloud_data.get(self._cc('parentFolderId'), None)
678688

679689
def __str__(self):

O365/calendar.py

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
import calendar
22
import datetime as dt
33
import logging
4-
from zoneinfo import ZoneInfo
54

65
# noinspection PyPep8Naming
76
from bs4 import BeautifulSoup as bs
87
from dateutil.parser import parse
8+
from zoneinfo import ZoneInfo
99

10-
from .utils import CaseEnum
11-
from .utils import HandleRecipientsMixin
12-
from .utils import AttachableMixin, ImportanceLevel, TrackerSet
13-
from .utils import BaseAttachments, BaseAttachment
14-
from .utils import Pagination, NEXT_LINK_KEYWORD, ApiComponent
15-
from .utils.windows_tz import get_windows_tz
1610
from .category import Category
11+
from .utils import (
12+
NEXT_LINK_KEYWORD,
13+
ApiComponent,
14+
AttachableMixin,
15+
BaseAttachment,
16+
BaseAttachments,
17+
CaseEnum,
18+
HandleRecipientsMixin,
19+
ImportanceLevel,
20+
Pagination,
21+
TrackerSet,
22+
)
23+
from .utils.windows_tz import get_windows_tz
1724

1825
log = logging.getLogger(__name__)
1926

@@ -541,9 +548,11 @@ def __init__(self, parent, response_status):
541548
"""
542549
super().__init__(protocol=parent.protocol,
543550
main_resource=parent.main_resource)
551+
#: The status of the response |br| **Type:** str
544552
self.status = response_status.get(self._cc('response'), 'none')
545553
self.status = None if self.status == 'none' else EventResponse.from_value(self.status)
546554
if self.status:
555+
#: The time the response was received |br| **Type:** datetime
547556
self.response_time = response_status.get(self._cc('time'), None)
548557
if self.response_time == '0001-01-01T00:00:00Z':
549558
# consider there's no response time
@@ -853,15 +862,18 @@ def __init__(self, *, parent=None, con=None, **kwargs):
853862
cc = self._cc # alias
854863
# internal to know which properties need to be updated on the server
855864
self._track_changes = TrackerSet(casing=cc)
865+
#: The calendar's unique identifier. |br| **Type:** str
856866
self.calendar_id = kwargs.get('calendar_id', None)
857867
download_attachments = kwargs.get('download_attachments')
858868
cloud_data = kwargs.get(self._cloud_data_key, {})
859869

870+
#: Unique identifier for the event. |br| **Type:** str
860871
self.object_id = cloud_data.get(cc('id'), None)
861872
self.__subject = cloud_data.get(cc('subject'),
862873
kwargs.get('subject', '') or '')
863874
body = cloud_data.get(cc('body'), {})
864875
self.__body = body.get(cc('content'), '')
876+
#: The type of the content. Possible values are text and html. |br| **Type:** bodyType
865877
self.body_type = body.get(cc('contentType'),
866878
'HTML') # default to HTML for new messages
867879

@@ -886,23 +898,32 @@ def __init__(self, *, parent=None, con=None, **kwargs):
886898
end_obj = cloud_data.get(cc('end'), {})
887899
self.__end = self._parse_date_time_time_zone(end_obj, self.__is_all_day)
888900

901+
#: Set to true if the event has attachments. |br| **Type:** bool
889902
self.has_attachments = cloud_data.get(cc('hasAttachments'), False)
890903
self.__attachments = EventAttachments(parent=self, attachments=[])
891904
if self.has_attachments and download_attachments:
892905
self.attachments.download_attachments()
893906
self.__categories = cloud_data.get(cc('categories'), [])
907+
#: A unique identifier for an event across calendars. This ID is different for each occurrence in a recurring series. |br| **Type:** str
894908
self.ical_uid = cloud_data.get(cc('iCalUId'), None)
895909
self.__importance = ImportanceLevel.from_value(
896910
cloud_data.get(cc('importance'), 'normal') or 'normal')
911+
#: Set to true if the event has been cancelled. |br| **Type:** bool
897912
self.is_cancelled = cloud_data.get(cc('isCancelled'), False)
913+
#: Set to true if the calendar owner (specified by the owner property of the calendar) is the organizer of the event
914+
#: (specified by the organizer property of the event). It also applies if a delegate organized the event on behalf of the owner.
915+
#: |br| **Type:** bool
898916
self.is_organizer = cloud_data.get(cc('isOrganizer'), True)
899917
self.__location = cloud_data.get(cc('location'), {})
918+
#: The locations where the event is held or attended from. |br| **Type:** list
900919
self.locations = cloud_data.get(cc('locations'), []) # TODO
901920

921+
#: A URL for an online meeting. |br| **Type:** str
902922
self.online_meeting_url = cloud_data.get(cc('onlineMeetingUrl'), None)
903923
self.__is_online_meeting = cloud_data.get(cc('isOnlineMeeting'), False)
904924
self.__online_meeting_provider = OnlineMeetingProviderType.from_value(
905925
cloud_data.get(cc('onlineMeetingProvider'), 'teamsForBusiness'))
926+
#: Details for an attendee to join the meeting online. The default is null. |br| **Type:** OnlineMeetingInfo
906927
self.online_meeting = cloud_data.get(cc('onlineMeeting'), None)
907928
if not self.online_meeting_url and self.is_online_meeting:
908929
self.online_meeting_url = self.online_meeting.get(cc('joinUrl'), None) \
@@ -923,10 +944,12 @@ def __init__(self, *, parent=None, con=None, **kwargs):
923944
cc('responseStatus'), {}))
924945
self.__sensitivity = EventSensitivity.from_value(
925946
cloud_data.get(cc('sensitivity'), 'normal'))
947+
#: The ID for the recurring series master item, if this event is part of a recurring series. |br| **Type:** str
926948
self.series_master_id = cloud_data.get(cc('seriesMasterId'), None)
927949
self.__show_as = EventShowAs.from_value(cloud_data.get(cc('showAs'), 'busy'))
928950
self.__event_type = EventType.from_value(cloud_data.get(cc('type'), 'singleInstance'))
929951
self.__no_forwarding = False
952+
#: The URL to open the event in Outlook on the web. |br| **Type:** str
930953
self.web_link = cloud_data.get(cc('webLink'), None)
931954

932955
def __str__(self):
@@ -1359,6 +1382,7 @@ def no_forwarding(self, value):
13591382
def get_occurrences(self, start, end, *, limit=None, query=None, order_by=None, batch=None):
13601383
"""
13611384
Returns all the occurrences of a seriesMaster event for a specified time range.
1385+
13621386
:type start: datetime
13631387
:param start: the start of the time range
13641388
:type end: datetime
@@ -1608,7 +1632,7 @@ class Calendar(ApiComponent, HandleRecipientsMixin):
16081632
'default_events_view': '/calendar/calendarView',
16091633
'get_event': '/calendars/{id}/events/{ide}',
16101634
}
1611-
event_constructor = Event
1635+
event_constructor = Event #: :meta private:
16121636

16131637
def __init__(self, *, parent=None, con=None, **kwargs):
16141638
""" Create a Calendar Representation
@@ -1635,22 +1659,31 @@ def __init__(self, *, parent=None, con=None, **kwargs):
16351659

16361660
cloud_data = kwargs.get(self._cloud_data_key, {})
16371661

1662+
#: The calendar name. |br| **Type:** str
16381663
self.name = cloud_data.get(self._cc('name'), '')
1664+
#: The calendar's unique identifier. |br| **Type:** str
16391665
self.calendar_id = cloud_data.get(self._cc('id'), None)
16401666
self.__owner = self._recipient_from_cloud(
16411667
cloud_data.get(self._cc('owner'), {}), field='owner')
16421668
color = cloud_data.get(self._cc('color'), 'auto')
16431669
try:
1670+
#: Specifies the color theme to distinguish the calendar from other calendars in a UI. |br| **Type:** calendarColor
16441671
self.color = CalendarColor.from_value(color)
16451672
except:
16461673
self.color = CalendarColor.from_value('auto')
1674+
#: true if the user can write to the calendar, false otherwise. |br| **Type:** bool
16471675
self.can_edit = cloud_data.get(self._cc('canEdit'), False)
1676+
#: true if the user has permission to share the calendar, false otherwise. |br| **Type:** bool
16481677
self.can_share = cloud_data.get(self._cc('canShare'), False)
1678+
#: If true, the user can read calendar items that have been marked private, false otherwise. |br| **Type:** bool
16491679
self.can_view_private_items = cloud_data.get(
16501680
self._cc('canViewPrivateItems'), False)
16511681

16521682
# Hex color only returns a value when a custom calandar is set
16531683
# Hex color is read-only, cannot be used to set calendar's color
1684+
#: The calendar color, expressed in a hex color code of three hexadecimal values,
1685+
#: each ranging from 00 to FF and representing the red, green, or blue components
1686+
#: of the color in the RGB color space. |br| **Type:** str
16541687
self.hex_color = cloud_data.get(self._cc('hexColor'), None)
16551688

16561689
def __str__(self):
@@ -1871,8 +1904,8 @@ class Schedule(ApiComponent):
18711904
'get_availability': '/calendar/getSchedule',
18721905
}
18731906

1874-
calendar_constructor = Calendar
1875-
event_constructor = Event
1907+
calendar_constructor = Calendar #: :meta private:
1908+
event_constructor = Event #: :meta private:
18761909

18771910
def __init__(self, *, parent=None, con=None, **kwargs):
18781911
""" Create a wrapper around calendars and events

0 commit comments

Comments
 (0)